Implement virtual memory protection

This commit is contained in:
Thomas Fleming 2021-04-21 19:58:36 -04:00
parent 44da1488ff
commit 4bae666fa1
9 changed files with 124 additions and 66 deletions

View File

@ -47,6 +47,7 @@ module dmem (
output logic SquashSCW,
// faults
input logic DataAccessFaultM,
output logic DTLBLoadPageFaultM, DTLBStorePageFaultM,
output logic LoadMisalignedFaultM, LoadAccessFaultM,
output logic StoreMisalignedFaultM, StoreAccessFaultM,
// TLB management
@ -54,22 +55,25 @@ module dmem (
input logic [`XLEN-1:0] PageTableEntryM,
input logic [1:0] PageTypeM,
input logic [`XLEN-1:0] SATP_REGW,
input logic STATUS_MXR, STATUS_SUM,
input logic DTLBWriteM, DTLBFlushM,
output logic DTLBMissM, DTLBHitM
);
logic MemAccessM; // Whether memory needs to be accessed
logic SquashSCM;
// *** needs to be sent to trap unit
logic DTLBPageFaultM;
tlb #(3) dtlb(.TLBAccess(MemAccessM), .VirtualAddress(MemAdrM),
tlb #(.ENTRY_BITS(3), .ITLB(0)) dtlb(.TLBAccessType(MemRWM), .VirtualAddress(MemAdrM),
.PageTableEntryWrite(PageTableEntryM), .PageTypeWrite(PageTypeM),
.TLBWrite(DTLBWriteM), .TLBFlush(DTLBFlushM),
.PhysicalAddress(MemPAdrM), .TLBMiss(DTLBMissM),
.TLBHit(DTLBHitM), .TLBPageFault(DTLBPageFaultM),
.*);
// Specify which type of page fault is occurring
assign DTLBLoadPageFaultM = DTLBPageFaultM & MemRWM[1];
assign DTLBStorePageFaultM = DTLBPageFaultM & MemRWM[0];
// Determine if an Unaligned access is taking place
always_comb
case(Funct3M[1:0])
@ -83,7 +87,6 @@ module dmem (
// *** this is also the place to squash if the cache is hit
assign MemReadM = MemRWM[1] & ~DataMisalignedM;
assign MemWriteM = MemRWM[0] & ~DataMisalignedM && ~SquashSCM;
assign MemAccessM = |MemRWM;
// Determine if address is valid
assign LoadMisalignedFaultM = DataMisalignedM & MemRWM[1];

View File

@ -85,6 +85,9 @@ module ahblite (
logic IReady, DReady;
logic CaptureDataM;
// Describes type of access
logic Atomic, Execute, Write, Read;
assign HCLK = clk;
assign HRESETn = ~reset;
@ -109,15 +112,6 @@ module ahblite (
else NextBusState = IDLE;
MMUTRANSLATE: if (~HREADY) NextBusState = MMUTRANSLATE;
else NextBusState = IDLE;
// *** Could the MMUIDLE state just be the normal idle state?
// Do we trust MMUTranslate to be high exactly when we need translation?
// MMUIDLE: if (MMUTranslate)
// NextBusState = MMUTRANSLATE;
// else if (AtomicM[1]) NextBusState = ATOMICREAD;
// else if (MemReadM) NextBusState = MEMREAD; // Memory has priority over instructions
// else if (MemWriteM) NextBusState = MEMWRITE;
// else if (InstrReadF) NextBusState = INSTRREAD;
// else NextBusState = IDLE;
ATOMICREAD: if (~HREADY) NextBusState = ATOMICREAD;
else NextBusState = ATOMICWRITE;
ATOMICWRITE: if (~HREADY) NextBusState = ATOMICWRITE;
@ -148,6 +142,13 @@ module ahblite (
assign #1 InstrStall = ((NextBusState == INSTRREAD) || (NextBusState == INSTRREADC) ||
(NextBusState == MMUTRANSLATE) || (MMUTranslate && ~MMUTranslationComplete));
// Determine access type (important for determining whether to fault)
assign Atomic = ((NextBusState == ATOMICREAD) || (NextBusState == ATOMICWRITE));
assign Execute = ((NextBusState == INSTRREAD) || (NextBusState == INSTRREADC));
assign Write = ((NextBusState == MEMWRITE) || (NextBusState == ATOMICWRITE));
assign Read = ((NextBusState == MEMREAD) || (NextBusState == ATOMICREAD) ||
(NextBusState == MMUTRANSLATE));
// bus outputs
assign #1 GrantData = (NextBusState == MEMREAD) || (NextBusState == MEMWRITE) ||
(NextBusState == ATOMICREAD) || (NextBusState == ATOMICWRITE);

View File

@ -61,7 +61,9 @@ module pagetablewalker (
output logic MMUTranslationComplete,
// Faults
output logic InstrPageFaultF, LoadPageFaultM, StorePageFaultM
output logic WalkerInstrPageFaultF,
output logic WalkerLoadPageFaultM,
output logic WalkerStorePageFaultM
);
// Internal signals
@ -147,7 +149,6 @@ module pagetablewalker (
assign SvMode = SATP_REGW[31];
// *** Do we need a synchronizer here for walker to talk to ahblite?
flopenl #(3) mmureg(HCLK, ~HRESETn, 1'b1, NextWalkerState, IDLE, WalkerState);
// State transition logic
@ -193,9 +194,9 @@ module pagetablewalker (
MMUTranslationComplete = '0;
DTLBWriteM = '0;
ITLBWriteF = '0;
InstrPageFaultF = '0;
LoadPageFaultM = '0;
StorePageFaultM = '0;
WalkerInstrPageFaultF = '0;
WalkerLoadPageFaultM = '0;
WalkerStorePageFaultM = '0;
case (NextWalkerState)
LEVEL1: begin
@ -216,9 +217,9 @@ module pagetablewalker (
FAULT: begin
TranslationPAdr = {CurrentPPN, VPN0, 2'b00};
MMUTranslationComplete = '1;
InstrPageFaultF = ~DTLBMissM;
LoadPageFaultM = DTLBMissM && ~MemStore;
StorePageFaultM = DTLBMissM && MemStore;
WalkerInstrPageFaultF = ~DTLBMissM;
WalkerLoadPageFaultM = DTLBMissM && ~MemStore;
WalkerStorePageFaultM = DTLBMissM && MemStore;
end
default: begin
// nothing
@ -298,9 +299,9 @@ module pagetablewalker (
MMUTranslationComplete = '0;
DTLBWriteM = '0;
ITLBWriteF = '0;
InstrPageFaultF = '0;
LoadPageFaultM = '0;
StorePageFaultM = '0;
WalkerInstrPageFaultF = '0;
WalkerLoadPageFaultM = '0;
WalkerStorePageFaultM = '0;
case (NextWalkerState)
LEVEL2: begin
@ -325,9 +326,9 @@ module pagetablewalker (
FAULT: begin
TranslationPAdr = {CurrentPPN, VPN0, 3'b000};
MMUTranslationComplete = '1;
InstrPageFaultF = ~DTLBMissM;
LoadPageFaultM = DTLBMissM && ~MemStore;
StorePageFaultM = DTLBMissM && MemStore;
WalkerInstrPageFaultF = ~DTLBMissM;
WalkerLoadPageFaultM = DTLBMissM && ~MemStore;
WalkerStorePageFaultM = DTLBMissM && MemStore;
end
default: begin
// nothing

View File

@ -54,6 +54,7 @@ module ifu (
// output logic [`XLEN-1:0] PCLinkW,
// Faults
input logic IllegalBaseInstrFaultD,
output logic ITLBInstrPageFaultF,
output logic IllegalIEUInstrFaultD,
output logic InstrMisalignedFaultM,
output logic [`XLEN-1:0] InstrMisalignedAdrM,
@ -62,6 +63,7 @@ module ifu (
input logic [`XLEN-1:0] PageTableEntryF,
input logic [1:0] PageTypeF,
input logic [`XLEN-1:0] SATP_REGW,
input logic STATUS_MXR, STATUS_SUM,
input logic ITLBWriteF, ITLBFlushF,
output logic ITLBMissF, ITLBHitF
);
@ -74,14 +76,12 @@ module ifu (
logic CompressedF;
logic [31:0] InstrRawD, InstrE, InstrW;
logic [31:0] nop = 32'h00000013; // instruction for NOP
// *** send this to the trap unit
logic ITLBPageFaultF;
tlb #(3) itlb(.TLBAccess(1'b1), .VirtualAddress(PCF),
tlb #(.ENTRY_BITS(3), .ITLB(1)) itlb(.TLBAccessType(2'b10), .VirtualAddress(PCF),
.PageTableEntryWrite(PageTableEntryF), .PageTypeWrite(PageTypeF),
.TLBWrite(ITLBWriteF), .TLBFlush(ITLBFlushF),
.PhysicalAddress(PCPF), .TLBMiss(ITLBMissF),
.TLBHit(ITLBHitF), .TLBPageFault(ITLBPageFaultF),
.TLBHit(ITLBHitF), .TLBPageFault(ITLBInstrPageFaultF),
.*);
// branch predictor signals

View File

@ -44,26 +44,26 @@
* RSW(2) -- for OS
*/
/* *** TODO:
* - add LRU algorithm (select the write index based on which entry was used
* least recently)
*/
`include "wally-config.vh"
`include "wally-constants.vh"
// The TLB will have 2**ENTRY_BITS total entries
module tlb #(parameter ENTRY_BITS = 3) (
module tlb #(parameter ENTRY_BITS = 3,
parameter ITLB = 0) (
input clk, reset,
// Current value of satp CSR (from privileged unit)
input [`XLEN-1:0] SATP_REGW,
input STATUS_MXR, STATUS_SUM,
// Current privilege level of the processeor
input [1:0] PrivilegeModeW,
// High if the TLB is currently being accessed
input TLBAccess,
// 00 - TLB is not being accessed
// 1x - TLB is accessed for a read (or an instruction)
// x1 - TLB is accessed for a write
// 11 - TLB is accessed for both read and write
input [1:0] TLBAccessType,
// Virtual address input
input [`XLEN-1:0] VirtualAddress,
@ -87,17 +87,7 @@ module tlb #(parameter ENTRY_BITS = 3) (
logic SvMode;
logic Translate;
generate
if (`XLEN == 32) begin
assign SvMode = SATP_REGW[31]; // *** change to an enum somehow?
end else begin
assign SvMode = SATP_REGW[63]; // currently just a boolean whether translation enabled
end
endgenerate
// Whether translation should occur
assign Translate = SvMode & (PrivilegeModeW != `M_MODE);
logic TLBAccess, ReadAccess, WriteAccess;
// *** If we want to support multiple virtual memory modes (ie sv39 AND sv48),
// we could have some muxes that control which parameters are current.
@ -116,6 +106,9 @@ module tlb #(parameter ENTRY_BITS = 3) (
logic [7:0] PTEAccessBits;
logic [11:0] PageOffset;
// Useful PTE Control Bits
logic PTE_U, PTE_X, PTE_W, PTE_R;
// Pattern location in the CAM and type of page hit
logic [ENTRY_BITS-1:0] VPNIndex;
logic [1:0] HitPageType;
@ -123,18 +116,68 @@ module tlb #(parameter ENTRY_BITS = 3) (
// Whether the virtual address has a match in the CAM
logic CAMHit;
// Grab the sv bit from SATP
generate
if (`XLEN == 32) begin
assign SvMode = SATP_REGW[31]; // *** change to an enum somehow?
end else begin
assign SvMode = SATP_REGW[63]; // currently just a boolean whether translation enabled
end
endgenerate
// Whether translation should occur
assign Translate = SvMode & (PrivilegeModeW != `M_MODE);
// Determine how the TLB is currently being used
assign ReadAccess = TLBAccessType[1];
assign WriteAccess = TLBAccessType[0];
assign TLBAccess = ReadAccess || WriteAccess;
assign VirtualPageNumber = VirtualAddress[`VPN_BITS+11:12];
assign PageOffset = VirtualAddress[11:0];
// Currently use random replacement algorithm
// tlb_rand rdm(.*);
// TLB entries are evicted according to the LRU algorithm
tlb_lru lru(.*);
tlb_ram #(ENTRY_BITS) ram(.*);
tlb_cam #(ENTRY_BITS, `VPN_BITS, `VPN_SEGMENT_BITS) cam(.*);
tlb_ram #(ENTRY_BITS) tlb_ram(.*);
tlb_cam #(ENTRY_BITS, `VPN_BITS, `VPN_SEGMENT_BITS) tlb_cam(.*);
// *** check whether access is allowed, otherwise fault
assign TLBPageFault = 0; // *** temporary
// unswizzle useful PTE bits
assign PTE_U = PTEAccessBits[4];
assign PTE_X = PTEAccessBits[3];
assign PTE_W = PTEAccessBits[2];
assign PTE_R = PTEAccessBits[1];
// Check whether the access is allowed, page faulting if not.
// *** We might not have S mode.
generate
if (ITLB == 1) begin
logic ImproperPrivilege;
// User mode may only execute user mode pages, and supervisor mode may
// only execute non-user mode pages.
assign ImproperPrivilege = ((PrivilegeModeW == `U_MODE) && ~PTE_U) ||
((PrivilegeModeW == `S_MODE) && PTE_U);
assign TLBPageFault = Translate && TLBHit && (ImproperPrivilege || ~PTE_X);
end else begin
logic ImproperPrivilege, InvalidRead, InvalidWrite;
// User mode may only load/store from user mode pages, and supervisor mode
// may only access user mode pages when STATUS_SUM is low.
assign ImproperPrivilege = ((PrivilegeModeW == `U_MODE) && ~PTE_U) ||
((PrivilegeModeW == `S_MODE) && PTE_U && ~STATUS_SUM);
// Check for read error. Reads are invalid when the page is not readable
// (and executable pages are not readable) or when the page is neither
// readable nor executable (and executable pages are readable).
assign InvalidRead = ReadAccess &&
((~STATUS_MXR && ~PTE_R) || (STATUS_MXR && ~PTE_R && PTE_X));
// Check for write error. Writes are invalid when the page's write bit is
// low.
assign InvalidWrite = WriteAccess && ~PTE_W;
assign TLBPageFault = Translate && TLBHit &&
(ImproperPrivilege || InvalidRead || InvalidWrite);
end
endgenerate
// *** Not the cleanest solution.
// The highest segment of the physical page number has some extra bits
@ -158,6 +201,8 @@ module tlb #(parameter ENTRY_BITS = 3) (
// Output the hit physical address if translation is currently on.
generate
if (`XLEN == 32) begin
// *** If we want rv32 to use the full 34 bit physical address space, this
// must be changed
mux2 #(`XLEN) addressmux(VirtualAddress, PhysicalAddressFull[31:0], Translate, PhysicalAddress);
end else begin
mux2 #(`XLEN) addressmux(VirtualAddress, {8'b0, PhysicalAddressFull}, Translate, PhysicalAddress);

View File

@ -49,6 +49,7 @@ module csr #(parameter
output logic [`XLEN-1:0] SATP_REGW,
output logic [11:0] MIP_REGW, MIE_REGW,
output logic STATUS_MIE, STATUS_SIE,
output logic STATUS_MXR, STATUS_SUM,
input logic [4:0] SetFflagsM,
output logic [2:0] FRM_REGW,
// output logic [11:0] MIP_REGW, SIP_REGW, UIP_REGW, MIE_REGW, SIE_REGW, UIE_REGW,

View File

@ -36,10 +36,11 @@ module csrsr (
output logic [`XLEN-1:0] MSTATUS_REGW, SSTATUS_REGW, USTATUS_REGW,
output logic [1:0] STATUS_MPP,
output logic STATUS_SPP, STATUS_TSR,
output logic STATUS_MIE, STATUS_SIE
output logic STATUS_MIE, STATUS_SIE,
output logic STATUS_MXR, STATUS_SUM
);
logic STATUS_SD, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_SUM_INT, STATUS_MPRV, STATUS_MPRV_INT;
logic STATUS_SD, STATUS_TW, STATUS_TVM, STATUS_SUM_INT, STATUS_MPRV, STATUS_MPRV_INT;
logic [1:0] STATUS_SXL, STATUS_UXL, STATUS_XS, STATUS_FS, STATUS_FS_INT, STATUS_MPP_NEXT;
logic STATUS_MPIE, STATUS_SPIE, STATUS_UPIE, STATUS_UIE;

View File

@ -40,7 +40,8 @@ module privileged (
input logic InstrValidW, FloatRegWriteW, LoadStallD, BPPredWrongM,
input logic [3:0] InstrClassM,
input logic PrivilegedM,
input logic InstrPageFaultF, LoadPageFaultM, StorePageFaultM,
input logic ITLBInstrPageFaultF, DTLBLoadPageFaultM, DTLBStorePageFaultM,
input logic WalkerInstrPageFaultF, WalkerLoadPageFaultM, WalkerStorePageFaultM,
input logic InstrMisalignedFaultM, InstrAccessFaultF, IllegalIEUInstrFaultD,
input logic LoadMisalignedFaultM, LoadAccessFaultM,
input logic StoreMisalignedFaultM, StoreAccessFaultM,
@ -49,6 +50,7 @@ module privileged (
input logic [4:0] SetFflagsM,
output logic [1:0] PrivilegeModeW,
output logic [`XLEN-1:0] SATP_REGW,
output logic STATUS_MXR, STATUS_SUM,
output logic [2:0] FRM_REGW,
input logic FlushD, FlushE, FlushM, StallD, StallW, StallE, StallM
);
@ -63,7 +65,8 @@ module privileged (
logic uretM, sretM, mretM, ecallM, ebreakM, wfiM, sfencevmaM;
logic IllegalCSRAccessM;
logic IllegalIEUInstrFaultE, IllegalIEUInstrFaultM;
logic InstrPageFaultD, InstrPageFaultE, InstrPageFaultM;
logic LoadPageFaultM, StorePageFaultM;
logic InstrPageFaultF, InstrPageFaultD, InstrPageFaultE, InstrPageFaultM;
logic InstrAccessFaultD, InstrAccessFaultE, InstrAccessFaultM;
logic IllegalInstrFaultM;
@ -123,11 +126,12 @@ module privileged (
assign EcallFaultM = ecallM;
assign ITLBFlushF = sfencevmaM;
assign DTLBFlushM = sfencevmaM;
// *** Page faults now driven by page table walker. Might need to make the
// below signals ORs of a walker fault and a tlb fault if both of those come in
// assign InstrPageFaultM = 0;
// assign LoadPageFaultM = 0;
// assign StorePageFaultM = 0;
// A page fault might occur because of insufficient privilege during a TLB
// lookup or a improperly formatted page table during walking
assign InstrPageFaultF = ITLBInstrPageFaultF || WalkerInstrPageFaultF;
assign LoadPageFaultM = DTLBLoadPageFaultM || WalkerLoadPageFaultM;
assign StorePageFaultM = DTLBStorePageFaultM || WalkerStorePageFaultM;
// pipeline fault signals
flopenrc #(2) faultregD(clk, reset, FlushD, ~StallD,

View File

@ -77,7 +77,8 @@ module wallypipelinedhart (
logic InstrMisalignedFaultM;
logic DataMisalignedM;
logic IllegalBaseInstrFaultD, IllegalIEUInstrFaultD;
logic InstrPageFaultF, LoadPageFaultM, StorePageFaultM;
logic ITLBInstrPageFaultF, DTLBLoadPageFaultM, DTLBStorePageFaultM;
logic WalkerInstrPageFaultF, WalkerLoadPageFaultM, WalkerStorePageFaultM;
logic LoadMisalignedFaultM, LoadAccessFaultM;
logic StoreMisalignedFaultM, StoreAccessFaultM;
logic [`XLEN-1:0] InstrMisalignedAdrM;
@ -103,6 +104,7 @@ module wallypipelinedhart (
logic ITLBMissF, ITLBHitF;
logic DTLBMissM, DTLBHitM;
logic [`XLEN-1:0] SATP_REGW;
logic STATUS_MXR, STATUS_SUM;
logic [1:0] PrivilegeModeW;
logic [`XLEN-1:0] PageTableEntryF, PageTableEntryM;