From 37eb820e6b18940b9687e97306d3c6b669876b1f Mon Sep 17 00:00:00 2001 From: Andreas Kurth Date: Fri, 13 Dec 2024 13:51:30 +0000 Subject: [PATCH] [rtl,pmp] Allow all accesses to Debug Module in debug mode The RISC-V Debug Specification (current release 1.0.0-rc4) in Section A.2 states that the PMP must not disallow accesses to addresses of the Debug Module when the hart is in debug mode, regardless of how the PMP is configured. This commit changes the PMP accordingly. Signed-off-by: Andreas Kurth --- doc/02_user/integration.rst | 6 ++++++ doc/03_reference/debug.rst | 4 ++++ doc/03_reference/pmp.rst | 6 ++++++ .../rtl/ibex_riscv_compliance.sv | 2 ++ dv/uvm/core_ibex/tb/core_ibex_tb_top.sv | 2 ++ .../simple_system/rtl/ibex_simple_system.sv | 2 ++ rtl/ibex_core.sv | 5 +++++ rtl/ibex_lockstep.sv | 4 ++++ rtl/ibex_pmp.sv | 17 ++++++++++++++++- rtl/ibex_top.sv | 10 ++++++++++ rtl/ibex_top_tracing.sv | 4 ++++ 11 files changed, 61 insertions(+), 1 deletion(-) diff --git a/doc/02_user/integration.rst b/doc/02_user/integration.rst index 17e3652e59..cc3c59c84d 100644 --- a/doc/02_user/integration.rst +++ b/doc/02_user/integration.rst @@ -108,6 +108,8 @@ Instantiation Template .RndCnstLfsrSeed ( ibex_pkg::RndCnstLfsrSeedDefault ), .RndCnstLfsrPerm ( ibex_pkg::RndCnstLfsrPermDefault ), .DbgTriggerEn ( 0 ), + .DmBaseAddr ( 32'h1A110000 ), + .DmAddrMask ( 32'h00000FFF ), .DmHaltAddr ( 32'h1A110800 ), .DmExceptionAddr ( 32'h1A110808 ) ) u_top ( @@ -224,6 +226,10 @@ Parameters +------------------------------+---------------------+------------+-----------------------------------------------------------------------+ | ``DbgTriggerEn`` | bit | 0 | Enable debug trigger support (one trigger only) | +------------------------------+---------------------+------------+-----------------------------------------------------------------------+ +| ``DmBaseAddr`` | int | 0x1A110000 | Base address of the Debug Module | ++------------------------------+---------------------+------------+-----------------------------------------------------------------------+ +| ``DmAddrMask`` | int | 0x1A110000 | Address mask of the Debug Module | ++------------------------------+---------------------+------------+-----------------------------------------------------------------------+ | ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode | +------------------------------+---------------------+------------+-----------------------------------------------------------------------+ | ``DmExceptionAddr`` | int | 0x1A110808 | Address to jump to when an exception occurs while in Debug Mode | diff --git a/doc/03_reference/debug.rst b/doc/03_reference/debug.rst index 5574f4f5d4..6b67db42e6 100644 --- a/doc/03_reference/debug.rst +++ b/doc/03_reference/debug.rst @@ -32,6 +32,10 @@ Parameters +---------------------+-----------------------------------------------------------------+ | Parameter | Description | +=====================+=================================================================+ +| ``DmBaseAddr`` | Base address of the Debug Module | ++---------------------+-----------------------------------------------------------------+ +| ``DmAddrMask`` | Address mask of the Debug Module | ++---------------------+-----------------------------------------------------------------+ | ``DmHaltAddr`` | Address to jump to when entering Debug Mode | +---------------------+-----------------------------------------------------------------+ | ``DmExceptionAddr`` | Address to jump to when an exception occurs while in Debug Mode | diff --git a/doc/03_reference/pmp.rst b/doc/03_reference/pmp.rst index 6494a0d45d..d4993020dd 100644 --- a/doc/03_reference/pmp.rst +++ b/doc/03_reference/pmp.rst @@ -52,3 +52,9 @@ By default all PMP CSRs (include ``mseccfg``) are reset to 0. Some applications may want other reset values. Default reset values are defined in :file:`ibex_pkg.sv`. An implementation can either modify this file or pass custom reset values as a module parameter. + +Debug Mode +---------- + +In debug mode, the PMP allows all accesses to addresses of the Debug Module, as defined by the `DmBaseAddr` and `DmAddrMask` module parameters. +This is mandated by the RISC-V Debug Specification (v1.0.0). diff --git a/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv b/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv index 8d3669ef33..10d0bb053d 100644 --- a/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv +++ b/dv/riscv_compliance/rtl/ibex_riscv_compliance.sv @@ -155,6 +155,8 @@ module ibex_riscv_compliance ( .DbgTriggerEn (DbgTriggerEn ), .SecureIbex (SecureIbex ), .ICacheScramble (ICacheScramble ), + .DmBaseAddr (32'h00000000 ), + .DmAddrMask (32'h00000003 ), .DmHaltAddr (32'h00000000 ), .DmExceptionAddr (32'h00000000 ) ) u_top ( diff --git a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv index 601509975d..5ca14c0664 100644 --- a/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv +++ b/dv/uvm/core_ibex/tb/core_ibex_tb_top.sv @@ -84,6 +84,8 @@ module core_ibex_tb_top; assign {scramble_key, scramble_nonce} = scrambling_key_if.d_data; ibex_top_tracing #( + .DmBaseAddr (32'h`BOOT_ADDR ), + .DmAddrMask (32'h0000_0007 ), .DmHaltAddr (32'h`BOOT_ADDR + 'h0 ), .DmExceptionAddr (32'h`BOOT_ADDR + 'h4 ), .PMPEnable (PMPEnable ), diff --git a/examples/simple_system/rtl/ibex_simple_system.sv b/examples/simple_system/rtl/ibex_simple_system.sv index ac74691d68..e466ac286d 100644 --- a/examples/simple_system/rtl/ibex_simple_system.sv +++ b/examples/simple_system/rtl/ibex_simple_system.sv @@ -204,6 +204,8 @@ module ibex_simple_system ( .WritebackStage ( WritebackStage ), .BranchPredictor ( BranchPredictor ), .DbgTriggerEn ( DbgTriggerEn ), + .DmBaseAddr ( 32'h00100000 ), + .DmAddrMask ( 32'h00000003 ), .DmHaltAddr ( 32'h00100000 ), .DmExceptionAddr ( 32'h00100000 ) ) u_top ( diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 807e315133..67ab922466 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -44,6 +44,8 @@ module ibex_core import ibex_pkg::*; #( parameter int unsigned RegFileDataWidth = 32, parameter bit MemECC = 1'b0, parameter int unsigned MemDataWidth = MemECC ? 32 + 7 : 32, + parameter int unsigned DmBaseAddr = 32'h1A110000, + parameter int unsigned DmAddrMask = 32'h00000FFF, parameter int unsigned DmHaltAddr = 32'h1A110800, parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( @@ -1177,6 +1179,8 @@ module ibex_core import ibex_pkg::*; #( assign pmp_priv_lvl[PMP_D] = priv_mode_lsu; ibex_pmp #( + .DmBaseAddr (DmBaseAddr), + .DmAddrMask (DmAddrMask), .PMPGranularity(PMPGranularity), .PMPNumChan (PMPNumChan), .PMPNumRegions (PMPNumRegions) @@ -1185,6 +1189,7 @@ module ibex_core import ibex_pkg::*; #( .csr_pmp_cfg_i (csr_pmp_cfg), .csr_pmp_addr_i (csr_pmp_addr), .csr_pmp_mseccfg_i(csr_pmp_mseccfg), + .debug_mode_i (debug_mode), .priv_mode_i (pmp_priv_lvl), // Access checking channels .pmp_req_addr_i (pmp_req_addr), diff --git a/rtl/ibex_lockstep.sv b/rtl/ibex_lockstep.sv index 6d2f176c54..7466e9eb34 100644 --- a/rtl/ibex_lockstep.sv +++ b/rtl/ibex_lockstep.sv @@ -40,6 +40,8 @@ module ibex_lockstep import ibex_pkg::*; #( parameter int unsigned RegFileDataWidth = 32, parameter bit MemECC = 1'b0, parameter int unsigned MemDataWidth = MemECC ? 32 + 7 : 32, + parameter int unsigned DmBaseAddr = 32'h1A110000, + parameter int unsigned DmAddrMask = 32'h00000FFF, parameter int unsigned DmHaltAddr = 32'h1A110800, parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( @@ -377,6 +379,8 @@ module ibex_lockstep import ibex_pkg::*; #( .RegFileDataWidth ( RegFileDataWidth ), .MemECC ( MemECC ), .MemDataWidth ( MemDataWidth ), + .DmBaseAddr ( DmBaseAddr ), + .DmAddrMask ( DmAddrMask ), .DmHaltAddr ( DmHaltAddr ), .DmExceptionAddr ( DmExceptionAddr ) ) u_shadow_core ( diff --git a/rtl/ibex_pmp.sv b/rtl/ibex_pmp.sv index 48c3a7ed67..12827e0f93 100644 --- a/rtl/ibex_pmp.sv +++ b/rtl/ibex_pmp.sv @@ -5,6 +5,8 @@ `include "dv_fcov_macros.svh" module ibex_pmp #( + parameter int unsigned DmBaseAddr = 32'h1A110000, + parameter int unsigned DmAddrMask = 32'h00000FFF, // Granularity of NAPOT access, // 0 = No restriction, 1 = 8 byte, 2 = 16 byte, 3 = 32 byte, etc. parameter int unsigned PMPGranularity = 0, @@ -18,6 +20,8 @@ module ibex_pmp #( input logic [33:0] csr_pmp_addr_i [PMPNumRegions], input ibex_pkg::pmp_mseccfg_t csr_pmp_mseccfg_i, + input logic debug_mode_i, + input ibex_pkg::priv_lvl_e priv_mode_i [PMPNumChan], // Access checking channels input logic [33:0] pmp_req_addr_i [PMPNumChan], @@ -37,6 +41,7 @@ module ibex_pmp #( logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_match_all; logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_basic_perm_check; logic [PMPNumChan-1:0][PMPNumRegions-1:0] region_perm_check; + logic [PMPNumChan-1:0] debug_mode_allowed_access; /////////////////////// // Functions for PMP // @@ -48,6 +53,7 @@ module ibex_pmp #( // | // region_match_all --------------------------------> access_fault_check <---------- // | + // !debug_mode_allowed_access ------------------------------> & // \--> pmp_req_err_o // Compute permissions checks that apply when MSECCFG.MML is set. Added for Smepmp support. @@ -226,6 +232,13 @@ module ibex_pmp #( pmp_req_addr_i[c][PMPGranularity+2-1:0]}; end + // Determine whether the core is in debug mode and the access is to an address in the range of + // the Debug Module. According to Section A.2 of the RISC-V Debug Specification, the PMP must + // not disallow fetches, loads, or stores in the address range associated with the Debug Module + // when the hart is in debug mode. + assign debug_mode_allowed_access[c] = debug_mode_i & + ((pmp_req_addr_i[c][31:0] & ~DmAddrMask) == DmBaseAddr); + // Once the permission checks of the regions are done, decide if the access is // denied by figuring out the matching region and its permission check. assign pmp_req_err_o[c] = access_fault_check(csr_pmp_mseccfg_i.mmwp, @@ -233,7 +246,9 @@ module ibex_pmp #( pmp_req_type_i[c], region_match_all[c], priv_mode_i[c], - region_perm_check[c]); + region_perm_check[c]) & + // No error if the access is allowed as Debug Module access. + ~debug_mode_allowed_access[c]; // Access fails check against one region but access allowed due to another higher-priority // region. diff --git a/rtl/ibex_top.sv b/rtl/ibex_top.sv index 8991c17251..a90fee0e66 100644 --- a/rtl/ibex_top.sv +++ b/rtl/ibex_top.sv @@ -37,6 +37,8 @@ module ibex_top import ibex_pkg::*; #( parameter int unsigned ICacheScrNumPrinceRoundsHalf = 2, parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, + parameter int unsigned DmBaseAddr = 32'h1A110000, + parameter int unsigned DmAddrMask = 32'h00000FFF, parameter int unsigned DmHaltAddr = 32'h1A110800, parameter int unsigned DmExceptionAddr = 32'h1A110808, // Default seed and nonce for scrambling @@ -313,6 +315,8 @@ module ibex_top import ibex_pkg::*; #( .RegFileDataWidth (RegFileDataWidth), .MemECC (MemECC), .MemDataWidth (MemDataWidth), + .DmBaseAddr (DmBaseAddr), + .DmAddrMask (DmAddrMask), .DmHaltAddr (DmHaltAddr), .DmExceptionAddr (DmExceptionAddr) ) u_ibex_core ( @@ -1016,6 +1020,8 @@ module ibex_top import ibex_pkg::*; #( .RegFileECC (RegFileECC), .RegFileDataWidth (RegFileDataWidth), .MemECC (MemECC), + .DmBaseAddr (DmBaseAddr), + .DmAddrMask (DmAddrMask), .DmHaltAddr (DmHaltAddr), .DmExceptionAddr (DmExceptionAddr) ) u_ibex_lockstep ( @@ -1120,6 +1126,10 @@ module ibex_top import ibex_pkg::*; #( assign alert_major_bus_o = core_alert_major_bus | lockstep_alert_major_bus; assign alert_minor_o = core_alert_minor | lockstep_alert_minor; + // Parameter assertions + `ASSERT_INIT(DmHaltAddrInRange_A, (DmHaltAddr & ~DmAddrMask) == DmBaseAddr) + `ASSERT_INIT(DmExceptionAddrInRange_A, (DmExceptionAddr & ~DmAddrMask) == DmBaseAddr) + // X checks for top-level outputs `ASSERT_KNOWN(IbexInstrReqX, instr_req_o) `ASSERT_KNOWN_IF(IbexInstrReqPayloadX, instr_addr_o, instr_req_o) diff --git a/rtl/ibex_top_tracing.sv b/rtl/ibex_top_tracing.sv index 14fcfb2994..b9f8045c06 100644 --- a/rtl/ibex_top_tracing.sv +++ b/rtl/ibex_top_tracing.sv @@ -27,6 +27,8 @@ module ibex_top_tracing import ibex_pkg::*; #( parameter bit ICacheScramble = 1'b0, parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, + parameter int unsigned DmBaseAddr = 32'h1A110000, + parameter int unsigned DmAddrMask = 32'h00000FFF, parameter int unsigned DmHaltAddr = 32'h1A110800, parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( @@ -184,6 +186,8 @@ module ibex_top_tracing import ibex_pkg::*; #( .ICacheScramble ( ICacheScramble ), .RndCnstLfsrSeed ( RndCnstLfsrSeed ), .RndCnstLfsrPerm ( RndCnstLfsrPerm ), + .DmBaseAddr ( DmBaseAddr ), + .DmAddrMask ( DmAddrMask ), .DmHaltAddr ( DmHaltAddr ), .DmExceptionAddr ( DmExceptionAddr ) ) u_ibex_top (