[keymgr/dv] Scb update for LC disable
Clean all regression failures in keymgr_lc_disable, except
that LC disable occurs at StReset, as design will fix it
Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/ip/keymgr/dv/env/keymgr_if.sv b/hw/ip/keymgr/dv/env/keymgr_if.sv
index c55f977..dd1ded9 100644
--- a/hw/ip/keymgr/dv/env/keymgr_if.sv
+++ b/hw/ip/keymgr/dv/env/keymgr_if.sv
@@ -289,6 +289,8 @@
endfunction
function automatic void wipe_sideload_keys();
+ is_kmac_key_good <= 0;
+
aes_key_exp.valid <= 0;
kmac_key_exp.valid <= 0;
otbn_key_exp.valid <= 0;
diff --git a/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv b/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv
index 4301ed1..d25c8f8 100644
--- a/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv
+++ b/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv
@@ -47,6 +47,8 @@
NotUpdate
} update_result_e;
+ localparam int RESET_ADV_CYCLES = 2000;
+
int adv_cnt = 0;
// local variables
@@ -132,31 +134,32 @@
case (op)
keymgr_pkg::OpAdvance: begin
+ bit is_err = get_hw_invalid_input() || get_fault_err();
case (current_state)
keymgr_pkg::StInit: begin
- bit is_err = get_hw_invalid_input();
compare_adv_creator_data(.cdi_type(current_cdi),
.exp_match(!is_err),
.byte_data_q(item.byte_data_q));
if (is_err) compare_invalid_data(item.byte_data_q);
end
keymgr_pkg::StCreatorRootKey: begin
- bit is_err = get_hw_invalid_input();
-
compare_adv_owner_int_data(.cdi_type(current_cdi),
.exp_match(!is_err),
.byte_data_q(item.byte_data_q));
if (is_err) compare_invalid_data(item.byte_data_q);
end
keymgr_pkg::StOwnerIntKey: begin
- compare_adv_owner_data(current_cdi, item.byte_data_q);
+ compare_adv_owner_data(.cdi_type(current_cdi),
+ .exp_match(!is_err),
+ .byte_data_q(item.byte_data_q));
end
keymgr_pkg::StOwnerKey, keymgr_pkg::StDisabled, keymgr_pkg::StInvalid: begin
- compare_invalid_data(item.byte_data_q);
+ is_err = 0;
end
default: `uvm_error(`gfn, $sformatf("Unexpected current_state: %0d", current_state))
endcase
+ if (is_err) compare_invalid_data(item.byte_data_q);
end
keymgr_pkg::OpGenId: begin
if (get_is_kmac_data_correct()) compare_id_data(item.byte_data_q);
@@ -222,7 +225,7 @@
default: `uvm_info(`gfn, "KMAC result isn't updated to any output", UVM_MEDIUM)
endcase
- if (!(current_state inside {keymgr_pkg::StReset, keymgr_pkg::StInvalid}) &&
+ if (current_state != keymgr_pkg::StReset &&
get_operation() inside {keymgr_pkg::OpAdvance, keymgr_pkg::OpDisable}) begin
current_cdi = get_adv_cdi_type();
if (current_cdi > 0) begin
@@ -239,6 +242,10 @@
keymgr_pkg::keymgr_ops_e op = get_operation();
bit is_final_kdf;
+ // Update state to Invalid earlier so that we can get InvalidOp error, as LC disable in the
+ // middle of OP will trigger this error
+ if (!cfg.keymgr_vif.get_keymgr_en()) current_state = get_next_state();
+
// for advance after StReset, it needs 2 KDF. Only update opt_status after the last one
if (!(op inside {keymgr_pkg::OpAdvance, keymgr_pkg::OpDisable}) ||
current_state == keymgr_pkg::StReset) begin
@@ -258,10 +265,23 @@
end
join_none
- if (is_final_kdf && cfg.keymgr_vif.get_keymgr_en()) process_error_n_alert();
+ if (is_final_kdf) process_error_n_alert();
// IntrOpDone occurs after every KDF
void'(ral.intr_state.predict(.value(1 << int'(IntrOpDone))));
+ if (get_fault_err() || !cfg.keymgr_vif.get_keymgr_en()) begin
+ if (op inside {keymgr_pkg::OpAdvance, keymgr_pkg::OpDisable}) begin
+ if (adv_cnt != keymgr_pkg::CDIs - 1) begin
+ adv_cnt++;
+ end else begin
+ adv_cnt = 0;
+ update_state(keymgr_pkg::StInvalid);
+ end
+ end else begin // other non-advance OP
+ update_state(keymgr_pkg::StInvalid);
+ end
+ return NotUpdate;
+ end
case (current_state)
keymgr_pkg::StInit, keymgr_pkg::StCreatorRootKey, keymgr_pkg::StOwnerIntKey,
keymgr_pkg::StOwnerKey: begin
@@ -269,8 +289,7 @@
case (op)
keymgr_pkg::OpAdvance: begin
// if it's StOwnerKey, it advacens to OpDisable. Key is just random value
- if (current_state == keymgr_pkg::StOwnerKey || get_fault_err()) begin
- if (get_fault_err()) current_state = keymgr_pkg::StDisabled;
+ if (current_state == keymgr_pkg::StOwnerKey) begin
update_result = NotUpdate;
end else begin
update_result = UpdateInternalKey;
@@ -297,14 +316,13 @@
end
keymgr_pkg::OpGenId, keymgr_pkg::OpGenSwOut, keymgr_pkg::OpGenHwOut: begin
// If only op error but no fault error, no update for output
- if (get_op_err() && !get_fault_err()) begin
+ if (get_op_err()) begin
update_result = NotUpdate;
end else if (op == keymgr_pkg::OpGenHwOut) begin
update_result = UpdateHwOut;
end else begin
update_result = UpdateSwOut;
end
- if (get_fault_err()) update_state(keymgr_pkg::StDisabled);
end
default: `uvm_fatal(`gfn, $sformatf("Unexpected operation: %0s", op.name))
endcase
@@ -405,9 +423,32 @@
end
end
end
- "intr_enable", "err_code", "sw_binding_regwen": begin
+ "intr_enable", "sw_binding_regwen": begin
// no speical handle is needed
end
+ "err_code": begin
+ // Check in this block
+ do_read_check = 1'b0;
+
+ if (data_phase_read) begin
+ bit [TL_DW-1:0] err_code = `gmv(ral.err_code);
+
+ `DV_CHECK_EQ(item.d_data[keymgr_pkg::ErrInvalidOp],
+ err_code[keymgr_pkg::ErrInvalidOp])
+
+ `DV_CHECK_EQ(item.d_data[keymgr_pkg::ErrShadowUpdate],
+ err_code[keymgr_pkg::ErrShadowUpdate])
+
+ `DV_CHECK_EQ(item.d_data[keymgr_pkg::ErrInvalidStates],
+ err_code[keymgr_pkg::ErrInvalidStates])
+ // when op error occurs with keymgr_en = 0, input is meaningless. Design may or may not
+ // assert ErrInvalidIn, which doesn't matter
+ if (!err_code[keymgr_pkg::ErrInvalidOp] || cfg.keymgr_vif.get_keymgr_en()) begin
+ `DV_CHECK_EQ(item.d_data[keymgr_pkg::ErrInvalidIn],
+ err_code[keymgr_pkg::ErrInvalidIn])
+ end
+ end
+ end
"intr_test": begin
if (write && channel == AddrChannel) begin
bit [TL_DW-1:0] intr_en = `gmv(ral.intr_enable);
@@ -529,9 +570,13 @@
if (current_state == keymgr_pkg::StReset) begin
// when advance from StReset to StInit, we don't know how long it will take, it's ok
// when status is WIP or success
- `DV_CHECK_EQ(item.d_data inside {current_op_status, keymgr_pkg::OpDoneSuccess}, 1)
- if (item.d_data == keymgr_pkg::OpDoneSuccess) begin
- current_op_status = keymgr_pkg::OpDoneSuccess;
+ if (cfg.keymgr_vif.get_keymgr_en()) begin
+ `DV_CHECK_EQ(item.d_data inside {current_op_status, keymgr_pkg::OpDoneSuccess}, 1)
+ end
+ // advance OP completes
+ if (current_op_status == keymgr_pkg::OpWip &&
+ item.d_data inside {keymgr_pkg::OpDoneSuccess, keymgr_pkg::OpDoneFail}) begin
+ current_op_status = item.d_data;
current_state = get_next_state(current_state);
void'(ral.intr_state.predict(.value(1 << int'(IntrOpDone))));
@@ -586,6 +631,9 @@
endtask
virtual function bit [TL_DW-1:0] get_current_max_version();
+ // design change this to 0 if LC turns off keymgr.
+ if (!cfg.keymgr_vif.get_keymgr_en()) return 0;
+
case (current_state)
keymgr_pkg::StCreatorRootKey: return `gmv(ral.max_creator_key_ver_shadowed);
keymgr_pkg::StOwnerIntKey: return `gmv(ral.max_owner_int_key_ver_shadowed);
@@ -601,6 +649,8 @@
if (get_fault_err()) begin
set_exp_alert("fatal_fault_err", .is_fatal(1));
+ end
+ if (get_fault_err() || !cfg.keymgr_vif.get_keymgr_en()) begin
is_sw_share_corrupted = 1;
cfg.keymgr_vif.wipe_sideload_keys();
end
@@ -623,19 +673,13 @@
virtual function bit [TL_DW-1:0] get_err_code();
bit [TL_DW-1:0] err_code;
- // TODO, clean up later
- // if keymgr_en is off during an OP, suppress op err
- //if (cfg.keymgr_vif.get_keymgr_en() && current_state != keymgr_pkg::StInvalid) begin
- err_code[keymgr_pkg::ErrInvalidOp] = get_op_error();
- //end
+ err_code[keymgr_pkg::ErrInvalidOp] = get_op_error();
// this fault error is sticky, should preserve the value until reset
if (!invalid_status_err) invalid_status_err = is_kmac_rsp_err | is_kmac_invalid_data;
err_code[keymgr_pkg::ErrInvalidStates] = invalid_status_err;
- if (cfg.keymgr_vif.keymgr_en_sync2 == lc_ctrl_pkg::On) begin
- err_code[keymgr_pkg::ErrInvalidIn] = get_hw_invalid_input() | get_sw_invalid_input();
- end
+ err_code[keymgr_pkg::ErrInvalidIn] = get_hw_invalid_input() | get_sw_invalid_input();
`uvm_info(`gfn, $sformatf({"op_err = %0d, rsp_err = %0d, hw_invalid = %0d, sw_invalid = %0d, ",
"kmac_invalid_data = %0d"},
@@ -717,12 +761,12 @@
if (cfg.keymgr_vif.otp_key.key_share0 inside {0, '1}) begin
is_err = 1;
- `uvm_info(`gfn, "HW invalid input on key_share0", UVM_LOW)
+ `uvm_info(`gfn, "HW invalid input on otp key_share0", UVM_LOW)
end
if (cfg.keymgr_vif.otp_key.key_share1 inside {0, '1}) begin
is_err = 1;
- `uvm_info(`gfn, "HW invalid input on key_share1", UVM_LOW)
+ `uvm_info(`gfn, "HW invalid input on otp key_share1", UVM_LOW)
end
if (cfg.keymgr_vif.flash.seeds[flash_ctrl_pkg::CreatorSeedIdx] inside {0, '1}) begin
@@ -765,7 +809,7 @@
op == keymgr_pkg::OpDisable || !cfg.keymgr_vif.get_keymgr_en()) begin
return 0;
end else begin
- return !(err_code[keymgr_pkg::ErrInvalidOp]);
+ return !(err_code[keymgr_pkg::ErrInvalidOp]) && !get_fault_err();
end
endfunction
@@ -830,6 +874,7 @@
endfunction
virtual function void compare_adv_owner_data(keymgr_cdi_type_e cdi_type,
+ bit exp_match,
const ref byte byte_data_q[$]);
adv_owner_data_t exp, act;
string str = $sformatf("cdi_type: %s\n", cdi_type.name);
@@ -843,7 +888,11 @@
`CREATE_CMP_STR(SoftwareBinding[i])
end
- `DV_CHECK_EQ(act, exp, str)
+ if (exp_match) begin
+ `DV_CHECK_EQ(act, exp, str)
+ end else begin
+ `DV_CHECK_NE(act, exp, str)
+ end
adv_data_a_array[Sealing][keymgr_pkg::StOwnerKey] = act;
endfunction
@@ -958,12 +1007,15 @@
return op;
endfunction
- virtual function keymgr_pkg::keymgr_working_state_e get_next_state(keymgr_pkg::keymgr_working_state_e cur);
+ virtual function keymgr_pkg::keymgr_working_state_e get_next_state(
+ keymgr_pkg::keymgr_working_state_e cur = current_state);
if (!cfg.keymgr_vif.get_keymgr_en()) return keymgr_pkg::StInvalid;
else return keymgr_env_pkg::get_next_state(cur);
endfunction
- virtual function void update_state(keymgr_pkg::keymgr_working_state_e new_state, int cyc_dly = 1);
+ virtual function void update_state(
+ keymgr_pkg::keymgr_working_state_e new_state = get_next_state(),
+ int cyc_dly = 1);
fork
begin
// it takes 1 cycle to update state after rsp_done is set. add one more negedge to avoid
@@ -975,33 +1027,29 @@
endfunction
virtual function void wipe_hw_keys();
- if (current_op_status != keymgr_pkg::OpWip) begin
- // design takes 2 cycle to update state
- update_state(keymgr_pkg::StInvalid, .cyc_dly(2));
- `uvm_info(`gfn, "Keymgr_en is Off, wipe secret and move state to Invalid", UVM_LOW)
- cfg.keymgr_vif.wipe_sideload_keys();
- end
fork
begin
- if (current_op_status == keymgr_pkg::OpWip) begin
- // if operation is ongoing, then we must wait for response to be received
- // before transitioning
- wait(cfg.keymgr_vif.kmac_data_rsp.done);
- current_state = keymgr_pkg::StInvalid;
- `uvm_info(`gfn, "operation WIP but Keymgr_en is Off, update err_code and move to Invalid",
- UVM_LOW)
- process_error_n_alert();
- current_op_status = keymgr_pkg::OpDoneFail;
- end else begin
- // it takes 2 cycle to wipe sw_share. add one more negedge to avoid race condition
- // corner case, keymgr_en is changed while OP is almost done. OP will finish successfully
- // delay update_state in 1 cycle
- cfg.clk_rst_vif.wait_n_clks(3);
- update_state(keymgr_pkg::StInvalid);
- `uvm_info(`gfn, "operation WIP but Keymgr_en is Off, move to Invalid", UVM_LOW)
+ cfg.clk_rst_vif.wait_n_clks(1);
+ if (current_op_status != keymgr_pkg::OpWip || current_state == keymgr_pkg::StReset) begin
+ if (current_state != keymgr_pkg::StReset) begin
+ // design takes 2 cycle to update state
+ update_state(.cyc_dly(2));
+ `uvm_info(`gfn, "Keymgr_en is Off, wipe secret and move state to Invalid", UVM_LOW)
+ end else begin
+ bit [TL_DW-1:0] err_code = get_err_code();
+ err_code[keymgr_pkg::ErrInvalidOp] = 1;
+ // if it's StReset, the Advance OP is ongoing. alert will be sent after the OP
+ set_exp_alert("recov_operation_err", .max_delay(RESET_ADV_CYCLES));
+ void'(ral.err_code.predict(err_code));
+ end
end
- is_sw_share_corrupted = 1;
+ end
+ begin
+ // it takes 2 cycle to wipe sw_share. add one more negedge to avoid race condition
+ // corner case
+ cfg.clk_rst_vif.wait_n_clks(3);
cfg.keymgr_vif.wipe_sideload_keys();
+ is_sw_share_corrupted = 1;
end
join_none
endfunction