Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lc_ctrl/top_earlgrey] Disable RAW unlock feature and additional DV checks #21320

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -746,10 +746,10 @@ class cip_base_vseq #(
// Wait a random number of cycles (up to reset_delay_bound) before triggering the reset.
cfg.clk_rst_vif.wait_clks(rand_reset_delay);

// If there is an outstanding access, wait up to 1000 more cycles to allow it to clear. If it
// If there is an outstanding access, wait up to 10000 more cycles to allow it to clear. If it
// doesn't clear, something has gone wrong: we don't expect there to permanently be CSR
// accesses.
for (int i = 0; i < 1000; i++) begin
for (int i = 0; i < 10000; i++) begin
if (!has_outstanding_access()) break;
cfg.clk_rst_vif.wait_clks(1);
end
Expand Down
4 changes: 2 additions & 2 deletions hw/ip/lc_ctrl/dv/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ It also updates the UVM register model.
## Building and running tests
We are using our in-house developed [regression tool](../../../../util/dvsim/README.md) for building and running our tests and regressions.
Please take a look at the link for detailed information on the usage, capabilities, features and known issues.
Here's how to run a smoke test:
Here's how to run a smoke test for the LC_CTRL variant with volatile RAW unlock disabled:
```console
$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/lc_ctrl/dv/lc_ctrl_sim_cfg.hjson -i lc_ctrl_smoke
$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/lc_ctrl/dv/lc_ctrl_volatile_unlock_disabled_sim.hjson -i lc_ctrl_smoke
```

## Testplan
Expand Down
7 changes: 6 additions & 1 deletion hw/ip/lc_ctrl/dv/env/lc_ctrl_scoreboard.sv
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@ class lc_ctrl_scoreboard extends cip_base_scoreboard #(
bit write = item.is_write();
uvm_reg_addr_t csr_addr = cfg.ral_models[ral_name].get_word_aligned_addr(item.a_addr);
lc_outputs_t exp = '{default: lc_ctrl_pkg::Off};

bit addr_phase_read = (!write && channel == AddrChannel);
bit addr_phase_write = (write && channel == AddrChannel);
bit data_phase_read = (!write && channel == DataChannel);
Expand All @@ -277,6 +276,12 @@ class lc_ctrl_scoreboard extends cip_base_scoreboard #(
else exp_clk_byp_req = lc_ctrl_pkg::Off;
end
end
// In case the volatile unlock feature is disabled, the register is hardwired to zero.
// Since the RAL models this as an RW register, we have to override that model here.
if (!`SEC_VOLATILE_RAW_UNLOCK_EN) begin
bit [DataWidth-1:0] mask = 'h2;
item.a_data &= ~mask;
end
end
default: begin
// Do nothing.
Expand Down
117 changes: 59 additions & 58 deletions hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_errors_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -355,75 +355,76 @@ class lc_ctrl_errors_vseq extends lc_ctrl_smoke_vseq;
cfg.set_test_phase(LcCtrlWaitTransition);
sw_transition_req(next_lc_state, token_val);
cfg.set_test_phase(LcCtrlTransitionComplete);
end else begin
cfg.set_test_phase(LcCtrlBadNextState);
// wait at least two clks for scb to finish checking lc outputs
cfg.clk_rst_vif.wait_clks($urandom_range(10, 2));
end
Copy link
Contributor Author

@msfschaffner msfschaffner Feb 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a big change, but what it really does is move this else leg towards the end of the test, so that either we perform a transition and do all the checking, or we skip the transition and go straight to the LcCtrlBadNextState phase.

// verilog_format: on

if (cfg.err_inj.token_mux_ctrl_redun_err || cfg.err_inj.token_mux_digest_err) begin
// Allow the FSM to get to a terminal state
wait(cfg.lc_ctrl_vif.lc_ctrl_fsm_state inside {PostTransSt, InvalidSt, EscalateSt});
disable token_mux_ctrl_err_inject;
disable token_mux_digest_err_inject;
end
// verilog_format: on

// Allow volatile registers to settle
cfg.clk_rst_vif.wait_clks($urandom_range(15, 10));
if (cfg.err_inj.token_mux_ctrl_redun_err || cfg.err_inj.token_mux_digest_err) begin
// Allow the FSM to get to a terminal state
wait(cfg.lc_ctrl_vif.lc_ctrl_fsm_state inside {PostTransSt, InvalidSt, EscalateSt});
disable token_mux_ctrl_err_inject;
disable token_mux_digest_err_inject;
end

cfg.set_test_phase(LcCtrlReadState1);
// Check count and state before escalate is generated
// Skip this if we are injecting clock bypass error responses as the KMAC
// may or may not respond leaving the FSM stuck in TokenHashSt
// Also Token Mux select error injection leads to unpredicable results
if (!err_inj.clk_byp_error_rsp && !err_inj.token_mux_ctrl_redun_err) begin
rd_lc_state_and_cnt_csrs();
end else begin
`uvm_info(`gfn, "Skipped read of lc state & lc_count because of error injection",
UVM_MEDIUM)
// Allow volatile registers to settle
cfg.clk_rst_vif.wait_clks($urandom_range(15, 10));
end

// Allow escalate to be generated if we have received an alert
cfg.set_test_phase(LcCtrlEscalate);
cfg.set_test_phase(LcCtrlReadState1);
// Check count and state before escalate is generated
// Skip this if we are injecting clock bypass error responses as the KMAC
// may or may not respond leaving the FSM stuck in TokenHashSt
// Also Token Mux select error injection leads to unpredicable results
if (!err_inj.clk_byp_error_rsp && !err_inj.token_mux_ctrl_redun_err) begin
rd_lc_state_and_cnt_csrs();
end else begin
`uvm_info(`gfn, "Skipped read of lc state & lc_count because of error injection",
UVM_MEDIUM)
cfg.clk_rst_vif.wait_clks($urandom_range(15, 10));
end

// Allow escalate to be generated if we have received an alert
cfg.set_test_phase(LcCtrlEscalate);

// Wait before re-checking lc_state to allow escalate to be accepted
cfg.clk_rst_vif.wait_clks($urandom_range(150, 100));
cfg.set_test_phase(LcCtrlReadState2);
// Check count and state after escalate is generated
// Skip if token mux select line error injection
if (!err_inj.token_mux_ctrl_redun_err) rd_lc_state_and_cnt_csrs();
// Wait before re-checking lc_state to allow escalate to be accepted
cfg.clk_rst_vif.wait_clks($urandom_range(150, 100));
cfg.set_test_phase(LcCtrlReadState2);
// Check count and state after escalate is generated
// Skip if token mux select line error injection
if (!err_inj.token_mux_ctrl_redun_err) rd_lc_state_and_cnt_csrs();

cfg.set_test_phase(LcCtrlPostTransition);
cfg.set_test_phase(LcCtrlPostTransition);

// Delay a few extra cycles if we are doing escalate injection
if (err_inj.security_escalation_err) begin
cfg.clk_rst_vif.wait_clks(security_escalation_err_inj_delay + 10);
end
// Delay a few extra cycles if we are doing escalate injection
if (err_inj.security_escalation_err) begin
cfg.clk_rst_vif.wait_clks(security_escalation_err_inj_delay + 10);
end

// Attempt a second transition post transition if enabled
// verilog_format: off - avoid bad formatting
if (err_inj.post_trans_err) begin
`uvm_info(`gfn, "Attempting second transition post transition", UVM_LOW)
`DV_CHECK_RANDOMIZE_FATAL(this)
// Clear all error injections except post_trans_err
err_inj = '{post_trans_err: 1, default: 0};
// SW transition request
if ((err_inj.state_err || valid_state_for_trans(lc_state)) &&
(err_inj.count_err || err_inj.transition_count_err || lc_cnt != LcCnt24)) begin
lc_ctrl_state_pkg::lc_token_t token_val = get_random_token();
randomize_next_lc_state(dec_lc_state(lc_state));
set_hashed_token();
set_otp_prog_rsp();
sw_transition_req(next_lc_state, token_val);
end else begin
// wait at least two clks for scb to finish checking lc outputs
cfg.clk_rst_vif.wait_clks($urandom_range(10, 2));
// Attempt a second transition post transition if enabled
// verilog_format: off - avoid bad formatting
if (err_inj.post_trans_err) begin
`uvm_info(`gfn, "Attempting second transition post transition", UVM_LOW)
`DV_CHECK_RANDOMIZE_FATAL(this)
// Clear all error injections except post_trans_err
err_inj = '{post_trans_err: 1, default: 0};
// SW transition request
if ((err_inj.state_err || valid_state_for_trans(lc_state)) &&
(err_inj.count_err || err_inj.transition_count_err || lc_cnt != LcCnt24)) begin
lc_ctrl_state_pkg::lc_token_t token_val = get_random_token();
randomize_next_lc_state(dec_lc_state(lc_state));
set_hashed_token();
set_otp_prog_rsp();
sw_transition_req(next_lc_state, token_val);
end else begin
// wait at least two clks for scb to finish checking lc outputs
cfg.clk_rst_vif.wait_clks($urandom_range(15, 6));
end
cfg.set_test_phase(LcCtrlPostTransTransitionComplete);
end
cfg.set_test_phase(LcCtrlPostTransTransitionComplete);
// verilog_format: on
end else begin
cfg.set_test_phase(LcCtrlBadNextState);
// wait at least two clks for scb to finish checking lc outputs
cfg.clk_rst_vif.wait_clks($urandom_range(15, 6));
end
// verilog_format: on

// Sample coverage if enabled
sample_cov();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,21 @@ class lc_ctrl_volatile_unlock_smoke_vseq extends lc_ctrl_smoke_vseq;
end
csr_wr(ral.transition_cmd, 'h01);

if (next_state == DecLcStTestUnlocked0) begin
if (!`SEC_VOLATILE_RAW_UNLOCK_EN) begin
// We expect the VOLATILE_RAW_UNLOCK bit to stay at zero in this case.
cfg.clk_rst_vif.wait_clks(2);
csr_rd_check(.ptr(ral.transition_ctrl.volatile_raw_unlock), .compare_value(0));
cfg.clk_rst_vif.wait_clks(10);
// Since we're performing a real transition in this case with a hashed token, we should
// be getting a token error since a real transition expects an unhashed token.
csr_spinwait(.ptr(ral.status.token_error), .exp_data(1), .timeout_ns(10_000_000));
// The strap sampling override signal should be zero.
`DV_CHECK_EQ(cfg.lc_ctrl_vif.strap_en_override_o, 0);
if (cfg.en_cov) cov.volatile_raw_unlock_cg.sample(0);
end else if (next_state == DecLcStTestUnlocked0) begin
// We expect the VOLATILE_RAW_UNLOCK bit to go to one in this case.
cfg.clk_rst_vif.wait_clks(2);
csr_rd_check(.ptr(ral.transition_ctrl.volatile_raw_unlock), .compare_value(1));
csr_spinwait(.ptr(ral.status.transition_successful), .exp_data(1), .timeout_ns(100_000));
cfg.clk_rst_vif.wait_clks(10);
`DV_CHECK_EQ(cfg.lc_ctrl_vif.strap_en_override_o, 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,16 @@
}
]

// Add LC_CTRL specific exclusion files.
vcs_cov_excl_files: ["{proj_root}/hw/ip/lc_ctrl/dv/cov/lc_ctrl_cov_unr_excl.el",
"{proj_root}/hw/ip/lc_ctrl/dv/cov/lc_ctrl_terminal_st_excl.el"]
build_modes: [
{
name: volatile_unlock_disabled
build_opts: ["+define+SEC_VOLATILE_RAW_UNLOCK_EN=0"]
}
{
name: volatile_unlock_enabled
build_opts: ["+define+SEC_VOLATILE_RAW_UNLOCK_EN=1"]
}
]

// Default UVM test and seq class name.
uvm_test: lc_ctrl_base_test
Expand Down Expand Up @@ -157,14 +164,14 @@
{
name: lc_ctrl_jtag_access
uvm_test_seq: lc_ctrl_jtag_access_vseq
run_opts: ["+en_scb=0", "+create_jtag_riscv_map=1"]
run_opts: ["+create_jtag_riscv_map=1"]
reseed: 50
}

{
name: lc_ctrl_jtag_priority
uvm_test_seq: lc_ctrl_jtag_priority_vseq
run_opts: ["+en_scb=0", "+create_jtag_riscv_map=1"]
run_opts: ["+create_jtag_riscv_map=1"]
reseed: 10
}

Expand Down
19 changes: 19 additions & 0 deletions hw/ip/lc_ctrl/dv/lc_ctrl_volatile_unlock_disabled_sim_cfg.hjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// sim cfg file for the variant of LC_CTRL without volatile unlock
{
// Name of the sim cfg variant
variant: volatile_unlock_disabled

// Import additional common sim cfg files.
import_cfgs: ["{proj_root}/hw/ip/lc_ctrl/dv/lc_ctrl_base_sim_cfg.hjson"]

// Enable this build mode for all tests
en_build_modes: ["volatile_unlock_disabled"]

// exclusion files
// TODO: redo UNR
vcs_cov_excl_files: ["{proj_root}/hw/ip/lc_ctrl/dv/cov/lc_ctrl_terminal_st_excl.el"]
}
19 changes: 19 additions & 0 deletions hw/ip/lc_ctrl/dv/lc_ctrl_volatile_unlock_enabled_sim_cfg.hjson
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// sim cfg file for the variant of LC_CTRL with volatile unlock
{
// Name of the sim cfg variant
variant: volatile_unlock_enabled

// Import additional common sim cfg files.
import_cfgs: ["{proj_root}/hw/ip/lc_ctrl/dv/lc_ctrl_base_sim_cfg.hjson"]

// Enable this build mode for all tests
en_build_modes: ["volatile_unlock_enabled"]

// exclusion files
// TODO: redo UNR
vcs_cov_excl_files: ["{proj_root}/hw/ip/lc_ctrl/dv/cov/lc_ctrl_terminal_st_excl.el"]
}
10 changes: 1 addition & 9 deletions hw/ip/lc_ctrl/dv/tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ module tb;
LcKeymgrDivWidth'({(LcKeymgrDivWidth/8){8'h5a}});
parameter lc_keymgr_div_t RndCnstLcKeymgrDivProduction =
LcKeymgrDivWidth'({(LcKeymgrDivWidth/8){8'ha5}});
// ---------- VOLATILE_TEST_UNLOCKED CODE SECTION START ----------
// NOTE THAT THIS IS A FEATURE FOR TEST CHIPS ONLY TO MITIGATE
// THE RISK OF A BROKEN OTP MACRO. THIS WILL BE DISABLED VIA
// SecVolatileRawUnlockEn AT COMPILETIME FOR PRODUCTION DEVICES.
// ---------------------------------------------------------------
// ICEBOX(#18250): The SecVolatileRawUnlockEn configuration should be tested separately for PROD.
parameter bit SecVolatileRawUnlockEn = 1;
// ----------- VOLATILE_TEST_UNLOCKED CODE SECTION END -----------

// macro includes
`include "uvm_macros.svh"
Expand Down Expand Up @@ -108,7 +100,7 @@ module tb;
.SiliconCreatorId(LcCtrlSiliconCreatorId[lc_ctrl_reg_pkg::SiliconCreatorIdWidth-1:0]),
.ProductId(LcCtrlProductId[lc_ctrl_reg_pkg::ProductIdWidth-1:0]),
.RevisionId(LcCtrlRevisionId[lc_ctrl_reg_pkg::RevisionIdWidth-1:0]),
.SecVolatileRawUnlockEn(SecVolatileRawUnlockEn)
.SecVolatileRawUnlockEn(`SEC_VOLATILE_RAW_UNLOCK_EN)
) dut (
.clk_i (clk),
.rst_ni(rst_n),
Expand Down
11 changes: 10 additions & 1 deletion hw/top_earlgrey/data/ip/chip_lc_ctrl_testplan.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -297,12 +297,21 @@
- Pre-load OTP image with RAW lc_state.
- Initiate the LC transition to test_unlocked0 state using the
VOLATILE_RAW_UNLOCK mode of operation.

If this top-level is expected to support VOLATILE_RAW_UNLOCK:

- As part of the transition to test_unlocked0, switch the TAP interface to rv_dm.
- Enable ROM execution via rv_dm, and perform POR.
- Initiate a second transition to test_unlocked0 using VOLATILE_RAW_UNLOCK.
- Verify that the CPU is able to execute.
- Test ext_clk injection before enabling ROM execution.

If this top-level is NOT expected to support VOLATILE_RAW_UNLOCK:

Test ext_clk injection before enabling ROM execution.
- Check that the VOLATILE_RAW_UNLOCK bit in the transition control register stays 0
when it is programmed to 1.
- Check that the transition results in a token error (the real RAW unlock transition
expects the unhashed token instead of the hashed token supplied for volatile RAW unlock).
'''
features: [
"LC_CTRL.STATE.RAW",
Expand Down
11 changes: 9 additions & 2 deletions hw/top_earlgrey/dv/chip_sim_cfg.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,11 @@
uvm_test_seq: chip_sw_lc_volatile_raw_unlock_vseq
sw_images: ["//sw/device/tests/sim_dv:lc_ctrl_volatile_raw_unlock_test:1:new_rules"]
en_run_modes: ["sw_test_mode_test_rom"]
run_opts: ["+use_otp_image=OtpTypeLcStRaw"]
run_opts: [
"+use_otp_image=OtpTypeLcStRaw",
// We set this to zero if the volatile RAW unlock mechanism is expected
// to be disabled (this should be the case in production silicon).
"+exp_volatile_raw_unlock_en=0"]
run_timeout_mins: 120
}
{
Expand All @@ -935,7 +939,10 @@
en_run_modes: ["sw_test_mode_test_rom"]
run_opts: [
"+use_otp_image=OtpTypeLcStRaw",
"+chip_clock_source=ChipClockSourceExternal48Mhz"]
"+chip_clock_source=ChipClockSourceExternal48Mhz",
// We set this to zero if the volatile RAW unlock mechanism is expected
// to be disabled (this should be the case in production silicon).
"+exp_volatile_raw_unlock_en=0"]
run_timeout_mins: 120
}
{
Expand Down
Loading
Loading