From 5f2bccd88fe4b83448dccc6f78d77e441415da07 Mon Sep 17 00:00:00 2001 From: Thomas Fleming Date: Thu, 29 Apr 2021 02:20:39 -0400 Subject: [PATCH] Clean up PMA checker and begin PMP checker --- wally-pipelined/src/ebu/ahblite.sv | 96 ++++++++-------- wally-pipelined/src/privileged/csr.sv | 2 + wally-pipelined/src/privileged/csrm.sv | 3 +- wally-pipelined/src/privileged/csrsr.sv | 5 +- .../src/{ebu => privileged}/pmachecker.sv | 29 +++-- wally-pipelined/src/privileged/pmpchecker.sv | 104 ++++++++++++++++++ wally-pipelined/src/privileged/privileged.sv | 18 ++- .../src/wally/wallypipelinedhart.sv | 4 +- 8 files changed, 196 insertions(+), 65 deletions(-) rename wally-pipelined/src/{ebu => privileged}/pmachecker.sv (75%) create mode 100644 wally-pipelined/src/privileged/pmpchecker.sv diff --git a/wally-pipelined/src/ebu/ahblite.sv b/wally-pipelined/src/ebu/ahblite.sv index 23ae2eb65..d829dee66 100644 --- a/wally-pipelined/src/ebu/ahblite.sv +++ b/wally-pipelined/src/ebu/ahblite.sv @@ -58,7 +58,9 @@ module ahblite ( output logic [`XLEN-1:0] MMUReadPTE, output logic MMUReady, // Signals from PMA checker - input logic SquashAHBAccess, + input logic SquashBusAccess, + // Signals to PMA checker (metadata of proposed access) + output logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM, // Return from bus output logic [`XLEN-1:0] ReadDataW, // AHB-Lite external signals @@ -79,8 +81,7 @@ module ahblite ( output logic HWRITED, // Stalls output logic /*InstrUpdate, */DataStall, - output logic MemAckW - // *** add a chip-level ready signal as part of handshake + output logic MemAckW ); logic GrantData; @@ -90,9 +91,6 @@ module ahblite ( logic IReady, DReady; logic CaptureDataM,CapturedDataAvailable; - // Describes type of access - logic Atomic, Execute, Write, Read; - assign HCLK = clk; assign HRESETn = ~reset; @@ -103,43 +101,56 @@ module ahblite ( // while an instruction read is occuring, the instruction read finishes before // the data access can take place. import ahbliteState::*; - statetype BusState, NextBusState; + statetype BusState, ProposedNextBusState, NextBusState; flopenl #(.TYPE(statetype)) busreg(HCLK, ~HRESETn, 1'b1, NextBusState, IDLE, BusState); - // *** If the SquashAHBAccess signal is high, we need to set NextBusState to IDLE. - // We could either have this case statement set a signal ProposedNextBusState, which gets - // used for NextBusState when we are not squashing. Alternatively, we could add a bunch of - // conditional statments below + // This case statement computes the desired next state for the AHBlite, + // prioritizing address translations, then atomics, then data accesses, and + // finally instructions. This proposition controls HADDR so the PMA and PMP + // checkers can determine whether the access is allowed. If not, the actual + // NextWalkerState is set to IDLE. + + // *** This ability to squash accesses must be replicated by any bus + // interface that might be used in place of the ahblite. always_comb case (BusState) - IDLE: if (MMUTranslate) NextBusState = MMUTRANSLATE; - else if (AtomicMaskedM[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; - MMUTRANSLATE: if (~HREADY) NextBusState = MMUTRANSLATE; - else NextBusState = IDLE; - ATOMICREAD: if (~HREADY) NextBusState = ATOMICREAD; - else NextBusState = ATOMICWRITE; - ATOMICWRITE: if (~HREADY) NextBusState = ATOMICWRITE; - else if (InstrReadF) NextBusState = INSTRREAD; - else NextBusState = IDLE; - MEMREAD: if (~HREADY) NextBusState = MEMREAD; - else if (InstrReadF) NextBusState = INSTRREADC; - else NextBusState = IDLE; - MEMWRITE: if (~HREADY) NextBusState = MEMWRITE; - else if (InstrReadF) NextBusState = INSTRREAD; - else NextBusState = IDLE; - INSTRREAD: - if (~HREADY) NextBusState = INSTRREAD; - else NextBusState = IDLE; // if (InstrReadF still high) - INSTRREADC: if (~HREADY) NextBusState = INSTRREADC; // "C" for "competing", meaning please don't mess up the memread in the W stage. - else NextBusState = IDLE; - default: NextBusState = IDLE; + IDLE: if (MMUTranslate) ProposedNextBusState = MMUTRANSLATE; + else if (AtomicMaskedM[1]) ProposedNextBusState = ATOMICREAD; + else if (MemReadM) ProposedNextBusState = MEMREAD; // Memory has priority over instructions + else if (MemWriteM) ProposedNextBusState = MEMWRITE; + else if (InstrReadF) ProposedNextBusState = INSTRREAD; + else ProposedNextBusState = IDLE; + MMUTRANSLATE: if (~HREADY) ProposedNextBusState = MMUTRANSLATE; + else ProposedNextBusState = IDLE; + ATOMICREAD: if (~HREADY) ProposedNextBusState = ATOMICREAD; + else ProposedNextBusState = ATOMICWRITE; + ATOMICWRITE: if (~HREADY) ProposedNextBusState = ATOMICWRITE; + else if (InstrReadF) ProposedNextBusState = INSTRREAD; + else ProposedNextBusState = IDLE; + MEMREAD: if (~HREADY) ProposedNextBusState = MEMREAD; + else if (InstrReadF) ProposedNextBusState = INSTRREADC; + else ProposedNextBusState = IDLE; + MEMWRITE: if (~HREADY) ProposedNextBusState = MEMWRITE; + else if (InstrReadF) ProposedNextBusState = INSTRREAD; + else ProposedNextBusState = IDLE; + INSTRREAD: if (~HREADY) ProposedNextBusState = INSTRREAD; + else ProposedNextBusState = IDLE; // if (InstrReadF still high) + INSTRREADC: if (~HREADY) ProposedNextBusState = INSTRREADC; // "C" for "competing", meaning please don't mess up the memread in the W stage. + else ProposedNextBusState = IDLE; + default: ProposedNextBusState = IDLE; endcase + // Determine access type (important for determining whether to fault) + assign AtomicAccessM = (ProposedNextBusState == ATOMICREAD) || (ProposedNextBusState == ATOMICWRITE); + assign ExecuteAccessF = (ProposedNextBusState == INSTRREAD) || (ProposedNextBusState == INSTRREADC); + assign WriteAccessM = (ProposedNextBusState == MEMWRITE) || (ProposedNextBusState == ATOMICWRITE); + assign ReadAccessM = (ProposedNextBusState == MEMREAD) || (ProposedNextBusState == ATOMICREAD) || + (ProposedNextBusState == MMUTRANSLATE); + + // The PMA and PMP checkers can decide to squash the access + assign NextBusState = (SquashBusAccess) ? IDLE : ProposedNextBusState; + // stall signals // Note that we need to extend both stalls when MMUTRANSLATE goes to idle, // since translation might not be complete. @@ -150,16 +161,9 @@ module ahblite ( assign #1 InstrStall = ((NextBusState == INSTRREAD) || (NextBusState == INSTRREADC) || MMUStall); - // 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); + assign #1 GrantData = (ProposedNextBusState == MEMREAD) || (ProposedNextBusState == MEMWRITE) || + (ProposedNextBusState == ATOMICREAD) || (ProposedNextBusState == ATOMICWRITE); assign #1 AccessAddress = (GrantData) ? MemPAdrM[31:0] : InstrPAdrF[31:0]; assign #1 HADDR = (MMUTranslate) ? MMUPAdr[31:0] : AccessAddress; generate @@ -184,7 +188,7 @@ module ahblite ( // Route signals to Instruction and Data Caches // *** assumes AHBW = XLEN - assign MMUReady = (BusState == MMUTRANSLATE && NextBusState == IDLE); + assign MMUReady = (BusState == MMUTRANSLATE && HREADY); assign InstrRData = HRDATA; assign InstrAckF = (BusState == INSTRREAD) && (NextBusState != INSTRREAD) || (BusState == INSTRREADC) && (NextBusState != INSTRREADC); diff --git a/wally-pipelined/src/privileged/csr.sv b/wally-pipelined/src/privileged/csr.sv index b457f7d34..36074415b 100644 --- a/wally-pipelined/src/privileged/csr.sv +++ b/wally-pipelined/src/privileged/csr.sv @@ -54,6 +54,8 @@ module csr #(parameter output logic [11:0] MIP_REGW, MIE_REGW, output logic STATUS_MIE, STATUS_SIE, output logic STATUS_MXR, STATUS_SUM, + output logic STATUS_MPRV, + output logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15], 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, diff --git a/wally-pipelined/src/privileged/csrm.sv b/wally-pipelined/src/privileged/csrm.sv index 5ab8fa38d..374a2a594 100644 --- a/wally-pipelined/src/privileged/csrm.sv +++ b/wally-pipelined/src/privileged/csrm.sv @@ -91,6 +91,7 @@ module csrm #(parameter output logic [`XLEN-1:0] CSRMReadValM, MEPC_REGW, MTVEC_REGW, output logic [31:0] MCOUNTEREN_REGW, MCOUNTINHIBIT_REGW, output logic [`XLEN-1:0] MEDELEG_REGW, MIDELEG_REGW, + output logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15], input logic [11:0] MIP_REGW, MIE_REGW, output logic WriteMSTATUSM, output logic IllegalCSRMAccessM, IllegalCSRMWriteReadonlyM @@ -99,8 +100,6 @@ module csrm #(parameter logic [`XLEN-1:0] MISA_REGW; logic [`XLEN-1:0] MSCRATCH_REGW,MCAUSE_REGW, MTVAL_REGW; logic [63:0] PMPCFG01_REGW, PMPCFG23_REGW; // 64-bit registers in RV64, or two 32-bit registers in RV32 - logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15]; // *** Might have to make 16 individual registers - //logic [`XLEN-1:0] PMPADDR0_REGW; logic WriteMTVECM, WriteMEDELEGM, WriteMIDELEGM; logic WriteMSCRATCHM, WriteMEPCM, WriteMCAUSEM, WriteMTVALM; diff --git a/wally-pipelined/src/privileged/csrsr.sv b/wally-pipelined/src/privileged/csrsr.sv index ecfcf4e82..8c5c7a3d1 100644 --- a/wally-pipelined/src/privileged/csrsr.sv +++ b/wally-pipelined/src/privileged/csrsr.sv @@ -37,10 +37,11 @@ module csrsr ( output logic [1:0] STATUS_MPP, output logic STATUS_SPP, STATUS_TSR, output logic STATUS_MIE, STATUS_SIE, - output logic STATUS_MXR, STATUS_SUM + output logic STATUS_MXR, STATUS_SUM, + output logic STATUS_MPRV ); - logic STATUS_SD, STATUS_TW, STATUS_TVM, STATUS_SUM_INT, STATUS_MPRV, STATUS_MPRV_INT; + logic STATUS_SD, STATUS_TW, STATUS_TVM, STATUS_SUM_INT, 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; diff --git a/wally-pipelined/src/ebu/pmachecker.sv b/wally-pipelined/src/privileged/pmachecker.sv similarity index 75% rename from wally-pipelined/src/ebu/pmachecker.sv rename to wally-pipelined/src/privileged/pmachecker.sv index 2f4e32dc2..214b9b4b9 100644 --- a/wally-pipelined/src/ebu/pmachecker.sv +++ b/wally-pipelined/src/privileged/pmachecker.sv @@ -28,22 +28,22 @@ `include "wally-config.vh" module pmachecker ( + input logic clk, reset, + input logic [31:0] HADDR, input logic [2:0] HSIZE, - input logic HWRITE, input logic [2:0] HBURST, - input logic Atomic, Execute, Write, Read, + input logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM, - // *** Add pipeline suffixes output logic Cacheable, Idempotent, AtomicAllowed, - output logic SquashAHBAccess, + output logic PMASquashBusAccess, output logic [5:0] HSELRegions, - output logic InstrAccessFaultF, - output logic LoadAccessFaultM, - output logic StoreAccessFaultM + output logic PMAInstrAccessFaultF, + output logic PMALoadAccessFaultM, + output logic PMAStoreAccessFaultM ); // Signals are high if the memory access is within the given region @@ -51,6 +51,7 @@ module pmachecker ( logic PreHSELUART; + logic ExecutableRegion, ReadableRegion, WritableRegion; logic Empty; // Determine which region of physical memory (if any) is being accessed @@ -61,6 +62,7 @@ module pmachecker ( adrdec uartdec(HADDR, `UARTBASE, `UARTRANGE, PreHSELUART); adrdec plicdec(HADDR, `PLICBASE, `PLICRANGE, HSELPLIC); + // *** Should this fault? assign HSELUART = PreHSELUART && (HSIZE == 3'b000); // only byte writes to UART are supported // Swizzle region bits @@ -75,12 +77,17 @@ module pmachecker ( // *** Temporarily assume only RAM regions allow full atomic operations -- likely wrong assign AtomicAllowed = HSELBootTim | HSELTim; + assign ExecutableRegion = HSELBootTim | HSELTim; + assign ReadableRegion = HSELBootTim | HSELTim | HSELCLINT | HSELGPIO | HSELUART | HSELPLIC; + assign WritableRegion = HSELBootTim | HSELTim | HSELCLINT | HSELGPIO | HSELUART | HSELPLIC; + assign Empty = ~|HSELRegions; - assign InstrAccessFaultF = Empty && Execute; - assign LoadAccessFaultM = Empty && Read; - assign StoreAccessFaultM = Empty && Write; + assign PMAInstrAccessFaultF = ExecuteAccessF && (Empty || ~ExecutableRegion); + assign PMALoadAccessFaultM = ReadAccessM && (Empty || ~ReadableRegion); + assign PMAStoreAccessFaultM = WriteAccessM && (Empty || ~WritableRegion); - assign SquashAHBAccess = InstrAccessFaultF || LoadAccessFaultM || StoreAccessFaultM; + //assign PMASquashBusAccess = PMAInstrAccessFaultF || PMALoadAccessFaultM || PMAStoreAccessFaultM; + assign PMASquashBusAccess = 0; endmodule diff --git a/wally-pipelined/src/privileged/pmpchecker.sv b/wally-pipelined/src/privileged/pmpchecker.sv new file mode 100644 index 000000000..2ca0b5984 --- /dev/null +++ b/wally-pipelined/src/privileged/pmpchecker.sv @@ -0,0 +1,104 @@ +/////////////////////////////////////////// +// pmpchecker.sv +// +// Written: tfleming@hmc.edu & jtorrey@hmc.edu 28 April 2021 +// Modified: +// +// Purpose: Examines all physical memory accesses and checks them against the +// current values of the physical memory protection (PMP) registers. +// Can raise an access fault on illegal reads, writes, and instruction +// fetches. +// +// A component of the Wally configurable RISC-V project. +// +// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +/////////////////////////////////////////// + +`include "wally-config.vh" + +module pmpchecker ( + input logic clk, reset, + + input logic [31:0] HADDR, + + input logic [1:0] PrivilegeModeW, + + input logic [1:0] STATUS_MPP, + input logic STATUS_MPRV, + + input logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15], + + input logic ExecuteAccessF, WriteAccessM, ReadAccessM, + + output logic PMPSquashBusAccess, + + output logic PMPInstrAccessFaultF, + output logic PMPLoadAccessFaultM, + output logic PMPStoreAccessFaultM +); + + assign PMPSquashBusAccess = '0; + assign PMPInstrAccessFaultF = '0; + assign PMPLoadAccessFaultM = '0; + assign PMPStoreAccessFaultM = '0; + + + + /* + // Signals are high if the memory access is within the given region + logic HSELBootTim, HSELTim, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC; + + logic PreHSELUART; + + logic ExecutableRegion, ReadableRegion, WritableRegion; + logic Empty; + + // Determine which region of physical memory (if any) is being accessed + adrdec boottimdec(HADDR, `BOOTTIMBASE, `BOOTTIMRANGE, HSELBootTim); + adrdec timdec(HADDR, `TIMBASE, `TIMRANGE, HSELTim); + adrdec clintdec(HADDR, `CLINTBASE, `CLINTRANGE, HSELCLINT); + adrdec gpiodec(HADDR, `GPIOBASE, `GPIORANGE, HSELGPIO); + adrdec uartdec(HADDR, `UARTBASE, `UARTRANGE, PreHSELUART); + adrdec plicdec(HADDR, `PLICBASE, `PLICRANGE, HSELPLIC); + + // *** Should this fault? + assign HSELUART = PreHSELUART && (HSIZE == 3'b000); // only byte writes to UART are supported + + // Swizzle region bits + assign HSELRegions = {HSELBootTim, HSELTim, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC}; + + // Only RAM memory regions are cacheable + assign Cacheable = HSELBootTim | HSELTim; + + // *** Temporarily assume only RAM regions are idempotent -- likely wrong + assign Idempotent = HSELBootTim | HSELTim; + + // *** Temporarily assume only RAM regions allow full atomic operations -- likely wrong + assign AtomicAllowed = HSELBootTim | HSELTim; + + assign ExecutableRegion = HSELBootTim | HSELTim; + assign ReadableRegion = HSELBootTim | HSELTim | HSELCLINT | HSELGPIO | HSELUART | HSELPLIC; + assign WritableRegion = HSELBootTim | HSELTim | HSELCLINT | HSELGPIO | HSELUART | HSELPLIC; + + assign Empty = ~|HSELRegions; + + assign InstrAccessFaultF = ExecuteAccessF && (Empty || ~ExecutableRegion); + assign LoadAccessFaultM = ReadAccessM && (Empty || ~ReadableRegion); + assign StoreAccessFaultM = WriteAccessM && (Empty || ~WritableRegion); + + assign SquashBusAccess = InstrAccessFaultF || LoadAccessFaultM || StoreAccessFaultM; + */ + +endmodule diff --git a/wally-pipelined/src/privileged/privileged.sv b/wally-pipelined/src/privileged/privileged.sv index ef312c7b6..493f8c894 100644 --- a/wally-pipelined/src/privileged/privileged.sv +++ b/wally-pipelined/src/privileged/privileged.sv @@ -62,9 +62,9 @@ module privileged ( input logic [31:0] HADDR, input logic [2:0] HSIZE, HBURST, input logic HWRITE, - input logic Atomic, Execute, Write, Read, + input logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM, output logic Cacheable, Idempotent, AtomicAllowed, - output logic SquashAHBAccess, + output logic SquashBusAccess, output logic [5:0] HSELRegions ); @@ -90,9 +90,16 @@ module privileged ( logic [1:0] STATUS_MPP; logic STATUS_SPP, STATUS_TSR; logic STATUS_MIE, STATUS_SIE; + logic STATUS_MPRV; logic [11:0] MIP_REGW, MIE_REGW; logic md, sd; + logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15]; + + logic PMASquashBusAccess, PMPSquashBusAccess; + logic PMAInstrAccessFaultF, PMALoadAccessFaultM, PMAStoreAccessFaultM; + logic PMPInstrAccessFaultF, PMPLoadAccessFaultM, PMPStoreAccessFaultM; + /////////////////////////////////////////// // track the current privilege level /////////////////////////////////////////// @@ -137,6 +144,7 @@ module privileged ( /////////////////////////////////////////// pmachecker pmachecker(.*); + pmpchecker pmpchecker(.*); /////////////////////////////////////////// // Extract exceptions by name and handle them @@ -153,6 +161,12 @@ module privileged ( assign LoadPageFaultM = DTLBLoadPageFaultM || WalkerLoadPageFaultM; assign StorePageFaultM = DTLBStorePageFaultM || WalkerStorePageFaultM; + assign InstrAccessFaultF = PMAInstrAccessFaultF || PMPInstrAccessFaultF; + assign LoadAccessFaultM = PMALoadAccessFaultM || PMPLoadAccessFaultM; + assign StoreAccessFaultM = PMAStoreAccessFaultM || PMPStoreAccessFaultM; + + assign SquashBusAccess = PMASquashBusAccess || PMPSquashBusAccess; + // pipeline fault signals flopenrc #(2) faultregD(clk, reset, FlushD, ~StallD, {InstrPageFaultF, InstrAccessFaultF}, diff --git a/wally-pipelined/src/wally/wallypipelinedhart.sv b/wally-pipelined/src/wally/wallypipelinedhart.sv index 8bf503c9b..b91e2e3a5 100644 --- a/wally-pipelined/src/wally/wallypipelinedhart.sv +++ b/wally-pipelined/src/wally/wallypipelinedhart.sv @@ -112,9 +112,9 @@ module wallypipelinedhart ( logic [1:0] PageTypeF, PageTypeM; // PMA checker signals - logic Atomic, Execute, Write, Read; + logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM; logic Cacheable, Idempotent, AtomicAllowed; - logic SquashAHBAccess; + logic SquashBusAccess; // IMem stalls logic ICacheStallF;