[keymgr] Fix for error capture
- Fixes #7998
- Break keymgr errors into 4 explicit categories
- sync errors
- async errors
- sync faults
- async faults
Signed-off-by: Timothy Chen <timothytim@google.com>
[keymgr, dv] Accompanying DV updates
Signed-off-by: Timothy Chen <timothytim@google.com>
[keymgr, sw] Accompanying software updates
Signed-off-by: Timothy Chen <timothytim@google.com>
[keymgr] Accompanying documentation update
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/keymgr/data/keymgr.hjson b/hw/ip/keymgr/data/keymgr.hjson
index a329f6b..f00e2df 100644
--- a/hw/ip/keymgr/data/keymgr.hjson
+++ b/hw/ip/keymgr/data/keymgr.hjson
@@ -847,37 +847,41 @@
desc: '''
Key manager error code.
This register must be explicitly cleared by software.
- Software clears by writing back whatever it reads.
+
+ This register represents both synchronous and asynchronous recoverable
+ errors.
+
+ Synchronous errors refer to those that only happen when a keymgr operation is
+ invoked, while asynchronous refers to errors that can happen at any time.
''',
swaccess: "rw1c",
- hwaccess: "hrw",
+ hwaccess: "hwo",
fields: [
{ bits: "0",
name: "INVALID_OP",
resval: "0x0"
- desc: "Invalid operation issued to key manager",
+ desc: "Invalid operation issued to key manager, synchronous error",
},
{ bits: "1",
name: "INVALID_KMAC_INPUT",
resval: "0x0"
- desc: "Invalid data issued to kmac interface",
+ desc: "Invalid data issued to kmac interface, synchronous error",
},
{ bits: "2",
name: "INVALID_SHADOW_UPDATE",
resval: "0x0"
- desc: "An error observed during shadow register updates.",
- },
- { bits: "3",
- name: "INVALID_STATES",
- resval: "0x0"
- desc: "Invalid states has occurred in keymgr. These are suspected faults. Please see !!FAULT_STATUS for a detailed breakdown",
+ desc: "An error observed during shadow register updates, asynchronous error",
},
]
},
{ name: "FAULT_STATUS",
desc: '''
- Detailed per bit breakdown of the INVALID_STATES field in !!ERR_CODE
+ This register represents both synchronous and asynchronous fatal faults.
+
+ Synchronous faults refer to those that only happen when a keymgr operation is
+ invoked, while asynchronous refers to faults that can happen at any time.
+
''',
swaccess: "ro",
hwaccess: "hrw",
@@ -885,42 +889,42 @@
{ bits: "0",
name: "CMD",
resval: "0x0"
- desc: "A non-onehot command was sent from keymgr to kmac",
+ desc: "A non-onehot command was seen in kmac, asynchronous fault.",
},
{ bits: "1",
name: "KMAC_FSM",
resval: "0x0"
- desc: "The kmac transfer interface is in an error state",
+ desc: "The kmac transfer interface is in an error state, asynchronous fault.",
},
{ bits: "2",
name: "KMAC_OP",
resval: "0x0"
- desc: "KMAC reported an error during keymgr usage, this should never happen",
+ desc: "KMAC reported an error during keymgr usage, this should never happen - synchronous fault.",
},
{ bits: "3",
name: "KMAC_OUT",
resval: "0x0"
- desc: "KMAC data returned as all 0's or all 1's",
+ desc: "KMAC data returned as all 0's or all 1's - synchronous fault",
},
{ bits: "4",
name: "REGFILE_INTG",
resval: "0x0"
- desc: "Register file integrity error.",
+ desc: "Register file integrity error, asynchronous fault",
},
{ bits: "5",
name: "SHADOW",
resval: "0x0"
- desc: "Shadow copy storage error.",
+ desc: "Shadow copy storage error, asynchronous fault",
},
{ bits: "6",
name: "CTRL_FSM_INTG",
resval: "0x0"
- desc: "Control FSM integrity error.",
+ desc: "Control FSM integrity error, asynchronous fault",
},
{ bits: "7",
name: "CTRL_FSM_CNT",
resval: "0x0"
- desc: "Control FSM counter integrity error.",
+ desc: "Control FSM counter integrity error, asynchronous fault",
},
]
},
diff --git a/hw/ip/keymgr/doc/_index.md b/hw/ip/keymgr/doc/_index.md
index bbc8a70..6cf2075 100644
--- a/hw/ip/keymgr/doc/_index.md
+++ b/hw/ip/keymgr/doc/_index.md
@@ -201,55 +201,104 @@
For advance-state and `generate-output` commands, the KMAC emitted output are also in 2-shares.
Software is responsible for determining if the key should be preserved in shares or combined, depending on the use case.
-## Errors, Interrupts and Alerts
-An error code register is maintained {{< regref ERR_CODE >}} to check issues that might rise while using the key manager.
-There are two categories of errors
-* Hardware fault errors - These errors indicate something fundamental has gone wrong and are errors that could not have been caused by software.
- * Invalid states - There are invalid / impossible states observed in the keymgr. These are likely fault errors.
- * Invalid fsm state - The fsm reached an invalid state. This is not possible by software and indicates a hardware fault.
- * Invalid kmac operation - The KMAC module itself reported an error. This is not possible given the set of KMAC data interface inputs.
- * Invalid output - The data return from KMAC is all 0's or all 1's. This is not possible given the set of KMAC data interface inputs.
+## Errors, Faults and Alerts
-* Software operation errors - These errors could have been caused by user errors and is a sign that software should examine its usage of key manager.
- * Invalid operation - An invalid operation (for example `generate` while in Reset) was invoked.
- * Invalid input - Invalid software and hardware inputs were supplied (for example a greater key version than allowed in {{< regref MAX_OWNER_KEY_VER >}}, or a root key or seed that has never been initialized.
+The key manager has two overall categories of errors:
+* Recoverable errors
+* Fatal errors
-Two separate alerts are generated, one corresponding to each category above.
+Recoverable errors are those likely to have been introduced by software and not fatal to the key manager or the system.
+Fatal errors are logically impossible errors that have a high likelihood of being a fault and thus fatal.
+
+Each category of error can be further divided into two:
+* Synchronous errors
+* Asynchronous errors
+
+Synchronous errors happen only during a key manager transaction.
+Asynchronous errors can happen at any time.
+
+Given the above, we have 4 total categories of errors:
+* Synchronous recoverable errors
+* Asynchronous recoverable errors
+* Synchronous fatal errors
+* Asynchronous fatal errors
+
+All recoverable errors (synchronous and asynchronous) are captured in {{< regref ERR_CODE >}}.
+All fatal errors (synchronous and asynchronous) are captured in {{< regref FAULT_STATUS >}}.
+
+Recoverable errors cause a recoverable alert to be sent from the key manager.
+Fatal errors cause a fatal alert to be sent from the key manager.
+
+Below, the behavior of each category and its constituent errors are described in detail.
+
+### Synchronous Recoverable Errors
+
+These errors can only happen when a key manager transaction is invoked and are typically associated with incorrect software programming.
+At the end of the transaction, key manager reports whether there was an error in {{< regref ERR_CODE >}} and sends a recoverable alert.
+
+* {{< regref ERR_CODE.INVALID_OP >}} Software issued an invalid operation given the current key manager state.
+* {{< regref ERR_CODE.INVALID_KMAC_INPUT >}} Software supplied invalid input (for example a key greater than the max version) for a key manager operation.
+
+### Asynchronous Recoverable Errors
+
+These errors can happen at any time regardless of whether there is a key manager operation.
+The error is reported in {{< regref ERR_CODE >}} and the key manager sends a recoverable alert.
+
+* {{< regref ERR_CODE.INVALID_SHADOW_UPDATE >}} Software performed an invalid sequence while trying to update a key manager shadow register.
+
+### Synchronous Fatal Errors
+
+These errors can only happen when a key manager transaction is invoked and receives malformed transaction results that are not logically possible.
+At the end of the transaction, key manager reports whether there was an error in {{< regref FAULT_STATUS >}} and continuously sends fatal alerts .
+
+* {{< regref ERR_CODE.KMAC_OP >}} KMAC reports a transaction error, this is not possible given current definitions.
+* {{< regref ERR_CODE.KMAC_OUT >}} KMAC returns all 0's or all 1's as a result, this is not possible given current definitions.
+
+Note, these errors are synchronous from the perspective of the key manager, but they may be asynchronous from the perspective of another module.
+
+### Asynchronous Fatal Errors
+
+These errors can happen at any time regardless of whether there is a key manager operation.
+The error is reported in {{< regref FAULT_STATUS >}} and the key manager continuously sends fatal alerts.
+
+* {{< regref ERR_CODE.CMD >}} KMAC control's command lines are displaying non-one hot values.
+* {{< regref ERR_CODE.KMAC_FSM >}} KMAC control's FSM is in an invalid state.
+* {{< regref ERR_CODE.REGFILE_INTG >}} The key manager's regfile reports an integrity error.
+* {{< regref ERR_CODE.SHADOW >}} The key manager's regfile reports a shadow storage error.
+* {{< regref ERR_CODE.CTRL_FSM_INTG >}} The key manager's main control FSM is in an invalid state.
+* {{< regref ERR_CODE.CTRL_FSM_CNT >}} The key manager's main control count exhibits an incorrect value.
### Faults and Operational Faults
-The {{< regref FAULT_STATUS >}} register captures all faults that can occur within the key manager.
-Some of these faults can occur only when there is a key manager operation ongoing, other faults can happen at any time (for example register integrity faults or shadow storage faults).
-{{< regref FAULT_STATUS >}} captures all faults regardless of when they happen.
+Since fatal errors (faults) can happen at any time, their impact on the key manager depends on transaction timing.
-The {{< regref ERR_CODE.INVALID_STATES >}} field represents the presence of **any** fault during a key manager operation.
-This means if a fault happens before or during an operation, it will be recognized as an operational fault and result in keymgr's transition to `Invalid` state.
+If the fault happens while a transaction is ongoing, key manager transitions to the `Invalid` [state](#invalid-entry-wiping).
+
+If the fault happens while there is no transaction, an alert is first sent to the alert handler.
+If before the alert handler escalates an operation is run, the key manager again transitions to `Invalid` [state](#invalid-entry-wiping).
+If the alert handler escalates and disables the key manager, then the key manager will also transition to `Invalid` state if it is not already there.
#### Example 1: Fault During Operation
The key manager is running a generate operation and a non-onehot command was observed by the kmac interface.
Since the non-onehot condition is a fault, it will be reflected in {{< regref FAULT_STATUS >}}.
-Since an operation was ongoing when this fault was seen, it will also be reflected in {{< regref ERR_CODE.INVALID_STATES >}}.
-This is considered an operational fault and begin transition to the `Invalid` [state](#invalid-entry-wiping).
+Since an operation was ongoing when this fault was seen, it will also be reflected in {{< regref ERR_CODE.INVALID_OP >}}.
+This is considered an operational fault and begins transition to `Invalid`.
#### Example 2: Fault During Idle
The key manager is NOT running an operation and is idle.
During this time, a fault was observed on the regfile (shadow storage error) and FSM (control FSM integrity error).
The faults will be reflected in {{< regref FAULT_STATUS >}}.
-However, since there was no ongoing key manager operation, the error is **not** reflected in {{< regref ERR_CODE.INVALID_STATES >}}.
-This is **not** considered an operational fault and the key manager will remain in its current state.
+
+This is **not** considered an operational fault and the key manager will remain in its current state until an operation is invoked or the alert handler escalates.
#### Example 3: Operation after Fault Detection
Continuing from the example above, assume now the key manager begins an operation.
-Since the key manager has previous encountered a fault, any operation now is considered an operational fault and will be reflected in {{< regref ERR_CODE.INVALID_STATES >}}.
-This is considered an operational fault and begin transition to the `Invalid` [state](#invalid-entry-wiping).
+Since the key manager has previous encountered a fault, any operation now is considered an operational fault and begins transition to the `Invalid` [state](#invalid-entry-wiping).
-### Invalid Output
-When these errors occur, a fault alert is generated.
+#### Additional Details on Invalid Input
-### Invalid Input
-When these errors occur, an operation alert is generated
-What is considered invalid input depends on the current state and the operation called.
+What is considered invalid input changes based on current state and operation.
When an advance operation is invoked:
- The working state key is checked for all 0's and all 1's.
@@ -264,8 +313,7 @@
When a generate output identity is invoked:
- The working state key is checked for all 0's and all 1's.
-### Invalid Operation
-When these errors occur, an operation alert is generated.
+#### Invalid Operation
The table below enumerates the legal operations in a given state.
When an illegal operation is supplied, the error code is updated and the operation is flagged as `done with error`.
diff --git a/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv b/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv
index 2b10c08..ce6973f 100644
--- a/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv
+++ b/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv
@@ -19,11 +19,11 @@
tl_intg_alert_name = "fatal_fault_err";
has_edn = 1;
super.initialize(csr_base_addr);
- tl_intg_alert_fields[ral.err_code.invalid_states] = 1;
+ //tl_intg_alert_fields[ral.err_code.invalid_states] = 1;
tl_intg_alert_fields[ral.fault_status.regfile_intg] = 1;
shadow_update_err_status_fields[ral.err_code.invalid_shadow_update] = 1;
shadow_storage_err_status_fields[ral.fault_status.shadow] = 1;
- shadow_storage_err_status_fields[ral.err_code.invalid_states] = 1;
+ //shadow_storage_err_status_fields[ral.err_code.invalid_states] = 1;
m_keymgr_kmac_agent_cfg = kmac_app_agent_cfg::type_id::create("m_keymgr_kmac_agent_cfg");
m_keymgr_kmac_agent_cfg.if_mode = dv_utils_pkg::Device;
diff --git a/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv b/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv
index d25c8f8..63f8390 100644
--- a/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv
+++ b/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv
@@ -56,7 +56,7 @@
keymgr_pkg::keymgr_op_status_e current_op_status;
bit is_kmac_rsp_err;
bit is_kmac_invalid_data;
- bit invalid_status_err;
+ bit is_fault_err;
bit is_sw_share_corrupted;
// HW internal key, used for OP in current state
@@ -135,7 +135,7 @@
case (op)
keymgr_pkg::OpAdvance: begin
bit is_err = get_hw_invalid_input() || get_fault_err();
-
+ `uvm_info(`gfn, $sformatf("What is is_err: %d", is_err), UVM_MEDIUM)
case (current_state)
keymgr_pkg::StInit: begin
compare_adv_creator_data(.cdi_type(current_cdi),
@@ -259,7 +259,7 @@
begin
cfg.clk_rst_vif.wait_n_clks(1);
if (is_final_kdf) begin
- if (get_err_code()) current_op_status = keymgr_pkg::OpDoneFail;
+ if (get_err_code() || get_fault_err()) current_op_status = keymgr_pkg::OpDoneFail;
else current_op_status = keymgr_pkg::OpDoneSuccess;
end
end
@@ -439,8 +439,6 @@
`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
@@ -608,8 +606,10 @@
if (addr_phase_read) begin
addr_phase_is_sw_share_corrupted = is_sw_share_corrupted;
end else if (data_phase_read && addr_phase_is_sw_share_corrupted) begin
+ // disable read check outside of the item compare.
+ // it is possible for the returned data when corrupted, to be 0
+ do_read_check = 1'b0;
if (item.d_data != 0) begin
- do_read_check = 1'b0;
`DV_CHECK_NE(item.d_data, `gmv(csr))
end
end
@@ -645,40 +645,51 @@
virtual function void process_error_n_alert();
bit [TL_DW-1:0] err = get_err_code();
+
+ // A detected fault will cause us to transition to invalid where
+ // operations are always error'd
+ if (get_fault_err()) begin
+ err[keymgr_pkg::ErrInvalidOp] = 1;
+ end
void'(ral.err_code.predict(err));
- 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
+
+ if (get_fault_err()) begin
+ set_exp_alert("fatal_fault_err", .is_fatal(1));
+ end
+
if (get_op_err()) set_exp_alert("recov_operation_err");
- `uvm_info(`gfn, $sformatf("at %s, %s is issued and error code is 'b%0b",
+ `uvm_info(`gfn, $sformatf("at %s, %s is issued and error 'b%0b",
current_state, get_operation(), err), UVM_MEDIUM)
endfunction
virtual function bit [TL_DW-1:0] get_fault_err();
- bit [TL_DW-1:0] err = get_err_code();
- return err[keymgr_pkg::ErrInvalidStates];
+
+ // faults are sticky, and will remain until reset
+ is_fault_err |= is_kmac_rsp_err | is_kmac_invalid_data;
+ return is_fault_err;
+
endfunction
virtual function bit [TL_DW-1:0] get_op_err();
bit [TL_DW-1:0] err = get_err_code();
- return err[keymgr_pkg::ErrInvalidOp] || err[keymgr_pkg::ErrInvalidIn];
+ bit fault = get_fault_err();
+
+ // A detected fault causes the operation to transition into invalid,
+ // which will report an invalid operation
+ return err[keymgr_pkg::ErrInvalidOp] || err[keymgr_pkg::ErrInvalidIn] ||
+ fault;
endfunction
virtual function bit [TL_DW-1:0] get_err_code();
bit [TL_DW-1:0] err_code;
- 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;
-
+ err_code[keymgr_pkg::ErrInvalidOp] = get_op_error() | get_fault_err();
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, ",
@@ -792,7 +803,7 @@
if (current_state inside {keymgr_pkg::StCreatorRootKey, keymgr_pkg::StOwnerIntKey,
keymgr_pkg::StOwnerKey}) begin
- return !(err_code[keymgr_pkg::ErrInvalidStates] |
+ return !(get_fault_err() |
err_code[keymgr_pkg::ErrInvalidIn] |
!cfg.keymgr_vif.get_keymgr_en());
end else begin
@@ -894,7 +905,7 @@
`DV_CHECK_NE(act, exp, str)
end
- adv_data_a_array[Sealing][keymgr_pkg::StOwnerKey] = act;
+ if (exp_match) adv_data_a_array[Sealing][keymgr_pkg::StOwnerKey] = act;
endfunction
// for invalid OP, should not output any meaningful data to KMAC. Check the outputs aren't
@@ -1061,7 +1072,7 @@
current_op_status = keymgr_pkg::OpIdle;
is_kmac_rsp_err = 0;
is_kmac_invalid_data = 0;
- invalid_status_err = 0;
+ is_fault_err = 0;
is_sw_share_corrupted = 0;
req_fifo.flush();
rsp_fifo.flush();
diff --git a/hw/ip/keymgr/rtl/keymgr.sv b/hw/ip/keymgr/rtl/keymgr.sv
index 829400d..c2da1d7 100644
--- a/hw/ip/keymgr/rtl/keymgr.sv
+++ b/hw/ip/keymgr/rtl/keymgr.sv
@@ -242,7 +242,6 @@
.sw_binding_unlock_o(sw_binding_unlock),
.status_o(hw2reg.op_status.d),
.fault_o(fault_code),
- .fault_i(|reg2hw.fault_status),
.error_o(err_code),
.data_en_o(data_en),
.data_valid_o(data_valid),
@@ -517,25 +516,19 @@
.intr_o (intr_op_done_o)
);
- assign hw2reg.err_code.invalid_op.d = reg2hw.err_code.invalid_op.q |
- err_code[ErrInvalidOp];
- assign hw2reg.err_code.invalid_kmac_input.d = reg2hw.err_code.invalid_kmac_input.q |
- err_code[ErrInvalidIn];
- assign hw2reg.err_code.invalid_shadow_update.d = reg2hw.err_code.invalid_shadow_update.q |
- err_code[ErrShadowUpdate];
- assign hw2reg.err_code.invalid_states.d = reg2hw.err_code.invalid_states.q |
- err_code[ErrInvalidStates];
- assign hw2reg.err_code.invalid_op.de = 1'b1;
- assign hw2reg.err_code.invalid_kmac_input.de = 1'b1;
- assign hw2reg.err_code.invalid_shadow_update.de = 1'b1;
- assign hw2reg.err_code.invalid_states.de = 1'b1;
+ assign hw2reg.err_code.invalid_op.d = 1'b1;
+ assign hw2reg.err_code.invalid_kmac_input.d = 1'b1;
+ assign hw2reg.err_code.invalid_shadow_update.d = 1'b1;
+ assign hw2reg.err_code.invalid_op.de = err_code[ErrInvalidOp];
+ assign hw2reg.err_code.invalid_kmac_input.de = err_code[ErrInvalidIn];
+ assign hw2reg.err_code.invalid_shadow_update.de = err_code[ErrShadowUpdate];
// detailed breakdown of the invalid_states field above
- assign hw2reg.fault_status.cmd.de = fault_code[FaultCmd];
+ assign hw2reg.fault_status.cmd.de = fault_code[FaultKmacCmd];
assign hw2reg.fault_status.kmac_fsm.de = fault_code[FaultKmacFsm];
assign hw2reg.fault_status.kmac_op.de = fault_code[FaultKmacOp];
assign hw2reg.fault_status.kmac_out.de = fault_code[FaultKmacOut];
- assign hw2reg.fault_status.regfile_intg.de = fault_code[FaultRegFileIntg];
+ assign hw2reg.fault_status.regfile_intg.de = fault_code[FaultRegIntg];
assign hw2reg.fault_status.shadow.de = fault_code[FaultShadow];
assign hw2reg.fault_status.ctrl_fsm_intg.de = fault_code[FaultCtrlFsm];
assign hw2reg.fault_status.ctrl_fsm_cnt.de = fault_code[FaultCtrlCnt];
@@ -555,15 +548,13 @@
logic fault_errs, fault_err_req_q, fault_err_req_d, fault_err_ack;
logic op_errs, op_err_req_q, op_err_req_d, op_err_ack;
- // Error code fatal faults occur only when keymgr operation is actually invoked.
// Fault status can happen independently of any operation
- assign fault_errs = |reg2hw.fault_status |
- err_code[ErrInvalidStates];
+ assign fault_errs = |reg2hw.fault_status;
assign fault_err_req_d = fault_errs ? 1'b1 :
fault_err_ack ? 1'b0 : fault_err_req_q;
- assign op_errs = err_code[ErrInvalidOp] | err_code[ErrInvalidIn] | err_code[ErrShadowUpdate];
+ assign op_errs = |err_code;
assign op_err_req_d = op_errs ? 1'b1 :
op_err_ack ? 1'b0 : op_err_req_q;
diff --git a/hw/ip/keymgr/rtl/keymgr_ctrl.sv b/hw/ip/keymgr/rtl/keymgr_ctrl.sv
index 4f04ed4..d5731a3 100644
--- a/hw/ip/keymgr/rtl/keymgr_ctrl.sv
+++ b/hw/ip/keymgr/rtl/keymgr_ctrl.sv
@@ -35,7 +35,6 @@
output keymgr_working_state_e working_state_o,
output logic sw_binding_unlock_o,
output logic init_o,
- input fault_i,
// Data input
input otp_ctrl_pkg::otp_keymgr_key_t root_key_i,
@@ -125,7 +124,7 @@
logic [CdiWidth-1:0] cdi_cnt;
// error conditions
- logic kmac_out_valid;
+ logic invalid_kmac_out;
logic invalid_op;
logic cnt_err;
// states fall out of sparsely encoded range
@@ -178,22 +177,30 @@
///////////////////////////
// interaction between operation fsm and software
///////////////////////////
+ // categories of keymgr errors
+ logic [SyncErrLastIdx-1:0] sync_err;
+ logic [AsyncErrLastIdx-1:0] async_err;
+ logic [SyncFaultLastIdx-1:0] sync_fault;
+ logic [AsyncFaultLastIdx-1:0] async_fault;
logic op_err;
logic op_fault_err;
// unlock sw binding configuration whenever an advance call is made without errors
- assign sw_binding_unlock_o = adv_req & op_ack & ~|error_o;
+ assign sw_binding_unlock_o = adv_req & op_ack & ~(op_err | op_fault_err);
// error definition
// check incoming kmac data validity
- assign kmac_out_valid = valid_data_chk(kmac_data_i[0]) &
- (~KmacEnMasking | valid_data_chk(kmac_data_i[1]));
+ // Only check during the periods when there is actual kmac output
+ assign invalid_kmac_out = (op_update | op_ack) &
+ (~valid_data_chk(kmac_data_i[0]) |
+ (~valid_data_chk(kmac_data_i[1]) & KmacEnMasking));
- assign op_err = error_o[ErrInvalidOp] |
- error_o[ErrInvalidIn];
+ assign op_err = sync_err[SyncErrInvalidOp] |
+ sync_err[SyncErrInvalidIn];
- assign op_fault_err = error_o[ErrInvalidStates];
+ assign op_fault_err = |sync_fault |
+ |async_fault;
///////////////////////////
@@ -358,7 +365,7 @@
logic adv_state;
logic dis_state;
logic inv_state;
- assign adv_state = op_ack & adv_req;
+ assign adv_state = op_ack & adv_req & ~op_err;
assign dis_state = op_ack & dis_req;
assign inv_state = op_fault_err;
@@ -686,6 +693,7 @@
endcase // unique case (adv_state_q)
end
+
// operations fsm update precedence
// when in disabled state, always update.
assign op_update_sel = (op_ack | op_update) & disabled ? KeyUpdateKmac :
@@ -693,26 +701,75 @@
op_err ? KeyUpdateIdle :
(op_ack | op_update) ? KeyUpdateKmac : KeyUpdateIdle;
- assign error_o[ErrInvalidOp] = op_done_o & (invalid_op | disabled);
- assign error_o[ErrInvalidIn] = op_ack & kmac_input_invalid_i;
- assign error_o[ErrShadowUpdate] = shadowed_update_err_i;
- assign error_o[ErrInvalidStates] = (op_done_o | op_update) & fault_i;
- assign fault_o[FaultCmd] = kmac_cmd_err_i;
- assign fault_o[FaultKmacFsm] = kmac_fsm_err_i;
- assign fault_o[FaultKmacOp] = kmac_op_err_i;
- // Kmac output is only checked on operation complete. Invalid
- // values are legal otherwise
- assign fault_o[FaultKmacOut] = op_ack & ~kmac_out_valid;
- assign fault_o[FaultRegFileIntg] = regfile_intg_err_i;
- assign fault_o[FaultShadow] = shadowed_storage_err_i;
- assign fault_o[FaultCtrlFsm] = state_intg_err_q;
- assign fault_o[FaultCtrlCnt] = cnt_err;
+ // Advance calls are made up of multiple rounds of kmac operations.
+ // Any sync error that occurs is treated as an error of the entire call.
+ // Therefore sync errors that happen before the end of the call must be
+ // latched.
+ logic[SyncErrLastIdx-1:0] sync_err_q, sync_err_d;
+ logic[SyncFaultLastIdx-1:0] sync_fault_q, sync_fault_d;
+
+ logic err_vld;
+ assign err_vld = op_update | op_done_o;
+
+ // sync errors
+ // When an operation encounters a fault, the operation is always rejected as the FSM
+ // transitions to wipe
+ assign sync_err_d[SyncErrInvalidOp] = err_vld & (invalid_op | disabled | op_fault_err);
+ assign sync_err_d[SyncErrInvalidIn] = err_vld & kmac_input_invalid_i;
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ sync_err_q <= '0;
+ end else if (op_done_o) begin
+ sync_err_q <= '0;
+ end else if (op_update) begin
+ sync_err_q <= sync_err_d;
+ end
+ end
+ assign sync_err = sync_err_q | sync_err_d;
+
+ // async errors
+ assign async_err[AsyncErrShadowUpdate] = shadowed_update_err_i;
+
+ // sync faults
+ assign sync_fault_d[SyncFaultKmacOp] = err_vld & kmac_op_err_i;
+ assign sync_fault_d[SyncFaultKmacOut] = err_vld & invalid_kmac_out;
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ sync_fault_q <= '0;
+ end else if (op_update) begin
+ sync_fault_q <= sync_fault_d;
+ end
+ end
+ assign sync_fault = sync_fault_q | sync_fault_d;
+
+ // async faults
+ assign async_fault[AsyncFaultKmacCmd] = kmac_cmd_err_i;
+ assign async_fault[AsyncFaultKmacFsm] = kmac_fsm_err_i;
+ assign async_fault[AsyncFaultRegIntg] = regfile_intg_err_i;
+ assign async_fault[AsyncFaultShadow ] = shadowed_storage_err_i;
+ assign async_fault[AsyncFaultFsmIntg] = state_intg_err_q;
+ assign async_fault[AsyncFaultCntErr ] = cnt_err;
+
+ // output to error code register
+ assign error_o[ErrInvalidOp] = op_done_o & sync_err[SyncErrInvalidOp];
+ assign error_o[ErrInvalidIn] = op_done_o & sync_err[SyncErrInvalidIn];
+ assign error_o[ErrShadowUpdate] = async_err[AsyncErrShadowUpdate];
+
+ // output to fault code register
+ assign fault_o[FaultKmacOp] = op_done_o & sync_fault[SyncFaultKmacOp];
+ assign fault_o[FaultKmacOut] = op_done_o & sync_fault[SyncFaultKmacOut];
+ assign fault_o[FaultKmacCmd] = async_fault[AsyncFaultKmacCmd];
+ assign fault_o[FaultKmacFsm] = async_fault[AsyncFaultKmacFsm];
+ assign fault_o[FaultRegIntg] = async_fault[AsyncFaultRegIntg];
+ assign fault_o[FaultShadow] = async_fault[AsyncFaultShadow];
+ assign fault_o[FaultCtrlFsm] = async_fault[AsyncFaultFsmIntg];
+ assign fault_o[FaultCtrlCnt] = async_fault[AsyncFaultCntErr];
always_comb begin
status_o = OpIdle;
if (op_done_o) begin
- status_o = |error_o ? OpDoneFail : OpDoneSuccess;
+ status_o = |error_o | |fault_o ? OpDoneFail : OpDoneSuccess;
end else if (op_start_i) begin
status_o = OpWip;
end
diff --git a/hw/ip/keymgr/rtl/keymgr_pkg.sv b/hw/ip/keymgr/rtl/keymgr_pkg.sv
index aee9699..43c8651 100644
--- a/hw/ip/keymgr/rtl/keymgr_pkg.sv
+++ b/hw/ip/keymgr/rtl/keymgr_pkg.sv
@@ -140,23 +140,56 @@
OpDoneFail = 3
} keymgr_op_status_e;
+ // keymgr has 4 categories of errors
+ // sync errors - recoverable errors that happen during keymgr operation
+ // async errors - recoverable errors that happen asynchronously
+ // sync faults - fatal errors that happen during keymgr operation
+ // async faults - fatal errors that happen asynchronously
+
+ typedef enum logic [1:0] {
+ SyncErrInvalidOp,
+ SyncErrInvalidIn,
+ SyncErrLastIdx
+ } keymgr_sync_error_e;
+
+ typedef enum logic [1:0] {
+ AsyncErrShadowUpdate,
+ AsyncErrLastIdx
+ } keymgr_async_error_e;
+
+ typedef enum logic [1:0] {
+ SyncFaultKmacOp,
+ SyncFaultKmacOut,
+ SyncFaultLastIdx
+ } keymgr_sync_fault_e;
+
+ typedef enum logic [2:0] {
+ AsyncFaultKmacCmd,
+ AsyncFaultKmacFsm,
+ AsyncFaultRegIntg,
+ AsyncFaultShadow,
+ AsyncFaultFsmIntg,
+ AsyncFaultCntErr,
+ AsyncFaultLastIdx
+ } keymgr_async_fault_e;
+
+
// Bit position of error code
// Error is encoded as 1 error per bit
typedef enum logic [2:0] {
ErrInvalidOp,
ErrInvalidIn,
ErrShadowUpdate,
- ErrInvalidStates,
ErrLastPos
} keymgr_err_pos_e;
// Bit position of fault status
typedef enum logic [3:0] {
- FaultCmd,
+ FaultKmacCmd,
FaultKmacFsm,
FaultKmacOp,
FaultKmacOut,
- FaultRegFileIntg,
+ FaultRegIntg,
FaultShadow,
FaultCtrlFsm,
FaultCtrlCnt,
diff --git a/hw/ip/keymgr/rtl/keymgr_reg_pkg.sv b/hw/ip/keymgr/rtl/keymgr_reg_pkg.sv
index 21ffbb0..67a2976 100644
--- a/hw/ip/keymgr/rtl/keymgr_reg_pkg.sv
+++ b/hw/ip/keymgr/rtl/keymgr_reg_pkg.sv
@@ -111,21 +111,6 @@
typedef struct packed {
struct packed {
logic q;
- } invalid_op;
- struct packed {
- logic q;
- } invalid_kmac_input;
- struct packed {
- logic q;
- } invalid_shadow_update;
- struct packed {
- logic q;
- } invalid_states;
- } keymgr_reg2hw_err_code_reg_t;
-
- typedef struct packed {
- struct packed {
- logic q;
} cmd;
struct packed {
logic q;
@@ -203,10 +188,6 @@
logic d;
logic de;
} invalid_shadow_update;
- struct packed {
- logic d;
- logic de;
- } invalid_states;
} keymgr_hw2reg_err_code_reg_t;
typedef struct packed {
@@ -246,36 +227,35 @@
// Register -> HW type
typedef struct packed {
- keymgr_reg2hw_intr_state_reg_t intr_state; // [944:944]
- keymgr_reg2hw_intr_enable_reg_t intr_enable; // [943:943]
- keymgr_reg2hw_intr_test_reg_t intr_test; // [942:941]
- keymgr_reg2hw_alert_test_reg_t alert_test; // [940:937]
- keymgr_reg2hw_control_reg_t control; // [936:929]
- keymgr_reg2hw_sideload_clear_reg_t sideload_clear; // [928:926]
- keymgr_reg2hw_reseed_interval_shadowed_reg_t reseed_interval_shadowed; // [925:910]
- keymgr_reg2hw_sw_binding_regwen_reg_t sw_binding_regwen; // [909:908]
- keymgr_reg2hw_sealing_sw_binding_mreg_t [7:0] sealing_sw_binding; // [907:652]
- keymgr_reg2hw_attest_sw_binding_mreg_t [7:0] attest_sw_binding; // [651:396]
- keymgr_reg2hw_salt_mreg_t [7:0] salt; // [395:140]
- keymgr_reg2hw_key_version_mreg_t [0:0] key_version; // [139:108]
- keymgr_reg2hw_max_creator_key_ver_shadowed_reg_t max_creator_key_ver_shadowed; // [107:76]
- keymgr_reg2hw_max_owner_int_key_ver_shadowed_reg_t max_owner_int_key_ver_shadowed; // [75:44]
- keymgr_reg2hw_max_owner_key_ver_shadowed_reg_t max_owner_key_ver_shadowed; // [43:12]
- keymgr_reg2hw_err_code_reg_t err_code; // [11:8]
+ keymgr_reg2hw_intr_state_reg_t intr_state; // [940:940]
+ keymgr_reg2hw_intr_enable_reg_t intr_enable; // [939:939]
+ keymgr_reg2hw_intr_test_reg_t intr_test; // [938:937]
+ keymgr_reg2hw_alert_test_reg_t alert_test; // [936:933]
+ keymgr_reg2hw_control_reg_t control; // [932:925]
+ keymgr_reg2hw_sideload_clear_reg_t sideload_clear; // [924:922]
+ keymgr_reg2hw_reseed_interval_shadowed_reg_t reseed_interval_shadowed; // [921:906]
+ keymgr_reg2hw_sw_binding_regwen_reg_t sw_binding_regwen; // [905:904]
+ keymgr_reg2hw_sealing_sw_binding_mreg_t [7:0] sealing_sw_binding; // [903:648]
+ keymgr_reg2hw_attest_sw_binding_mreg_t [7:0] attest_sw_binding; // [647:392]
+ keymgr_reg2hw_salt_mreg_t [7:0] salt; // [391:136]
+ keymgr_reg2hw_key_version_mreg_t [0:0] key_version; // [135:104]
+ keymgr_reg2hw_max_creator_key_ver_shadowed_reg_t max_creator_key_ver_shadowed; // [103:72]
+ keymgr_reg2hw_max_owner_int_key_ver_shadowed_reg_t max_owner_int_key_ver_shadowed; // [71:40]
+ keymgr_reg2hw_max_owner_key_ver_shadowed_reg_t max_owner_key_ver_shadowed; // [39:8]
keymgr_reg2hw_fault_status_reg_t fault_status; // [7:0]
} keymgr_reg2hw_t;
// HW -> register type
typedef struct packed {
- keymgr_hw2reg_intr_state_reg_t intr_state; // [564:563]
- keymgr_hw2reg_cfg_regwen_reg_t cfg_regwen; // [562:562]
- keymgr_hw2reg_control_reg_t control; // [561:560]
- keymgr_hw2reg_sw_binding_regwen_reg_t sw_binding_regwen; // [559:559]
- keymgr_hw2reg_sw_share0_output_mreg_t [7:0] sw_share0_output; // [558:295]
- keymgr_hw2reg_sw_share1_output_mreg_t [7:0] sw_share1_output; // [294:31]
- keymgr_hw2reg_working_state_reg_t working_state; // [30:27]
- keymgr_hw2reg_op_status_reg_t op_status; // [26:24]
- keymgr_hw2reg_err_code_reg_t err_code; // [23:16]
+ keymgr_hw2reg_intr_state_reg_t intr_state; // [562:561]
+ keymgr_hw2reg_cfg_regwen_reg_t cfg_regwen; // [560:560]
+ keymgr_hw2reg_control_reg_t control; // [559:558]
+ keymgr_hw2reg_sw_binding_regwen_reg_t sw_binding_regwen; // [557:557]
+ keymgr_hw2reg_sw_share0_output_mreg_t [7:0] sw_share0_output; // [556:293]
+ keymgr_hw2reg_sw_share1_output_mreg_t [7:0] sw_share1_output; // [292:29]
+ keymgr_hw2reg_working_state_reg_t working_state; // [28:25]
+ keymgr_hw2reg_op_status_reg_t op_status; // [24:22]
+ keymgr_hw2reg_err_code_reg_t err_code; // [21:16]
keymgr_hw2reg_fault_status_reg_t fault_status; // [15:0]
} keymgr_hw2reg_t;
diff --git a/hw/ip/keymgr/rtl/keymgr_reg_top.sv b/hw/ip/keymgr/rtl/keymgr_reg_top.sv
index fd3a6d9..d02dd53 100644
--- a/hw/ip/keymgr/rtl/keymgr_reg_top.sv
+++ b/hw/ip/keymgr/rtl/keymgr_reg_top.sv
@@ -297,8 +297,6 @@
logic err_code_invalid_kmac_input_wd;
logic err_code_invalid_shadow_update_qs;
logic err_code_invalid_shadow_update_wd;
- logic err_code_invalid_states_qs;
- logic err_code_invalid_states_wd;
logic fault_status_cmd_qs;
logic fault_status_kmac_fsm_qs;
logic fault_status_kmac_op_qs;
@@ -1983,7 +1981,7 @@
// to internal hardware
.qe (),
- .q (reg2hw.err_code.invalid_op.q),
+ .q (),
// to register interface (read)
.qs (err_code_invalid_op_qs)
@@ -2009,7 +2007,7 @@
// to internal hardware
.qe (),
- .q (reg2hw.err_code.invalid_kmac_input.q),
+ .q (),
// to register interface (read)
.qs (err_code_invalid_kmac_input_qs)
@@ -2035,39 +2033,13 @@
// to internal hardware
.qe (),
- .q (reg2hw.err_code.invalid_shadow_update.q),
+ .q (),
// to register interface (read)
.qs (err_code_invalid_shadow_update_qs)
);
- // F[invalid_states]: 3:3
- prim_subreg #(
- .DW (1),
- .SwAccess(prim_subreg_pkg::SwAccessW1C),
- .RESVAL (1'h0)
- ) u_err_code_invalid_states (
- .clk_i (clk_i),
- .rst_ni (rst_ni),
-
- // from register interface
- .we (err_code_we),
- .wd (err_code_invalid_states_wd),
-
- // from internal hardware
- .de (hw2reg.err_code.invalid_states.de),
- .d (hw2reg.err_code.invalid_states.d),
-
- // to internal hardware
- .qe (),
- .q (reg2hw.err_code.invalid_states.q),
-
- // to register interface (read)
- .qs (err_code_invalid_states_qs)
- );
-
-
// R[fault_status]: V(False)
// F[cmd]: 0:0
@@ -2601,8 +2573,6 @@
assign err_code_invalid_shadow_update_wd = reg_wdata[2];
- assign err_code_invalid_states_wd = reg_wdata[3];
-
// Read data return
always_comb begin
reg_rdata_next = '0;
@@ -2847,7 +2817,6 @@
reg_rdata_next[0] = err_code_invalid_op_qs;
reg_rdata_next[1] = err_code_invalid_kmac_input_qs;
reg_rdata_next[2] = err_code_invalid_shadow_update_qs;
- reg_rdata_next[3] = err_code_invalid_states_qs;
end
addr_hit[59]: begin
diff --git a/sw/device/lib/dif/dif_keymgr.c b/sw/device/lib/dif/dif_keymgr.c
index 3ac3415..e956207 100644
--- a/sw/device/lib/dif/dif_keymgr.c
+++ b/sw/device/lib/dif/dif_keymgr.c
@@ -108,9 +108,6 @@
static_assert(kDifKeymgrStatusCodeInvalidOperation >> 1 ==
1 << KEYMGR_ERR_CODE_INVALID_OP_BIT,
"Layout of ERR_CODE register changed.");
-static_assert(kDifKeymgrStatusCodeInvalidState >> 1 ==
- 1 << KEYMGR_ERR_CODE_INVALID_STATES_BIT,
- "Layout of ERR_CODE register changed.");
static_assert(kDifKeymgrStatusCodeInvalidKmacInput >> 1 ==
1 << KEYMGR_ERR_CODE_INVALID_KMAC_INPUT_BIT,
"Layout of ERR_CODE register changed.");
diff --git a/sw/device/lib/dif/dif_keymgr_unittest.cc b/sw/device/lib/dif/dif_keymgr_unittest.cc
index ba0fd9c..aafbcf5 100644
--- a/sw/device/lib/dif/dif_keymgr_unittest.cc
+++ b/sw/device/lib/dif/dif_keymgr_unittest.cc
@@ -529,14 +529,6 @@
},
GetStatusCodesTestCase{
.reg_val = {{
- .offset = KEYMGR_ERR_CODE_INVALID_STATES_BIT,
- .value = 1,
- }},
- .exp_val = kDifKeymgrStatusCodeIdle |
- kDifKeymgrStatusCodeInvalidState,
- },
- GetStatusCodesTestCase{
- .reg_val = {{
.offset = KEYMGR_ERR_CODE_INVALID_KMAC_INPUT_BIT,
.value = 1,
}},
@@ -555,13 +547,7 @@
.exp_val = kDifKeymgrStatusCodeIdle |
kDifKeymgrStatusCodeInvalidOperation |
kDifKeymgrStatusCodeInvalidKmacInput,
- },
- GetStatusCodesTestCase{.reg_val = {{
- .offset = KEYMGR_ERR_CODE_INVALID_STATES_BIT,
- .value = 1,
- }},
- .exp_val = kDifKeymgrStatusCodeIdle |
- kDifKeymgrStatusCodeInvalidState}));
+ }));
class GetStateTest : public DifKeymgrInitialized {};