[keymgr] Detect spurious done's from kmac as a fault

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 7ce6f19..dbc4099 100644
--- a/hw/ip/keymgr/data/keymgr.hjson
+++ b/hw/ip/keymgr/data/keymgr.hjson
@@ -1030,41 +1030,46 @@
           desc: "The kmac transfer interface is in an error state, asynchronous fault.",
         },
         { bits: "2",
+          name: "KMAC_DONE",
+          resval: "0x0"
+          desc: "The kmac transfer interface encountered unexpected done, asynchronous fault.",
+        },
+        { bits: "3",
           name: "KMAC_OP",
           resval: "0x0"
           desc: "KMAC reported an error during keymgr usage, this should never happen - synchronous fault.",
         },
-        { bits: "3",
+        { bits: "4",
           name: "KMAC_OUT",
           resval: "0x0"
           desc: "KMAC data returned as all 0's or all 1's - synchronous fault",
         },
-        { bits: "4",
+        { bits: "5",
           name: "REGFILE_INTG",
           resval: "0x0"
           desc: "Register file integrity error, asynchronous fault",
         },
-        { bits: "5",
+        { bits: "6",
           name: "SHADOW",
           resval: "0x0"
           desc: "Shadow copy storage error, asynchronous fault",
         },
-        { bits: "6",
+        { bits: "7",
           name: "CTRL_FSM_INTG",
           resval: "0x0"
           desc: "Control FSM integrity error, asynchronous fault",
         },
-        { bits: "7",
+        { bits: "8",
           name: "CTRL_FSM_CNT",
           resval: "0x0"
           desc: "Control FSM counter integrity error, asynchronous fault",
         },
-        { bits: "8",
+        { bits: "9",
           name: "RESEED_CNT",
           resval: "0x0"
           desc: "Reseed counter integrity error, asynchronous fault",
         },
-        { bits: "9",
+        { bits: "10",
           name: "SIDE_CTRL_FSM",
           resval: "0x0"
           desc: "Sideload control FSM integrity error, asynchronous fault",
diff --git a/hw/ip/keymgr/rtl/keymgr.sv b/hw/ip/keymgr/rtl/keymgr.sv
index a76c360..edf6011 100644
--- a/hw/ip/keymgr/rtl/keymgr.sv
+++ b/hw/ip/keymgr/rtl/keymgr.sv
@@ -261,6 +261,7 @@
   logic kmac_cmd_err;
   logic kmac_fsm_err;
   logic kmac_op_err;
+  logic kmac_done_err;
   logic [Shares-1:0][kmac_pkg::AppDigestW-1:0] kmac_data;
   logic [Shares-1:0][KeyWidth-1:0] kmac_data_truncated;
   logic [ErrLastPos-1:0] err_code;
@@ -314,6 +315,7 @@
     .kmac_input_invalid_i(kmac_input_invalid),
     .kmac_fsm_err_i(kmac_fsm_err),
     .kmac_op_err_i(kmac_op_err),
+    .kmac_done_err_i(kmac_done_err),
     .kmac_cmd_err_i(kmac_cmd_err),
     .kmac_data_i(kmac_data_truncated)
   );
@@ -516,6 +518,7 @@
     .entropy_i(data_rand),
     .fsm_error_o(kmac_fsm_err),
     .kmac_error_o(kmac_op_err),
+    .kmac_done_error_o(kmac_done_err),
     .cmd_error_o(kmac_cmd_err)
   );
 
@@ -615,6 +618,7 @@
   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_done.de     = fault_code[FaultKmacDone];
   assign hw2reg.fault_status.kmac_out.de      = fault_code[FaultKmacOut];
   assign hw2reg.fault_status.regfile_intg.de  = fault_code[FaultRegIntg];
   assign hw2reg.fault_status.shadow.de        = fault_code[FaultShadow];
@@ -624,6 +628,7 @@
   assign hw2reg.fault_status.side_ctrl_fsm.de = fault_code[FaultSideFsm];
   assign hw2reg.fault_status.cmd.d            = 1'b1;
   assign hw2reg.fault_status.kmac_fsm.d       = 1'b1;
+  assign hw2reg.fault_status.kmac_done.d      = 1'b1;
   assign hw2reg.fault_status.kmac_op.d        = 1'b1;
   assign hw2reg.fault_status.kmac_out.d       = 1'b1;
   assign hw2reg.fault_status.regfile_intg.d   = 1'b1;
diff --git a/hw/ip/keymgr/rtl/keymgr_ctrl.sv b/hw/ip/keymgr/rtl/keymgr_ctrl.sv
index f656ec9..68bad5f 100644
--- a/hw/ip/keymgr/rtl/keymgr_ctrl.sv
+++ b/hw/ip/keymgr/rtl/keymgr_ctrl.sv
@@ -58,6 +58,7 @@
   input kmac_input_invalid_i, // asserted when selected data fails criteria check
   input kmac_fsm_err_i, // asserted when kmac fsm reaches unexpected state
   input kmac_op_err_i,  // asserted when kmac itself reports an error
+  input kmac_done_err_i,// asserted when kmac unexpectedly toggles done
   input kmac_cmd_err_i, // asserted when more than one command given to kmac
   input [Shares-1:0][KeyWidth-1:0] kmac_data_i,
 
@@ -783,14 +784,15 @@
     end
   end
   assign async_fault = async_fault_q | async_fault_d;
-  assign async_fault_d[AsyncFaultKmacCmd] = kmac_cmd_err_i;
-  assign async_fault_d[AsyncFaultKmacFsm] = kmac_fsm_err_i;
-  assign async_fault_d[AsyncFaultRegIntg] = regfile_intg_err_i;
-  assign async_fault_d[AsyncFaultShadow ] = shadowed_storage_err_i;
-  assign async_fault_d[AsyncFaultFsmIntg] = state_intg_err_q | data_fsm_err;
-  assign async_fault_d[AsyncFaultCntErr ] = cnt_err;
-  assign async_fault_d[AsyncFaultRCntErr] = reseed_cnt_err_i;
-  assign async_fault_d[AsyncFaultSideErr] = sideload_fsm_err_i;
+  assign async_fault_d[AsyncFaultKmacCmd]  = kmac_cmd_err_i;
+  assign async_fault_d[AsyncFaultKmacFsm]  = kmac_fsm_err_i;
+  assign async_fault_d[AsyncFaultKmacDone] = kmac_done_err_i;
+  assign async_fault_d[AsyncFaultRegIntg]  = regfile_intg_err_i;
+  assign async_fault_d[AsyncFaultShadow ]  = shadowed_storage_err_i;
+  assign async_fault_d[AsyncFaultFsmIntg]  = state_intg_err_q | data_fsm_err;
+  assign async_fault_d[AsyncFaultCntErr ]  = cnt_err;
+  assign async_fault_d[AsyncFaultRCntErr]  = reseed_cnt_err_i;
+  assign async_fault_d[AsyncFaultSideErr]  = sideload_fsm_err_i;
 
   // output to error code register
   assign error_o[ErrInvalidOp]    = op_done_o & sync_err[SyncErrInvalidOp];
@@ -802,6 +804,7 @@
   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[FaultKmacDone]  = async_fault[AsyncFaultKmacDone];
   assign fault_o[FaultRegIntg]   = async_fault[AsyncFaultRegIntg];
   assign fault_o[FaultShadow]    = async_fault[AsyncFaultShadow];
   assign fault_o[FaultCtrlFsm]   = async_fault[AsyncFaultFsmIntg];
diff --git a/hw/ip/keymgr/rtl/keymgr_kmac_if.sv b/hw/ip/keymgr/rtl/keymgr_kmac_if.sv
index d25b4ac..77d3946 100644
--- a/hw/ip/keymgr/rtl/keymgr_kmac_if.sv
+++ b/hw/ip/keymgr/rtl/keymgr_kmac_if.sv
@@ -36,6 +36,7 @@
   // error outputs
   output logic fsm_error_o,
   output logic kmac_error_o,
+  output logic kmac_done_error_o,
   output logic cmd_error_o
 );
 
@@ -119,6 +120,7 @@
   logic start;
   logic [3:0] inputs_invalid_d, inputs_invalid_q;
   logic clr_err;
+  logic kmac_done_vld;
 
   data_state_e state_q, state_d;
 
@@ -173,6 +175,9 @@
     .state_o ( state_raw_q )
   );
 
+  // kmac done is asserted outside of expected window
+  assign kmac_done_error_o = ~kmac_done_vld & kmac_data_i.done;
+
   always_comb begin
     cnt_clr = 1'b0;
     cnt_set = 1'b0;
@@ -188,6 +193,8 @@
     fsm_error_o = '0;
     kmac_error_o = '0;
 
+    kmac_done_vld = '0;
+
     unique case (state_q)
 
       StIdle: begin
@@ -243,6 +250,7 @@
       end
 
       StOpWait: begin
+        kmac_done_vld = 1'b1;
         if (kmac_data_i.done) begin
           kmac_error_o = kmac_data_i.error;
           done_o = 1'b1;
@@ -271,16 +279,18 @@
     endcase // unique case (state_q)
 
     // unconditional error transitions
+    // counter errors may disturb the fsm flow and are
+    // treated like fsm errors
     if (cnt_err) begin
       state_d = StError;
     end
   end
 
-  // If an fsm error is detected, there is no guarantee the transaction can completely gracefully.
-  // Allow the transaction to terminate early with random data.
-  assign data_o = start && done_o && !fsm_error_o ? {kmac_data_i.digest_share1,
-                                                     kmac_data_i.digest_share0} :
-                                                    {DecoyOutputCopies{entropy_i[0]}};
+  // when transaction is not complete, populate the data with random
+  assign data_o = start && done_o ?
+                  {kmac_data_i.digest_share1,
+                   kmac_data_i.digest_share0} :
+                  {DecoyOutputCopies{entropy_i[0]}};
 
   // The input invalid check is done whenever transactions are ongoing with kmac
   // once set, it cannot be unset until transactions are fully complete
diff --git a/hw/ip/keymgr/rtl/keymgr_pkg.sv b/hw/ip/keymgr/rtl/keymgr_pkg.sv
index b28c9ce..b5c98c6 100644
--- a/hw/ip/keymgr/rtl/keymgr_pkg.sv
+++ b/hw/ip/keymgr/rtl/keymgr_pkg.sv
@@ -160,6 +160,7 @@
   typedef enum logic [3:0] {
     AsyncFaultKmacCmd,
     AsyncFaultKmacFsm,
+    AsyncFaultKmacDone,
     AsyncFaultRegIntg,
     AsyncFaultShadow,
     AsyncFaultFsmIntg,
@@ -183,6 +184,7 @@
   typedef enum logic [3:0] {
     FaultKmacCmd,
     FaultKmacFsm,
+    FaultKmacDone,
     FaultKmacOp,
     FaultKmacOut,
     FaultRegIntg,
diff --git a/hw/ip/keymgr/rtl/keymgr_reg_pkg.sv b/hw/ip/keymgr/rtl/keymgr_reg_pkg.sv
index a9a0003..7045a2b 100644
--- a/hw/ip/keymgr/rtl/keymgr_reg_pkg.sv
+++ b/hw/ip/keymgr/rtl/keymgr_reg_pkg.sv
@@ -124,6 +124,9 @@
     } kmac_fsm;
     struct packed {
       logic        q;
+    } kmac_done;
+    struct packed {
+      logic        q;
     } kmac_op;
     struct packed {
       logic        q;
@@ -213,6 +216,10 @@
     struct packed {
       logic        d;
       logic        de;
+    } kmac_done;
+    struct packed {
+      logic        d;
+      logic        de;
     } kmac_op;
     struct packed {
       logic        d;
@@ -246,37 +253,37 @@
 
   // Register -> HW type
   typedef struct packed {
-    keymgr_reg2hw_intr_state_reg_t intr_state; // [942:942]
-    keymgr_reg2hw_intr_enable_reg_t intr_enable; // [941:941]
-    keymgr_reg2hw_intr_test_reg_t intr_test; // [940:939]
-    keymgr_reg2hw_alert_test_reg_t alert_test; // [938:935]
-    keymgr_reg2hw_start_reg_t start; // [934:934]
-    keymgr_reg2hw_control_shadowed_reg_t control_shadowed; // [933:927]
-    keymgr_reg2hw_sideload_clear_reg_t sideload_clear; // [926:924]
-    keymgr_reg2hw_reseed_interval_shadowed_reg_t reseed_interval_shadowed; // [923:908]
-    keymgr_reg2hw_sw_binding_regwen_reg_t sw_binding_regwen; // [907:906]
-    keymgr_reg2hw_sealing_sw_binding_mreg_t [7:0] sealing_sw_binding; // [905:650]
-    keymgr_reg2hw_attest_sw_binding_mreg_t [7:0] attest_sw_binding; // [649:394]
-    keymgr_reg2hw_salt_mreg_t [7:0] salt; // [393:138]
-    keymgr_reg2hw_key_version_mreg_t [0:0] key_version; // [137:106]
-    keymgr_reg2hw_max_creator_key_ver_shadowed_reg_t max_creator_key_ver_shadowed; // [105:74]
-    keymgr_reg2hw_max_owner_int_key_ver_shadowed_reg_t max_owner_int_key_ver_shadowed; // [73:42]
-    keymgr_reg2hw_max_owner_key_ver_shadowed_reg_t max_owner_key_ver_shadowed; // [41:10]
-    keymgr_reg2hw_fault_status_reg_t fault_status; // [9:0]
+    keymgr_reg2hw_intr_state_reg_t intr_state; // [943:943]
+    keymgr_reg2hw_intr_enable_reg_t intr_enable; // [942:942]
+    keymgr_reg2hw_intr_test_reg_t intr_test; // [941:940]
+    keymgr_reg2hw_alert_test_reg_t alert_test; // [939:936]
+    keymgr_reg2hw_start_reg_t start; // [935:935]
+    keymgr_reg2hw_control_shadowed_reg_t control_shadowed; // [934:928]
+    keymgr_reg2hw_sideload_clear_reg_t sideload_clear; // [927:925]
+    keymgr_reg2hw_reseed_interval_shadowed_reg_t reseed_interval_shadowed; // [924:909]
+    keymgr_reg2hw_sw_binding_regwen_reg_t sw_binding_regwen; // [908:907]
+    keymgr_reg2hw_sealing_sw_binding_mreg_t [7:0] sealing_sw_binding; // [906:651]
+    keymgr_reg2hw_attest_sw_binding_mreg_t [7:0] attest_sw_binding; // [650:395]
+    keymgr_reg2hw_salt_mreg_t [7:0] salt; // [394:139]
+    keymgr_reg2hw_key_version_mreg_t [0:0] key_version; // [138:107]
+    keymgr_reg2hw_max_creator_key_ver_shadowed_reg_t max_creator_key_ver_shadowed; // [106:75]
+    keymgr_reg2hw_max_owner_int_key_ver_shadowed_reg_t max_owner_int_key_ver_shadowed; // [74:43]
+    keymgr_reg2hw_max_owner_key_ver_shadowed_reg_t max_owner_key_ver_shadowed; // [42:11]
+    keymgr_reg2hw_fault_status_reg_t fault_status; // [10:0]
   } keymgr_reg2hw_t;
 
   // HW -> register type
   typedef struct packed {
-    keymgr_hw2reg_intr_state_reg_t intr_state; // [566:565]
-    keymgr_hw2reg_cfg_regwen_reg_t cfg_regwen; // [564:564]
-    keymgr_hw2reg_start_reg_t start; // [563:562]
-    keymgr_hw2reg_sw_binding_regwen_reg_t sw_binding_regwen; // [561:561]
-    keymgr_hw2reg_sw_share0_output_mreg_t [7:0] sw_share0_output; // [560:297]
-    keymgr_hw2reg_sw_share1_output_mreg_t [7:0] sw_share1_output; // [296:33]
-    keymgr_hw2reg_working_state_reg_t working_state; // [32:29]
-    keymgr_hw2reg_op_status_reg_t op_status; // [28:26]
-    keymgr_hw2reg_err_code_reg_t err_code; // [25:20]
-    keymgr_hw2reg_fault_status_reg_t fault_status; // [19:0]
+    keymgr_hw2reg_intr_state_reg_t intr_state; // [568:567]
+    keymgr_hw2reg_cfg_regwen_reg_t cfg_regwen; // [566:566]
+    keymgr_hw2reg_start_reg_t start; // [565:564]
+    keymgr_hw2reg_sw_binding_regwen_reg_t sw_binding_regwen; // [563:563]
+    keymgr_hw2reg_sw_share0_output_mreg_t [7:0] sw_share0_output; // [562:299]
+    keymgr_hw2reg_sw_share1_output_mreg_t [7:0] sw_share1_output; // [298:35]
+    keymgr_hw2reg_working_state_reg_t working_state; // [34:31]
+    keymgr_hw2reg_op_status_reg_t op_status; // [30:28]
+    keymgr_hw2reg_err_code_reg_t err_code; // [27:22]
+    keymgr_hw2reg_fault_status_reg_t fault_status; // [21:0]
   } keymgr_hw2reg_t;
 
   // Register offsets
diff --git a/hw/ip/keymgr/rtl/keymgr_reg_top.sv b/hw/ip/keymgr/rtl/keymgr_reg_top.sv
index c6897eb..3edcca3 100644
--- a/hw/ip/keymgr/rtl/keymgr_reg_top.sv
+++ b/hw/ip/keymgr/rtl/keymgr_reg_top.sv
@@ -304,6 +304,7 @@
   logic err_code_invalid_shadow_update_wd;
   logic fault_status_cmd_qs;
   logic fault_status_kmac_fsm_qs;
+  logic fault_status_kmac_done_qs;
   logic fault_status_kmac_op_qs;
   logic fault_status_kmac_out_qs;
   logic fault_status_regfile_intg_qs;
@@ -2141,7 +2142,32 @@
     .qs     (fault_status_kmac_fsm_qs)
   );
 
-  //   F[kmac_op]: 2:2
+  //   F[kmac_done]: 2:2
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessRO),
+    .RESVAL  (1'h0)
+  ) u_fault_status_kmac_done (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (1'b0),
+    .wd     ('0),
+
+    // from internal hardware
+    .de     (hw2reg.fault_status.kmac_done.de),
+    .d      (hw2reg.fault_status.kmac_done.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.fault_status.kmac_done.q),
+
+    // to register interface (read)
+    .qs     (fault_status_kmac_done_qs)
+  );
+
+  //   F[kmac_op]: 3:3
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -2166,7 +2192,7 @@
     .qs     (fault_status_kmac_op_qs)
   );
 
-  //   F[kmac_out]: 3:3
+  //   F[kmac_out]: 4:4
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -2191,7 +2217,7 @@
     .qs     (fault_status_kmac_out_qs)
   );
 
-  //   F[regfile_intg]: 4:4
+  //   F[regfile_intg]: 5:5
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -2216,7 +2242,7 @@
     .qs     (fault_status_regfile_intg_qs)
   );
 
-  //   F[shadow]: 5:5
+  //   F[shadow]: 6:6
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -2241,7 +2267,7 @@
     .qs     (fault_status_shadow_qs)
   );
 
-  //   F[ctrl_fsm_intg]: 6:6
+  //   F[ctrl_fsm_intg]: 7:7
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -2266,7 +2292,7 @@
     .qs     (fault_status_ctrl_fsm_intg_qs)
   );
 
-  //   F[ctrl_fsm_cnt]: 7:7
+  //   F[ctrl_fsm_cnt]: 8:8
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -2291,7 +2317,7 @@
     .qs     (fault_status_ctrl_fsm_cnt_qs)
   );
 
-  //   F[reseed_cnt]: 8:8
+  //   F[reseed_cnt]: 9:9
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -2316,7 +2342,7 @@
     .qs     (fault_status_reseed_cnt_qs)
   );
 
-  //   F[side_ctrl_fsm]: 9:9
+  //   F[side_ctrl_fsm]: 10:10
   prim_subreg #(
     .DW      (1),
     .SwAccess(prim_subreg_pkg::SwAccessRO),
@@ -2929,14 +2955,15 @@
       addr_hit[61]: begin
         reg_rdata_next[0] = fault_status_cmd_qs;
         reg_rdata_next[1] = fault_status_kmac_fsm_qs;
-        reg_rdata_next[2] = fault_status_kmac_op_qs;
-        reg_rdata_next[3] = fault_status_kmac_out_qs;
-        reg_rdata_next[4] = fault_status_regfile_intg_qs;
-        reg_rdata_next[5] = fault_status_shadow_qs;
-        reg_rdata_next[6] = fault_status_ctrl_fsm_intg_qs;
-        reg_rdata_next[7] = fault_status_ctrl_fsm_cnt_qs;
-        reg_rdata_next[8] = fault_status_reseed_cnt_qs;
-        reg_rdata_next[9] = fault_status_side_ctrl_fsm_qs;
+        reg_rdata_next[2] = fault_status_kmac_done_qs;
+        reg_rdata_next[3] = fault_status_kmac_op_qs;
+        reg_rdata_next[4] = fault_status_kmac_out_qs;
+        reg_rdata_next[5] = fault_status_regfile_intg_qs;
+        reg_rdata_next[6] = fault_status_shadow_qs;
+        reg_rdata_next[7] = fault_status_ctrl_fsm_intg_qs;
+        reg_rdata_next[8] = fault_status_ctrl_fsm_cnt_qs;
+        reg_rdata_next[9] = fault_status_reseed_cnt_qs;
+        reg_rdata_next[10] = fault_status_side_ctrl_fsm_qs;
       end
 
       default: begin