[rtl] Add LFSR permutation option

Random constants are sent through the hierarchy as parameters in-line
with other OpenTitan modules.

Further detail on this mechanism can be found in lowrisc/opentitan#2229

Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
This commit is contained in:
Tom Roberts 2021-08-06 15:52:46 +01:00 committed by Tom Roberts
parent dbc2b6f5dc
commit 65bf9c94f9
9 changed files with 108 additions and 66 deletions

View file

@ -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 |

View file

@ -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.

View file

@ -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 ),

View file

@ -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 ),

View file

@ -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 ),

View file

@ -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 ),

View file

@ -559,4 +559,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

View file

@ -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 ),

View file

@ -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.");