[csrng/rtl] sw port data attack check added

For the software port only, the returned genbits will have a repeated data check before genbits are returned to the register interface.

Signed-off-by: Mark Branstad <mark.branstad@wdc.com>
diff --git a/hw/ip/csrng/data/csrng.hjson b/hw/ip/csrng/data/csrng.hjson
index 905e554..bdaf73a 100644
--- a/hw/ip/csrng/data/csrng.hjson
+++ b/hw/ip/csrng/data/csrng.hjson
@@ -316,6 +316,14 @@
                 Writing a zero resets this status bit.
                 '''
         }
+        { bits: "12",
+          name: "CS_BUS_CMP_ALERT",
+          desc: '''
+                This bit is set when the software application port genbits bus value is equal
+                to the prior valid value on the bus, indicating a possible attack.
+                Writing a zero resets this status bit.
+                '''
+        }
       ]
     },
     {
diff --git a/hw/ip/csrng/rtl/csrng_core.sv b/hw/ip/csrng/rtl/csrng_core.sv
index d41656e..c826b30 100644
--- a/hw/ip/csrng/rtl/csrng_core.sv
+++ b/hw/ip/csrng/rtl/csrng_core.sv
@@ -336,6 +336,9 @@
   logic [7:0]              track_sm[16];
   logic [1:0]              sel_track_sm_grp;
 
+  logic                    cs_rdata_capt_vld;
+  logic                    cs_bus_cmp_alert;
+
   logic                    unused_err_code_test_bit;
   logic                    unused_reg2hw_genbits;
   logic                    unused_int_state_val;
@@ -353,6 +356,8 @@
   logic           cs_aes_halt_q, cs_aes_halt_d;
   logic [SeedLen-1:0] entropy_src_seed_q, entropy_src_seed_d;
   logic               entropy_src_fips_q, entropy_src_fips_d;
+  logic [63:0]        cs_rdata_capt_q, cs_rdata_capt_d;
+  logic               cs_rdata_capt_vld_q, cs_rdata_capt_vld_d;
 
   always_ff @(posedge clk_i or negedge rst_ni)
     if (!rst_ni) begin
@@ -368,6 +373,8 @@
       cs_aes_halt_q <= '0;
       entropy_src_seed_q <= '0;
       entropy_src_fips_q <= '0;
+      cs_rdata_capt_q       <= '0;
+      cs_rdata_capt_vld_q   <= '0;
     end else begin
       acmd_q  <= acmd_d;
       shid_q  <= shid_d;
@@ -381,6 +388,8 @@
       cs_aes_halt_q <= cs_aes_halt_d;
       entropy_src_seed_q <= entropy_src_seed_d;
       entropy_src_fips_q <= entropy_src_fips_d;
+      cs_rdata_capt_q       <= cs_rdata_capt_d;
+      cs_rdata_capt_vld_q   <= cs_rdata_capt_vld_d;
     end
 
   //--------------------------------------------
@@ -676,7 +685,10 @@
   };
 
 
-  assign recov_alert_event = cs_enable_pfa || sw_app_enable_pfa || read_int_state_pfa;
+  assign recov_alert_event = cs_enable_pfa ||
+         sw_app_enable_pfa ||
+         read_int_state_pfa ||
+         cs_bus_cmp_alert;
 
   assign recov_alert_o = recov_alert_event;
 
@@ -804,6 +816,32 @@
 
   assign genbits_stage_fips_sw = genbits_stage_fips_sw_q;
 
+
+  //--------------------------------------------
+  // data path integrity check
+  // - a counter measure to software genbits bus tampering
+  // - checks to make sure repeated data sets off
+  //   an alert for sw to handle
+  //--------------------------------------------
+
+  // capture a copy of the genbits data
+  assign cs_rdata_capt_vld = (genbits_stage_vld[NApps-1] && genbits_stage_rdy[NApps-1]);
+
+  assign cs_rdata_capt_d = cs_rdata_capt_vld ? genbits_stage_bus[NApps-1][63:0] : cs_rdata_capt_q;
+
+  assign cs_rdata_capt_vld_d =
+         !cs_enable ? 1'b0 :
+         cs_rdata_capt_vld ? 1'b1 :
+         cs_rdata_capt_vld_q;
+
+  // continuous compare of the entropy data for sw port
+  assign cs_bus_cmp_alert = cs_rdata_capt_vld && cs_rdata_capt_vld_q &&
+         (cs_rdata_capt_q == genbits_stage_bus[NApps-1][63:0]); // only look at 64 bits
+
+  assign hw2reg.recov_alert_sts.cs_bus_cmp_alert.de = cs_bus_cmp_alert;
+  assign hw2reg.recov_alert_sts.cs_bus_cmp_alert.d  = cs_bus_cmp_alert;
+
+
   // HW interface connections (up to 16, numbered 0-14)
   for (genvar hai = 0; hai < (NApps-1); hai = hai+1) begin : gen_app_if
     // cmd req
diff --git a/hw/ip/csrng/rtl/csrng_reg_pkg.sv b/hw/ip/csrng/rtl/csrng_reg_pkg.sv
index 777d48d..400066b 100644
--- a/hw/ip/csrng/rtl/csrng_reg_pkg.sv
+++ b/hw/ip/csrng/rtl/csrng_reg_pkg.sv
@@ -182,6 +182,10 @@
       logic        d;
       logic        de;
     } read_int_state_field_alert;
+    struct packed {
+      logic        d;
+      logic        de;
+    } cs_bus_cmp_alert;
   } csrng_hw2reg_recov_alert_sts_reg_t;
 
   typedef struct packed {
@@ -327,13 +331,13 @@
 
   // HW -> register type
   typedef struct packed {
-    csrng_hw2reg_intr_state_reg_t intr_state; // [187:180]
-    csrng_hw2reg_sw_cmd_sts_reg_t sw_cmd_sts; // [179:176]
-    csrng_hw2reg_genbits_vld_reg_t genbits_vld; // [175:174]
-    csrng_hw2reg_genbits_reg_t genbits; // [173:142]
-    csrng_hw2reg_int_state_val_reg_t int_state_val; // [141:110]
-    csrng_hw2reg_hw_exc_sts_reg_t hw_exc_sts; // [109:94]
-    csrng_hw2reg_recov_alert_sts_reg_t recov_alert_sts; // [93:88]
+    csrng_hw2reg_intr_state_reg_t intr_state; // [189:182]
+    csrng_hw2reg_sw_cmd_sts_reg_t sw_cmd_sts; // [181:178]
+    csrng_hw2reg_genbits_vld_reg_t genbits_vld; // [177:176]
+    csrng_hw2reg_genbits_reg_t genbits; // [175:144]
+    csrng_hw2reg_int_state_val_reg_t int_state_val; // [143:112]
+    csrng_hw2reg_hw_exc_sts_reg_t hw_exc_sts; // [111:96]
+    csrng_hw2reg_recov_alert_sts_reg_t recov_alert_sts; // [95:88]
     csrng_hw2reg_err_code_reg_t err_code; // [87:36]
     csrng_hw2reg_tracking_sm_obs_reg_t tracking_sm_obs; // [35:0]
   } csrng_hw2reg_t;
@@ -408,7 +412,7 @@
     4'b 0001, // index[10] CSRNG_INT_STATE_NUM
     4'b 1111, // index[11] CSRNG_INT_STATE_VAL
     4'b 0011, // index[12] CSRNG_HW_EXC_STS
-    4'b 0001, // index[13] CSRNG_RECOV_ALERT_STS
+    4'b 0011, // index[13] CSRNG_RECOV_ALERT_STS
     4'b 1111, // index[14] CSRNG_ERR_CODE
     4'b 0001, // index[15] CSRNG_ERR_CODE_TEST
     4'b 0001, // index[16] CSRNG_SEL_TRACKING_SM
diff --git a/hw/ip/csrng/rtl/csrng_reg_top.sv b/hw/ip/csrng/rtl/csrng_reg_top.sv
index cee589c..96c4861 100644
--- a/hw/ip/csrng/rtl/csrng_reg_top.sv
+++ b/hw/ip/csrng/rtl/csrng_reg_top.sv
@@ -168,6 +168,8 @@
   logic recov_alert_sts_sw_app_enable_field_alert_wd;
   logic recov_alert_sts_read_int_state_field_alert_qs;
   logic recov_alert_sts_read_int_state_field_alert_wd;
+  logic recov_alert_sts_cs_bus_cmp_alert_qs;
+  logic recov_alert_sts_cs_bus_cmp_alert_wd;
   logic err_code_sfifo_cmd_err_qs;
   logic err_code_sfifo_genbits_err_qs;
   logic err_code_sfifo_cmdreq_err_qs;
@@ -866,6 +868,31 @@
     .qs     (recov_alert_sts_read_int_state_field_alert_qs)
   );
 
+  //   F[cs_bus_cmp_alert]: 12:12
+  prim_subreg #(
+    .DW      (1),
+    .SwAccess(prim_subreg_pkg::SwAccessW0C),
+    .RESVAL  (1'h0)
+  ) u_recov_alert_sts_cs_bus_cmp_alert (
+    .clk_i   (clk_i),
+    .rst_ni  (rst_ni),
+
+    // from register interface
+    .we     (recov_alert_sts_we),
+    .wd     (recov_alert_sts_cs_bus_cmp_alert_wd),
+
+    // from internal hardware
+    .de     (hw2reg.recov_alert_sts.cs_bus_cmp_alert.de),
+    .d      (hw2reg.recov_alert_sts.cs_bus_cmp_alert.d),
+
+    // to internal hardware
+    .qe     (),
+    .q      (),
+
+    // to register interface (read)
+    .qs     (recov_alert_sts_cs_bus_cmp_alert_qs)
+  );
+
 
   // R[err_code]: V(False)
   //   F[sfifo_cmd_err]: 0:0
@@ -1782,6 +1809,8 @@
   assign recov_alert_sts_sw_app_enable_field_alert_wd = reg_wdata[1];
 
   assign recov_alert_sts_read_int_state_field_alert_wd = reg_wdata[2];
+
+  assign recov_alert_sts_cs_bus_cmp_alert_wd = reg_wdata[12];
   assign err_code_test_we = addr_hit[15] & reg_we & !reg_error;
 
   assign err_code_test_wd = reg_wdata[4:0];
@@ -1863,6 +1892,7 @@
         reg_rdata_next[0] = recov_alert_sts_enable_field_alert_qs;
         reg_rdata_next[1] = recov_alert_sts_sw_app_enable_field_alert_qs;
         reg_rdata_next[2] = recov_alert_sts_read_int_state_field_alert_qs;
+        reg_rdata_next[12] = recov_alert_sts_cs_bus_cmp_alert_qs;
       end
 
       addr_hit[14]: begin