Skip to content

Commit

Permalink
[sram_ctrl,dv] Add sec_cm_mem_readback test
Browse files Browse the repository at this point in the history
This commit provides a new sec_cm_readback test that tests the
SRAM readback FI countermeasure. In the test, a fault is injected
during one of the read/write SRAM requests. The test checks, whether
the expected alert fires.

Closes #23322.

Signed-off-by: Pascal Nasahl <[email protected]>
  • Loading branch information
nasahlpa committed Sep 30, 2024
1 parent 718bfa6 commit b4be0db
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 9 deletions.
18 changes: 14 additions & 4 deletions hw/dv/sv/mem_bkdr_scb/mem_bkdr_scb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,19 @@ virtual class mem_bkdr_scb #(int AddrWidth = bus_params_pkg::BUS_AW,
function void read_finish(mem_data_t act_data,
mem_addr_t addr = 0,
mem_mask_t mask = '1,
bit en_check_consistency = 1);
bit en_check_consistency = 1,
bit en_check_exp = 1);
mem_item_t exp_item;
`DV_CHECK_NE(read_item_q.size, 0)
exp_item = read_item_q.pop_front();
act_data &= expand_bit_mask(mask);

if (en_check_consistency) check_item_consistency(exp_item, addr, mask);
`DV_CHECK_EQ(act_data, exp_item.data, $sformatf("addr 0x%0h read out mismatch", exp_item.addr))

if (en_check_exp) begin
`DV_CHECK_EQ(act_data, exp_item.data,
$sformatf("addr 0x%0h read out mismatch", exp_item.addr))
end

`uvm_info(`gfn, $sformatf("read_finish: Addr[0x%0h], data[0x%0h], Mask[0x%0h]",
exp_item.addr, act_data, exp_item.mask), UVM_MEDIUM)
Expand All @@ -148,7 +153,8 @@ virtual class mem_bkdr_scb #(int AddrWidth = bus_params_pkg::BUS_AW,
// write_item_q
function void write_finish(mem_addr_t addr = 0,
mem_mask_t mask = '1,
bit en_check_consistency = 1);
bit en_check_consistency = 1,
bit en_check_exp = 1);
mem_data_t act_data, exp_data;
mem_data_t bit_mask;
mem_item_t exp_item;
Expand All @@ -160,7 +166,11 @@ virtual class mem_bkdr_scb #(int AddrWidth = bus_params_pkg::BUS_AW,

act_data = get_bkdr_val(exp_item.addr) & bit_mask;
exp_data = exp_item.data & bit_mask;
`DV_CHECK_EQ(act_data, exp_data, $sformatf("addr 0x%0h write mismatch", exp_item.addr))

if (en_check_exp) begin
`DV_CHECK_EQ(act_data, exp_data,
$sformatf("addr 0x%0h write mismatch", exp_item.addr))
end

`uvm_info(`gfn, $sformatf("write_finish: Addr[0x%0h], data[0x%0h], Mask[0x%0h]",
exp_item.addr, act_data, exp_item.mask), UVM_MEDIUM)
Expand Down
5 changes: 3 additions & 2 deletions hw/ip/sram_ctrl/data/sram_ctrl_sec_cm_testplan.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,11 @@
name: sec_cm_mem_readback
desc: '''Verify the countermeasure(s) MEM.READBACK.

Test needs to be implemented, see lowRISC/opentitan#23322.
Injects bit-flips during memory reads/writes and checks whether
an error is triggered.
'''
stage: V2S
tests: ["{name}_smoke"]
tests: ["{name}_readback_err"]
}
{
name: sec_cm_mem_scramble
Expand Down
4 changes: 3 additions & 1 deletion hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_base_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ class sram_ctrl_base_vseq #(parameter int AddrWidth = `SRAM_ADDR_WIDTH) extends
readback_running = 1;
if (uvm_re_match("*throughput*", get_type_name()) &&
uvm_re_match("*sec_cm*", get_type_name()) &&
uvm_re_match("*readback_err*", get_type_name()) &&
uvm_re_match("*throughput*", common_seq_type) &&
uvm_re_match("*sec_cm*", common_seq_type)) begin
uvm_re_match("*sec_cm*", common_seq_type) &&
uvm_re_match("*readback_err*", common_seq_type)) begin
// Configure the SRAM TLUL agent to wait at least 2 cycles before dropping
// a request.
cfg.m_tl_agent_cfgs[cfg.sram_ral_name].a_valid_len_min = 2;
Expand Down
139 changes: 139 additions & 0 deletions hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_readback_err_vseq.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// readback_err_vseq
class sram_ctrl_readback_err_vseq extends sram_ctrl_base_vseq;
`uvm_object_utils(sram_ctrl_readback_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 do_fi_op;

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

constraint do_fi_op_c {
do_fi_op inside {[10 : num_ops]};
}

int fi_iteration_position = 0;

task drive_reqs(int iterations);
// Perform random read/write operations.
bit [TL_AW-1:0] addr;
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 write = $urandom_range(0, 1);
`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 tlul_req_path);
// Inject a fault into the signal indicated by fi_path.
bit req;
for (int iteration = 0; iteration < iterations; iteration++) begin
// Wait until the TL-UL request arrives in the SRAM module.
`DV_SPINWAIT(
do begin
#1ps;
uvm_hdl_read(tlul_req_path, req);
end while(!req);
)

// Check if it is time to inject a fault.
if (iteration == iteration_fi_position) begin
`uvm_info(`gfn, $sformatf(
"Injecting fault into %s in memory operation %d",
fi_path, iteration_fi_position),
UVM_LOW)
`DV_CHECK(uvm_hdl_force(fi_path, 'hbeef))
// Release the faulty signal after one clock cycle.
cfg.clk_rst_vif.wait_clks(1);
`DV_CHECK(uvm_hdl_release(fi_path))
end
cfg.clk_rst_vif.wait_clks(1);
end
endtask

task monitor_response(int iterations, int iteration_fi_position, string alert_signal,
string tlul_req_path);
// Monitor whether the alert_signal was triggered.
bit req;
for (int iteration = 0; iteration < iterations; iteration++) begin
// Wait until the TL-UL request arrives in the SRAM module.
`DV_SPINWAIT(
do begin
#1ps;
uvm_hdl_read(tlul_req_path, req);
end while(!req);
)
// Check if it is time to monitor the response.
if (iteration == iteration_fi_position) begin
`uvm_info(`gfn, $sformatf("Checking the %s alert", alert_signal), UVM_LOW)
// Check if alert_signal was triggered.
cfg.scb.set_exp_alert(alert_signal, .is_fatal(1'b1), .max_delay(20));
wait_alert_trigger (alert_signal, .max_wait_cycle(20), .wait_complete(0));
// Reset to get the DUT out of terminal state.
apply_resets_concurrently();
end
cfg.clk_rst_vif.wait_clks(1);
end
endtask

task body();
// Used as a FI target.
// TODO: add list of signals instead of using a single signal. Currently only
// the read or write address is faulted.
string fi_path = "tb.dut.sram_addr";
// Used to keep track of the incoming TL-UL requests.
string tlul_req_path = "tb.dut.ram_tl_i.a_valid";
// The readback feature raises the fatal_error alert on a mismatch.
string alert_signal = "fatal_error";

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

`DV_CHECK_MEMBER_RANDOMIZE_FATAL(num_ops)
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(do_fi_op)

// Request memory init & enable SRAM readback feature.
req_mem_init();
csr_wr(.ptr(ral.readback), .value(MuBi4True));

// Sanity check some static paths we use in this test.
`DV_CHECK(uvm_hdl_check_path(fi_path),
$sformatf("Hierarchical path %0s appears to be invalid.", fi_path))
`DV_CHECK(uvm_hdl_check_path(tlul_req_path),
$sformatf("Hierarchical path %0s appears to be invalid.", tlul_req_path))

// As we have at least 10 memory requests, correct the offset.
fi_iteration_position = do_fi_op - 10;

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

// Fault injector task.
inject_fault(num_ops, fi_iteration_position, fi_path, tlul_req_path);

// Monitoring task.
monitor_response(num_ops, fi_iteration_position, alert_signal, tlul_req_path);
join_any
endtask : body

endclass : sram_ctrl_readback_err_vseq
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 @@ -36,6 +36,7 @@ filesets:
- seq_lib/sram_ctrl_regwen_vseq.sv: {is_include_file: true}
- 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}
file_type: systemVerilogSource

generate:
Expand Down
3 changes: 3 additions & 0 deletions hw/ip/sram_ctrl/dv/env/sram_ctrl_env_cfg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class sram_ctrl_env_cfg #(parameter int AddrWidth = 10)
// This tracks when the ram is undergoing initialization in the scoreboard.
bit in_init = 1'b0;

// Disables certain checks for FI tests.
bit is_fi_test = 1'b0;

// ext component cfgs
rand push_pull_agent_cfg#(.DeviceDataWidth(KDI_DATA_SIZE)) m_kdi_cfg;

Expand Down
5 changes: 3 additions & 2 deletions hw/ip/sram_ctrl/dv/env/sram_ctrl_scoreboard.sv
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ class sram_ctrl_scoreboard #(parameter int AddrWidth = 10) extends cip_base_scor
cfg.clk_rst_vif.wait_clks(1);
#1ps;

mem_bkdr_scb.write_finish(decrypt_addr, item.mask);
mem_bkdr_scb.write_finish(decrypt_addr, item.mask, !cfg.is_fi_test, !cfg.is_fi_test);
`uvm_info(`gfn, $sformatf("Currently num of pending write items is %0d", write_item_q.size),
UVM_MEDIUM)
end
Expand Down Expand Up @@ -442,7 +442,8 @@ class sram_ctrl_scoreboard #(parameter int AddrWidth = 10) extends cip_base_scor
`DV_CHECK_EQ(cfg.in_init, 0, "No item is accepted during init")

if (status_lc_esc == EscNone && !item.is_write()) begin
mem_bkdr_scb.read_finish(item.d_data, simplify_addr(item.a_addr), item.a_mask);
mem_bkdr_scb.read_finish(item.d_data, simplify_addr(item.a_addr),
item.a_mask, !cfg.is_fi_test, !cfg.is_fi_test);
end
endtask

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 @@ -142,6 +142,10 @@
uvm_test_seq: "{name}_common_vseq"
run_opts: ["+run_mem_partial_access"]
}
{
name: "{name}_readback_err"
uvm_test_seq: sram_ctrl_readback_err_vseq
}
]

// List of regressions.
Expand Down

0 comments on commit b4be0db

Please sign in to comment.