[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 {};