Skip to content

Commit

Permalink
[sram_ctrl,dv] Add mubi FI test for prim_ram
Browse files Browse the repository at this point in the history
#23292 protected security-critical signals
within the prim_ram modules against FI by multi-bit encoding.
This commit adds a FI test that checks whether injecting
bit-flips into these signals trigger the expected alert.

Signed-off-by: Pascal Nasahl <[email protected]>
  • Loading branch information
nasahlpa committed Dec 9, 2024
1 parent 4994ba3 commit 59d9299
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 0 deletions.
3 changes: 3 additions & 0 deletions hw/ip/sram_ctrl/data/sram_ctrl.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@
{ name: "LC_HW_DEBUG_EN.INTERSIG.MUBI",
desc: "The life cycle hardware debug enable signal is multibit encoded."
}
{ name: "PRIM_RAM.CTRL.MUBI",
desc: "The control signals inside prim_ram are multibit encoded."
}
{ name: "MEM.INTEGRITY",
desc: "End-to-end data/memory integrity scheme."
}
Expand Down
10 changes: 10 additions & 0 deletions hw/ip/sram_ctrl/data/sram_ctrl_sec_cm_testplan.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@
stage: V2S
tests: ["{name}_lc_escalation"]
}
{
name: sec_cm_prim_ram_ctrl_mubi
desc: '''Verify the countermeasure(s) PRIM_RAM.CTRL.MUBI.

Injects bit-flips into multibit encoded control signals inside the
prim_ram modules.
'''
stage: V2S
tests: ["{name}_mubi_enc_err"]
}
{
name: sec_cm_mem_integrity
desc: "Verify the countermeasure(s) MEM.INTEGRITY."
Expand Down
1 change: 1 addition & 0 deletions hw/ip/sram_ctrl/doc/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Referring to the [Comportable guideline for peripheral device functionality](htt
| SRAM_CTRL.EXEC.INTERSIG.MUBI | The SRAM execution enable signal coming from OTP is multibit encoded. |
| SRAM_CTRL.LC_ESCALATE_EN.INTERSIG.MUBI | The life cycle escalation enable signal is multibit encoded. |
| SRAM_CTRL.LC_HW_DEBUG_EN.INTERSIG.MUBI | The life cycle hardware debug enable signal is multibit encoded. |
| SRAM_CTRL.PRIM_RAM.CTRL.MUBI | The control signals inside prim_ram are multibit encoded. |
| SRAM_CTRL.MEM.INTEGRITY | End-to-end data/memory integrity scheme. |
| SRAM_CTRL.MEM.READBACK | Each read and write is checked with a readback. |
| SRAM_CTRL.MEM.SCRAMBLE | Data is scrambled with a keyed reduced-round PRINCE cipher in CTR mode. |
Expand Down
145 changes: 145 additions & 0 deletions hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_mubi_enc_err_vseq.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// mubi_enc_err_vseq
class sram_ctrl_mubi_enc_err_vseq extends sram_ctrl_base_vseq;
`uvm_object_utils(sram_ctrl_mubi_enc_err_vseq)

`uvm_object_new

// Indicates the number of memory accesses to be performed in this test.
rand int num_ops;

// Indicates at which memory access the fault is injected.
rand int fi_op_idx;

constraint num_ops_c {
num_ops inside {[10 : 200]};
}

constraint fi_op_idx_c {
fi_op_idx inside {[1 : num_ops - 1]};
}

int fi_iteration_position = 0;

task wait_for_signal(string path);
// Wait until the signal is 1.
bit req = 1'b0;
`DV_SPINWAIT(
do begin
cfg.clk_rst_vif.wait_n_clks(1);
`DV_CHECK_FATAL(uvm_hdl_read(path, req));
end while(!req);
)
endtask

task drive_reqs(int iterations, bit write);
// Perform random read/write operations.
bit [TL_AW-1:0] sram_addr_mask = cfg.ral_models[cfg.sram_ral_name].get_addr_mask();
bit [TL_AW-1:0] max_offset = {sram_addr_mask[TL_AW-1:2], 2'd0};
logic [TL_DW-1:0] rdata;
for (int iteration = 0; iteration < iterations; iteration++) begin
bit [TL_AW-1:0] addr;
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(addr, (addr & sram_addr_mask) < max_offset;)
if (write) begin
do_single_write(.addr(addr), .data(iteration), .mask('1), .blocking(0));
end else begin
do_single_read(.addr(addr), .mask('1), .check_rdata(0), .blocking(0), .rdata(rdata));
end
end
endtask

task inject_fault(int iterations, int iteration_fi_position, string fi_path,
string sram_req_path, string sram_we_path, bit write_op,
string alert_signal);
// Inject a fault into the signal indicated by fi_path & monitor the response.
int value;
int value_faulty;
int fault_bit_pos;
// Sanity check fault position is within the number of iterations.
`DV_CHECK_LT_FATAL(iteration_fi_position, iterations)
for (int iteration = 0; iteration < iteration_fi_position; iteration++) begin
// Wait until the sram_we (for writes) or the sram_req (for reads) arrives.
if (write_op) begin
wait_for_signal(sram_we_path);
end else begin
wait_for_signal(sram_req_path);
end
end

// We have reached the transaction we were waiting for, start injecting
// the fault.
`uvm_info(`gfn, $sformatf(
"Injecting fault into %s in memory operation %d and check the %s alert",
fi_path, iteration_fi_position, alert_signal),
UVM_LOW)
// Configure which alert we are expecting.
cfg.scb.set_exp_alert(alert_signal, .is_fatal(1'b1), .max_delay(20));
fork
begin : inject_fault
`DV_CHECK_FATAL(uvm_hdl_read(fi_path, value));
fault_bit_pos = $urandom_range(1, 4);
value_faulty = value ^ fault_bit_pos;
`DV_CHECK_FATAL(uvm_hdl_force(fi_path, value_faulty))
// Release the faulty signal after one clock cycle.
cfg.clk_rst_vif.wait_n_clks(1);
`DV_CHECK_FATAL(uvm_hdl_release(fi_path))
end : inject_fault
begin : monitor_response
// Check if alert_signal was triggered.
wait_alert_trigger (alert_signal, .max_wait_cycle(20), .wait_complete(0));
end : monitor_response
join
// Reset to get the DUT out of terminal state.
apply_resets_concurrently();
endtask

task body();
// Define the signal we are targeting to inject a fault. This list covers
// critical signals within the prim_ram macro that are multi-bit encoded
// and should trigger an alert when detecting an invalid encoding.
string fi_paths[8] = {"tb.dut.u_prim_ram_1p_scr.write_en_q",
"tb.dut.u_prim_ram_1p_scr.addr_collision_q",
"tb.dut.u_prim_ram_1p_scr.write_pending_q",
"tb.dut.u_prim_ram_1p_scr.rvalid_q",
"tb.dut.u_prim_ram_1p_scr.u_prim_ram_1p_adv.req_q",
"tb.dut.u_prim_ram_1p_scr.u_prim_ram_1p_adv.write_q",
"tb.dut.u_prim_ram_1p_scr.u_prim_ram_1p_adv.rvalid_q",
"tb.dut.u_prim_ram_1p_scr.u_prim_ram_1p_adv.rvalid_sram_q"};
// These variables hold the randomly selected target signal.
string fi_path;
// Used to keep track of the incoming TL-UL requests.
string sram_req_path = "tb.dut.sram_req";
string sram_we_path = "tb.dut.sram_we";
// The multi-bit encoding raises the fatal_error alert on a mismatch.
string alert_signal = "fatal_error";
// Are we targeting a read or write operation?
bit target_write = $urandom_range(0, 1);

// Disable certain checks for FI.
cfg.is_fi_test = 1'b1;

// Turn off tlul_adapter_sram assertions as we are messing around with some
// signals that would trigger an assertion.
$assertoff(0, "tb.dut.u_tlul_adapter_sram");

// Request memory init.
req_mem_init();

// Set the target FI path randomly.
fi_path = fi_paths[$urandom_range(0, 7)];

// Start the parallel threads.
fork
// Driver task.
drive_reqs(num_ops, target_write);

// Fault injector task.
inject_fault(num_ops, fi_op_idx, fi_path, sram_req_path,
sram_we_path, target_write, alert_signal);
join
endtask : body

endclass : sram_ctrl_mubi_enc_err_vseq
1 change: 1 addition & 0 deletions hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_vseq_list.sv
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
`include "sram_ctrl_ram_cfg_vseq.sv"
`include "sram_ctrl_stress_all_vseq.sv"
`include "sram_ctrl_readback_err_vseq.sv"
`include "sram_ctrl_mubi_enc_err_vseq.sv"
1 change: 1 addition & 0 deletions hw/ip/sram_ctrl/dv/env/sram_ctrl_env.core
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ filesets:
- seq_lib/sram_ctrl_ram_cfg_vseq.sv: {is_include_file: true}
- seq_lib/sram_ctrl_stress_all_vseq.sv: {is_include_file: true}
- seq_lib/sram_ctrl_readback_err_vseq.sv: {is_include_file: true}
- seq_lib/sram_ctrl_mubi_enc_err_vseq.sv: {is_include_file: true}
file_type: systemVerilogSource

generate:
Expand Down
4 changes: 4 additions & 0 deletions hw/ip/sram_ctrl/dv/sram_ctrl_base_sim_cfg.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@
name: "{name}_readback_err"
uvm_test_seq: sram_ctrl_readback_err_vseq
}
{
name: "{name}_mubi_enc_err"
uvm_test_seq: sram_ctrl_mubi_enc_err_vseq
}
]

// List of regressions.
Expand Down

0 comments on commit 59d9299

Please sign in to comment.