diff --git a/doc/02_user/integration.rst b/doc/02_user/integration.rst index e1eca280bb..470224e7ab 100644 --- a/doc/02_user/integration.rst +++ b/doc/02_user/integration.rst @@ -15,22 +15,24 @@ Instantiation Template .. code-block:: verilog ibex_top #( - .PMPEnable ( 0 ), - .PMPGranularity ( 0 ), - .PMPNumRegions ( 4 ), - .MHPMCounterNum ( 0 ), - .MHPMCounterWidth ( 40 ), - .RV32E ( 0 ), - .RV32M ( ibex_pkg::RV32MFast ), - .RV32B ( ibex_pkg::RV32BNone ), - .RegFile ( ibex_pkg::RegFileFF ), - .ICache ( 0 ), - .ICacheECC ( 0 ), - .BranchPrediction ( 0 ), - .SecureIbex ( 0 ), - .DbgTriggerEn ( 0 ), - .DmHaltAddr ( 32'h1A110800 ), - .DmExceptionAddr ( 32'h1A110808 ) + .PMPEnable ( 0 ), + .PMPGranularity ( 0 ), + .PMPNumRegions ( 4 ), + .MHPMCounterNum ( 0 ), + .MHPMCounterWidth ( 40 ), + .RV32E ( 0 ), + .RV32M ( ibex_pkg::RV32MFast ), + .RV32B ( ibex_pkg::RV32BNone ), + .RegFile ( ibex_pkg::RegFileFF ), + .ICache ( 0 ), + .ICacheECC ( 0 ), + .BranchPrediction ( 0 ), + .SecureIbex ( 0 ), + .RndCnstLfsrSeed ( ibex_pkg::RndCnstLfsrSeedDefault ), + .RndCnstLfsrPerm ( ibex_pkg::RndCnstLfsrPermDefault ), + .DbgTriggerEn ( 0 ), + .DmHaltAddr ( 32'h1A110800 ), + .DmExceptionAddr ( 32'h1A110808 ) ) u_top ( // Clock and reset .clk_i (), @@ -132,6 +134,12 @@ Parameters | | | | secure code execution. Note: SecureIbex == 1'b1 and | | | | | RV32M == ibex_pkg::RV32MNone is an illegal combination. | +------------------------------+---------------------+------------+-----------------------------------------------------------------------+ +| ``RndCnstLfsrSeed`` | lfsr_seed_t | see above | Set the starting seed of the LFSR used to generate dummy instructions | +| | | | (only relevant when SecureIbex == 1'b1) | ++------------------------------+---------------------+------------+-----------------------------------------------------------------------+ +| ``RndCnstLfsrPerm`` | lfsr_perm_t | see above | Set the permutation applied to the output of the LFSR used to | +| | | | generate dummy instructions (only relevant when SecureIbex == 1'b1) | ++------------------------------+---------------------+------------+-----------------------------------------------------------------------+ | ``DbgTriggerEn`` | bit | 0 | Enable debug trigger support (one trigger only) | +------------------------------+---------------------+------------+-----------------------------------------------------------------------+ | ``DmHaltAddr`` | int | 0x1A110800 | Address to jump to when entering Debug Mode | diff --git a/doc/03_reference/security.rst b/doc/03_reference/security.rst index c52de535e4..219f9f16ae 100644 --- a/doc/03_reference/security.rst +++ b/doc/03_reference/security.rst @@ -50,6 +50,7 @@ The frequency of injected instructions can be tuned via the **dummy_instr_mask** Other values of **dummy_instr_mask** are legal, but will have a less predictable impact. The interval between instruction insertion is randomized in the core using an LFSR. +The initial seed and output permutation for this LFSR can be set using parameters from the top-level of Ibex. Sofware can periodically re-seed this LFSR with true random numbers (if available) via the **secureseed** CSR. This will make the insertion interval of dummy instructions much harder for an attacker to predict. diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 6fd2de62b9..0b6aa77fce 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -32,6 +32,8 @@ module ibex_core import ibex_pkg::*; #( parameter bit DbgTriggerEn = 1'b0, parameter int unsigned DbgHwBreakNum = 1, parameter bit ResetAll = 1'b0, + parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, + parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, parameter bit SecureIbex = 1'b0, parameter bit DummyInstructions = 1'b0, parameter bit RegFileECC = 1'b0, @@ -398,6 +400,8 @@ module ibex_core import ibex_pkg::*; #( .LineSizeECC ( LineSizeECC ), .PCIncrCheck ( PCIncrCheck ), .ResetAll ( ResetAll ), + .RndCnstLfsrSeed ( RndCnstLfsrSeed ), + .RndCnstLfsrPerm ( RndCnstLfsrPerm ), .BranchPredictor ( BranchPredictor ) ) if_stage_i ( .clk_i ( clk_i ), diff --git a/rtl/ibex_dummy_instr.sv b/rtl/ibex_dummy_instr.sv index 99b75b6509..cae665a85b 100644 --- a/rtl/ibex_dummy_instr.sv +++ b/rtl/ibex_dummy_instr.sv @@ -8,7 +8,10 @@ * Provides pseudo-randomly inserted fake instructions for secure code obfuscation */ -module ibex_dummy_instr ( +module ibex_dummy_instr import ibex_pkg::*; #( + parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, + parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault +) ( // Clock and reset input logic clk_i, input logic rst_ni, @@ -70,8 +73,11 @@ module ibex_dummy_instr ( end prim_lfsr #( - .LfsrDw ( 32 ), - .StateOutDw ( LFSR_OUT_W ) + .LfsrDw ( LfsrWidth ), + .StateOutDw ( LFSR_OUT_W ), + .DefaultSeed ( RndCnstLfsrSeed ), + .StatePermEn ( 1'b1 ), + .StatePerm ( RndCnstLfsrPerm ) ) lfsr_i ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/rtl/ibex_if_stage.sv b/rtl/ibex_if_stage.sv index 29c32c703e..abd09af76e 100644 --- a/rtl/ibex_if_stage.sv +++ b/rtl/ibex_if_stage.sv @@ -23,6 +23,8 @@ module ibex_if_stage import ibex_pkg::*; #( parameter int unsigned LineSizeECC = IC_LINE_SIZE, parameter bit PCIncrCheck = 1'b0, parameter bit ResetAll = 1'b0, + parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, + parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, parameter bit BranchPredictor = 1'b0 ) ( input logic clk_i, @@ -330,7 +332,10 @@ module ibex_if_stage import ibex_pkg::*; #( logic insert_dummy_instr; logic [31:0] dummy_instr_data; - ibex_dummy_instr dummy_instr_i ( + ibex_dummy_instr #( + .RndCnstLfsrSeed (RndCnstLfsrSeed), + .RndCnstLfsrPerm (RndCnstLfsrPerm) + ) dummy_instr_i ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .dummy_instr_en_i ( dummy_instr_en_i ), diff --git a/rtl/ibex_lockstep.sv b/rtl/ibex_lockstep.sv index ed9e19902a..0c962a3ebf 100644 --- a/rtl/ibex_lockstep.sv +++ b/rtl/ibex_lockstep.sv @@ -27,6 +27,8 @@ module ibex_lockstep import ibex_pkg::*; #( parameter bit DbgTriggerEn = 1'b0, parameter int unsigned DbgHwBreakNum = 1, parameter bit ResetAll = 1'b0, + parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, + parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, parameter bit SecureIbex = 1'b0, parameter bit DummyInstructions = 1'b0, parameter bit RegFileECC = 1'b0, @@ -292,6 +294,8 @@ module ibex_lockstep import ibex_pkg::*; #( .DbgHwBreakNum ( DbgHwBreakNum ), .WritebackStage ( WritebackStage ), .ResetAll ( ResetAll ), + .RndCnstLfsrSeed ( RndCnstLfsrSeed ), + .RndCnstLfsrPerm ( RndCnstLfsrPerm ), .SecureIbex ( SecureIbex ), .DummyInstructions ( DummyInstructions ), .RegFileECC ( RegFileECC ), diff --git a/rtl/ibex_pkg.sv b/rtl/ibex_pkg.sv index bc4a85158d..c1a7bc67b3 100644 --- a/rtl/ibex_pkg.sv +++ b/rtl/ibex_pkg.sv @@ -558,4 +558,14 @@ parameter int unsigned CSR_MSECCFG_MML_BIT = 0; parameter int unsigned CSR_MSECCFG_MMWP_BIT = 1; parameter int unsigned CSR_MSECCFG_RLB_BIT = 2; +// These LFSR parameters have been generated with +// $ opentitan/util/design/gen-lfsr-seed.py --width 32 --seed 2480124384 --prefix "" +parameter int LfsrWidth = 32; +typedef logic [LfsrWidth-1:0] lfsr_seed_t; +typedef logic [LfsrWidth-1:0][$clog2(LfsrWidth)-1:0] lfsr_perm_t; +parameter lfsr_seed_t RndCnstLfsrSeedDefault = 32'hac533bf4; +parameter lfsr_perm_t RndCnstLfsrPermDefault = { + 160'h1e35ecba467fd1b12e958152c04fa43878a8daed +}; + endpackage diff --git a/rtl/ibex_top.sv b/rtl/ibex_top.sv index 478e1ef3bb..bc6b4798bf 100644 --- a/rtl/ibex_top.sv +++ b/rtl/ibex_top.sv @@ -12,26 +12,28 @@ /** * Top level module of the ibex RISC-V core */ -module ibex_top #( - parameter bit PMPEnable = 1'b0, - parameter int unsigned PMPGranularity = 0, - parameter int unsigned PMPNumRegions = 4, - parameter int unsigned MHPMCounterNum = 0, - parameter int unsigned MHPMCounterWidth = 40, - parameter bit RV32E = 1'b0, - parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast, - parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone, - parameter ibex_pkg::regfile_e RegFile = ibex_pkg::RegFileFF, - parameter bit BranchTargetALU = 1'b0, - parameter bit WritebackStage = 1'b0, - parameter bit ICache = 1'b0, - parameter bit ICacheECC = 1'b0, - parameter bit BranchPredictor = 1'b0, - parameter bit DbgTriggerEn = 1'b0, - parameter int unsigned DbgHwBreakNum = 1, - parameter bit SecureIbex = 1'b0, - parameter int unsigned DmHaltAddr = 32'h1A110800, - parameter int unsigned DmExceptionAddr = 32'h1A110808 +module ibex_top import ibex_pkg::*; #( + parameter bit PMPEnable = 1'b0, + parameter int unsigned PMPGranularity = 0, + parameter int unsigned PMPNumRegions = 4, + parameter int unsigned MHPMCounterNum = 0, + parameter int unsigned MHPMCounterWidth = 40, + parameter bit RV32E = 1'b0, + parameter rv32m_e RV32M = RV32MFast, + parameter rv32b_e RV32B = RV32BNone, + parameter regfile_e RegFile = RegFileFF, + parameter bit BranchTargetALU = 1'b0, + parameter bit WritebackStage = 1'b0, + parameter bit ICache = 1'b0, + parameter bit ICacheECC = 1'b0, + parameter bit BranchPredictor = 1'b0, + parameter bit DbgTriggerEn = 1'b0, + parameter int unsigned DbgHwBreakNum = 1, + parameter bit SecureIbex = 1'b0, + parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, + parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, + parameter int unsigned DmHaltAddr = 32'h1A110800, + parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( // Clock and Reset input logic clk_i, @@ -71,7 +73,7 @@ module ibex_top #( // Debug Interface input logic debug_req_i, - output ibex_pkg::crash_dump_t crash_dump_o, + output crash_dump_t crash_dump_o, // RISC-V Formal Interface // Does not comply with the coding standards of _i/_o suffixes, but follows @@ -112,8 +114,6 @@ module ibex_top #( input logic scan_rst_ni ); - import ibex_pkg::*; - localparam bit Lockstep = SecureIbex; localparam bit ResetAll = Lockstep; localparam bit DummyInstructions = SecureIbex; @@ -199,6 +199,8 @@ module ibex_top #( .DbgHwBreakNum ( DbgHwBreakNum ), .WritebackStage ( WritebackStage ), .ResetAll ( ResetAll ), + .RndCnstLfsrSeed ( RndCnstLfsrSeed ), + .RndCnstLfsrPerm ( RndCnstLfsrPerm ), .SecureIbex ( SecureIbex ), .DummyInstructions ( DummyInstructions ), .RegFileECC ( RegFileECC ), @@ -648,6 +650,8 @@ module ibex_top #( .DbgHwBreakNum ( DbgHwBreakNum ), .WritebackStage ( WritebackStage ), .ResetAll ( ResetAll ), + .RndCnstLfsrSeed ( RndCnstLfsrSeed ), + .RndCnstLfsrPerm ( RndCnstLfsrPerm ), .SecureIbex ( SecureIbex ), .DummyInstructions ( DummyInstructions ), .RegFileECC ( RegFileECC ), diff --git a/rtl/ibex_top_tracing.sv b/rtl/ibex_top_tracing.sv index 06edeefb68..b253fa3989 100644 --- a/rtl/ibex_top_tracing.sv +++ b/rtl/ibex_top_tracing.sv @@ -6,26 +6,28 @@ * Top level module of the ibex RISC-V core with tracing enabled */ -module ibex_top_tracing #( - parameter bit PMPEnable = 1'b0, - parameter int unsigned PMPGranularity = 0, - parameter int unsigned PMPNumRegions = 4, - parameter int unsigned MHPMCounterNum = 0, - parameter int unsigned MHPMCounterWidth = 40, - parameter bit RV32E = 1'b0, - parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast, - parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone, - parameter ibex_pkg::regfile_e RegFile = ibex_pkg::RegFileFF, - parameter bit BranchTargetALU = 1'b0, - parameter bit WritebackStage = 1'b0, - parameter bit ICache = 1'b0, - parameter bit ICacheECC = 1'b0, - parameter bit BranchPredictor = 1'b0, - parameter bit DbgTriggerEn = 1'b0, - parameter int unsigned DbgHwBreakNum = 1, - parameter bit SecureIbex = 1'b0, - parameter int unsigned DmHaltAddr = 32'h1A110800, - parameter int unsigned DmExceptionAddr = 32'h1A110808 +module ibex_top_tracing import ibex_pkg::*; #( + parameter bit PMPEnable = 1'b0, + parameter int unsigned PMPGranularity = 0, + parameter int unsigned PMPNumRegions = 4, + parameter int unsigned MHPMCounterNum = 0, + parameter int unsigned MHPMCounterWidth = 40, + parameter bit RV32E = 1'b0, + parameter rv32m_e RV32M = RV32MFast, + parameter rv32b_e RV32B = RV32BNone, + parameter regfile_e RegFile = RegFileFF, + parameter bit BranchTargetALU = 1'b0, + parameter bit WritebackStage = 1'b0, + parameter bit ICache = 1'b0, + parameter bit ICacheECC = 1'b0, + parameter bit BranchPredictor = 1'b0, + parameter bit DbgTriggerEn = 1'b0, + parameter int unsigned DbgHwBreakNum = 1, + parameter bit SecureIbex = 1'b0, + parameter lfsr_seed_t RndCnstLfsrSeed = RndCnstLfsrSeedDefault, + parameter lfsr_perm_t RndCnstLfsrPerm = RndCnstLfsrPermDefault, + parameter int unsigned DmHaltAddr = 32'h1A110800, + parameter int unsigned DmExceptionAddr = 32'h1A110808 ) ( // Clock and Reset input logic clk_i, @@ -67,7 +69,7 @@ module ibex_top_tracing #( // Debug Interface input logic debug_req_i, - output ibex_pkg::crash_dump_t crash_dump_o, + output crash_dump_t crash_dump_o, // CPU Control Signals input logic fetch_enable_i, @@ -77,8 +79,6 @@ module ibex_top_tracing #( ); - import ibex_pkg::*; - // ibex_tracer relies on the signals from the RISC-V Formal Interface `ifndef RVFI $fatal("Fatal error: RVFI needs to be defined globally.");