[rtl] Switch to multi-bit fetch enable

The multi-bit enable aids security hardening. For non secure Ibex all
but the bottom bit is ignored so it is effectively a single bit enable.
This commit is contained in:
Greg Chadwick 2022-02-17 18:39:07 +00:00 committed by Greg Chadwick
parent 3475b9106c
commit b18eceba81
11 changed files with 111 additions and 72 deletions

View file

@ -208,9 +208,12 @@ Interfaces
+----------------------------+------------------------------------------------------------------------+
| ``double_fault_seen_o`` | A double fault was observed, see :ref:`double-fault-detect` |
+----------------------------+-------------------------+-----+----------------------------------------+
| ``fetch_enable_i`` | 1 | in | Allow the core to fetch instructions. |
| ``fetch_enable_i`` | 4 | in | Allow the core to fetch instructions. |
| | | | If this bit is set low, the core will |
| | | | pause fetching new instructions. |
| | | | pause fetching new instructions. A |
| | | | multi-bit encoding scheme is used. See |
| | | | `FetchEnableOn` / `FetchEnableOff` in |
| | | | :file:`rtl/ibex_pkg.sv` |
+----------------------------+-------------------------+-----+----------------------------------------+
| ``core_sleep_o`` | 1 | out | Core in WFI with no outstanding data |
| | | | or instruction accesses. Deasserts |

View file

@ -131,57 +131,57 @@ module ibex_riscv_compliance (
.DmHaltAddr (32'h00000000 ),
.DmExceptionAddr (32'h00000000 )
) u_top (
.clk_i (clk_sys ),
.rst_ni (rst_sys_n ),
.clk_i (clk_sys ),
.rst_ni (rst_sys_n ),
.test_en_i ('b0 ),
.scan_rst_ni (1'b1 ),
.ram_cfg_i ('b0 ),
.test_en_i ('b0 ),
.scan_rst_ni (1'b1 ),
.ram_cfg_i ('b0 ),
.hart_id_i (32'b0 ),
.hart_id_i (32'b0 ),
// First instruction executed is at 0x0 + 0x80
.boot_addr_i (32'h00000000 ),
.boot_addr_i (32'h00000000 ),
.instr_req_o (host_req[CoreI] ),
.instr_gnt_i (host_gnt[CoreI] ),
.instr_rvalid_i (host_rvalid[CoreI]),
.instr_addr_o (host_addr[CoreI] ),
.instr_rdata_i (host_rdata[CoreI] ),
.instr_rdata_intg_i ('0 ),
.instr_err_i (host_err[CoreI] ),
.instr_req_o (host_req[CoreI] ),
.instr_gnt_i (host_gnt[CoreI] ),
.instr_rvalid_i (host_rvalid[CoreI] ),
.instr_addr_o (host_addr[CoreI] ),
.instr_rdata_i (host_rdata[CoreI] ),
.instr_rdata_intg_i ('0 ),
.instr_err_i (host_err[CoreI] ),
.data_req_o (host_req[CoreD] ),
.data_gnt_i (host_gnt[CoreD] ),
.data_rvalid_i (host_rvalid[CoreD]),
.data_we_o (host_we[CoreD] ),
.data_be_o (host_be[CoreD] ),
.data_addr_o (host_addr[CoreD] ),
.data_wdata_o (host_wdata[CoreD] ),
.data_wdata_intg_o ( ),
.data_rdata_i (host_rdata[CoreD] ),
.data_rdata_intg_i ('0 ),
.data_err_i (host_err[CoreD] ),
.data_req_o (host_req[CoreD] ),
.data_gnt_i (host_gnt[CoreD] ),
.data_rvalid_i (host_rvalid[CoreD] ),
.data_we_o (host_we[CoreD] ),
.data_be_o (host_be[CoreD] ),
.data_addr_o (host_addr[CoreD] ),
.data_wdata_o (host_wdata[CoreD] ),
.data_wdata_intg_o ( ),
.data_rdata_i (host_rdata[CoreD] ),
.data_rdata_intg_i ('0 ),
.data_err_i (host_err[CoreD] ),
.irq_software_i (1'b0 ),
.irq_timer_i (1'b0 ),
.irq_external_i (1'b0 ),
.irq_fast_i (15'b0 ),
.irq_nm_i (1'b0 ),
.irq_software_i (1'b0 ),
.irq_timer_i (1'b0 ),
.irq_external_i (1'b0 ),
.irq_fast_i (15'b0 ),
.irq_nm_i (1'b0 ),
.scramble_key_valid_i ('0 ),
.scramble_key_i ('0 ),
.scramble_nonce_i ('0 ),
.scramble_req_o ( ),
.scramble_key_valid_i ('0 ),
.scramble_key_i ('0 ),
.scramble_nonce_i ('0 ),
.scramble_req_o ( ),
.debug_req_i ('b0 ),
.crash_dump_o ( ),
.double_fault_seen_o ( ),
.debug_req_i ('b0 ),
.crash_dump_o ( ),
.double_fault_seen_o ( ),
.fetch_enable_i ('b1 ),
.alert_minor_o ( ),
.alert_major_internal_o ( ),
.alert_major_bus_o ( ),
.core_sleep_o ( )
.fetch_enable_i (ibex_pkg::FetchEnableOn),
.alert_minor_o ( ),
.alert_major_internal_o ( ),
.alert_major_bus_o ( ),
.core_sleep_o ( )
);
// SRAM block for instruction and data storage

View file

@ -4,20 +4,20 @@
// Interface to probe DUT internal signal
interface core_ibex_dut_probe_if(input logic clk);
logic reset;
logic illegal_instr;
logic ecall;
logic wfi;
logic ebreak;
logic dret;
logic mret;
logic fetch_enable;
logic core_sleep;
logic alert_minor;
logic alert_major_internal;
logic alert_major_bus;
logic debug_req;
ibex_pkg::priv_lvl_e priv_mode;
logic reset;
logic illegal_instr;
logic ecall;
logic wfi;
logic ebreak;
logic dret;
logic mret;
ibex_pkg::fetch_enable_t fetch_enable;
logic core_sleep;
logic alert_minor;
logic alert_major_internal;
logic alert_major_bus;
logic debug_req;
ibex_pkg::priv_lvl_e priv_mode;
clocking dut_cb @(posedge clk);
output fetch_enable;

View file

@ -132,10 +132,10 @@ class core_ibex_base_test extends uvm_test;
enable_irq_seq = cfg.enable_irq_single_seq || cfg.enable_irq_multiple_seq;
phase.raise_objection(this);
cur_run_phase = phase;
dut_vif.dut_cb.fetch_enable <= 1'b0;
dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOff;
clk_vif.wait_clks(100);
load_binary_to_mem();
dut_vif.dut_cb.fetch_enable <= 1'b1;
dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOn;
send_stimulus();
wait_for_test_done();
cur_run_phase = null;
@ -194,7 +194,7 @@ class core_ibex_base_test extends uvm_test;
check_perf_stats();
// De-assert fetch enable to finish the test
clk_vif.wait_clks(10);
dut_vif.dut_cb.fetch_enable <= 1'b0;
dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOff;
end
// Wait some time for the remaining instruction to finish
clk_vif.wait_clks(3000);

View file

@ -47,7 +47,7 @@ class core_ibex_reset_test extends core_ibex_base_test;
clk_vif.wait_clks($urandom_range(0, 50000));
fork
begin
dut_vif.dut_cb.fetch_enable <= 1'b0;
dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOff;
clk_vif.apply_reset(.reset_width_clks (100));
end
begin
@ -61,7 +61,7 @@ class core_ibex_reset_test extends core_ibex_base_test;
end
join
// Assert fetch_enable to have the core start executing from boot address
dut_vif.dut_cb.fetch_enable <= 1'b1;
dut_vif.dut_cb.fetch_enable <= ibex_pkg::FetchEnableOn;
end
endtask

View file

@ -227,7 +227,7 @@ module ibex_simple_system (
.crash_dump_o (),
.double_fault_seen_o (),
.fetch_enable_i ('b1),
.fetch_enable_i (ibex_pkg::FetchEnableOn),
.alert_minor_o (),
.alert_major_internal_o (),
.alert_major_bus_o (),

View file

@ -137,7 +137,7 @@ module ibex_core import ibex_pkg::*; #(
`endif
// CPU Control Signals
input logic fetch_enable_i,
input fetch_enable_t fetch_enable_i,
output logic alert_minor_o,
output logic alert_major_o,
output logic icache_inval_o,
@ -450,8 +450,25 @@ module ibex_core import ibex_pkg::*; #(
// available
assign perf_iside_wait = id_in_ready & ~instr_valid_id;
// Multi-bit fetch enable used when SecureIbex == 1. When SecureIbex == 0 only use the bottom-bit
// of fetch_enable_i. Ensure the multi-bit encoding has the bottom bit set for on and unset for
// off so FetchEnableOn/FetchEnableOff can be used without needing to know the value of
// SecureIbex.
`ASSERT_INIT(FetchEnableSecureOnBottomBitSet, FetchEnableOn[0] == 1'b1)
`ASSERT_INIT(FetchEnableSecureOffBottomBitClear, FetchEnableOff[0] == 1'b0)
// fetch_enable_i can be used to stop the core fetching new instructions
assign instr_req_gated = instr_req_int & fetch_enable_i;
if (SecureIbex) begin : g_instr_req_gated_secure
// For secure Ibex fetch_enable_i must be a specific multi-bit pattern to enable instruction
// fetch
assign instr_req_gated = instr_req_int & (fetch_enable_i == FetchEnableOn);
end else begin : g_instr_req_gated_non_secure
// For non secure Ibex only the bottom bit of fetch enable is considered
logic unused_fetch_enable;
assign unused_fetch_enable = ^fetch_enable_i[$bits(fetch_enable_t)-1:1];
assign instr_req_gated = instr_req_int & fetch_enable_i[0];
end
//////////////
// ID stage //

View file

@ -94,7 +94,7 @@ module ibex_lockstep import ibex_pkg::*; #(
input crash_dump_t crash_dump_i,
input logic double_fault_seen_i,
input logic fetch_enable_i,
input fetch_enable_t fetch_enable_i,
output logic alert_minor_o,
output logic alert_major_internal_o,
output logic alert_major_bus_o,
@ -182,7 +182,7 @@ module ibex_lockstep import ibex_pkg::*; #(
logic [14:0] irq_fast;
logic irq_nm;
logic debug_req;
logic fetch_enable;
fetch_enable_t fetch_enable;
logic ic_scr_key_valid;
} delayed_inputs_t;

View file

@ -606,4 +606,15 @@ package ibex_pkg;
128'h14e8cecae3040d5e12286bb3cc113298;
parameter logic [SCRAMBLE_NONCE_W-1:0] RndCnstIbexNonceDefault =
64'hf79780bc735f3843;
// Fetch enable. Mult-bit signal used for security hardening. For non-secure implementation all
// bits other than the bottom bit are ignored.
typedef logic [3:0] fetch_enable_t;
// Note that if adjusting these parameters it is assumed the bottom bit is set for On and unset
// for Off. This allows the use of FetchEnableOn/FetchEnableOff to work for both secure and
// non-secure Ibex. If this assumption is broken the RTL that uses the fetch_enable signal within
// `ibex_core` may need adjusting.
parameter fetch_enable_t FetchEnableOn = 4'b1001;
parameter fetch_enable_t FetchEnableOff = 4'b0110;
endpackage

View file

@ -123,7 +123,7 @@ module ibex_top import ibex_pkg::*; #(
`endif
// CPU Control Signals
input logic fetch_enable_i,
input fetch_enable_t fetch_enable_i,
output logic alert_minor_o,
output logic alert_major_internal_o,
output logic alert_major_bus_o,
@ -182,6 +182,8 @@ module ibex_top import ibex_pkg::*; #(
logic scramble_key_valid_d, scramble_key_valid_q;
logic scramble_req_d, scramble_req_q;
fetch_enable_t fetch_enable_buf;
/////////////////////
// Main clock gate //
/////////////////////
@ -208,6 +210,12 @@ module ibex_top import ibex_pkg::*; #(
// Core instantiation //
////////////////////////
// Buffer fetch_enable_i to prevent synthesis optimising away multi-bit signal
prim_buf #(.Width($bits(fetch_enable_t))) u_fetch_enable_buf (
.in_i (fetch_enable_i),
.out_o(fetch_enable_buf)
);
ibex_core #(
.PMPEnable (PMPEnable),
.PMPGranularity (PMPGranularity),
@ -322,7 +330,7 @@ module ibex_top import ibex_pkg::*; #(
.rvfi_ext_mcycle,
`endif
.fetch_enable_i,
.fetch_enable_i(fetch_enable_buf),
.alert_minor_o (core_alert_minor),
.alert_major_o (core_alert_major),
.icache_inval_o(icache_inval),
@ -656,7 +664,7 @@ module ibex_top import ibex_pkg::*; #(
logic debug_req_local;
crash_dump_t crash_dump_local;
logic double_fault_seen_local;
logic fetch_enable_local;
fetch_enable_t fetch_enable_local;
logic icache_inval_local;
logic core_busy_local;

View file

@ -83,7 +83,7 @@ module ibex_top_tracing import ibex_pkg::*; #(
output logic double_fault_seen_o,
// CPU Control Signals
input logic fetch_enable_i,
input fetch_enable_t fetch_enable_i,
output logic alert_minor_o,
output logic alert_major_internal_o,
output logic alert_major_bus_o,