Skip to content

Commit

Permalink
[sram_ctrl] Add RW1C status for scr key rotation
Browse files Browse the repository at this point in the history
This adds a mubi RW1C CSR that indicates whether a scrambling
key has successfully been rotated. Addresses #18663.

Signed-off-by: Michael Schaffner <[email protected]>
  • Loading branch information
msfschaffner committed Jan 18, 2024
1 parent 03a0aaf commit 9e72212
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 22 deletions.
20 changes: 20 additions & 0 deletions hw/ip/sram_ctrl/data/sram_ctrl.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,26 @@
},
]
},
{ name: "SCR_KEY_ROTATED",
desc: "Clearable SRAM key request status.",
swaccess: "rw1c",
hwaccess: "hwo",
fields: [
{ bits: "3:0",
name: "SUCCESS",
mubi: true,
desc: '''
This status register is similar to !!SCR_KEY_VALID with the difference that the status is multibit encoded,
SW clearable and sticky (i.e., HW does not auto-clear the register except during escalation). That way,
SW can use this for a hardened acknowledgement mechanism where it clears the register before requesting a key.

kMultiBitBool4True indicates that a valid scrambling key has been obtained from OTP.
Write kMultiBitBool4True to clear.
''',
resval: false
},
]
},
],

ram: [
Expand Down
42 changes: 34 additions & 8 deletions hw/ip/sram_ctrl/doc/registers.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
<!-- BEGIN CMDGEN util/regtool.py -d ./hw/ip/sram_ctrl/data/sram_ctrl.hjson -->
## Summary of the **`regs`** interface's registers

| Name | Offset | Length | Description |
|:----------------------------------------|:---------|---------:|:---------------------------------------------|
| sram_ctrl.[`ALERT_TEST`](#alert_test) | 0x0 | 4 | Alert Test Register |
| sram_ctrl.[`STATUS`](#status) | 0x4 | 4 | SRAM status register. |
| sram_ctrl.[`EXEC_REGWEN`](#exec_regwen) | 0x8 | 4 | Lock register for execution enable register. |
| sram_ctrl.[`EXEC`](#exec) | 0xc | 4 | Sram execution enable. |
| sram_ctrl.[`CTRL_REGWEN`](#ctrl_regwen) | 0x10 | 4 | Lock register for control register. |
| sram_ctrl.[`CTRL`](#ctrl) | 0x14 | 4 | SRAM ctrl register. |
| Name | Offset | Length | Description |
|:------------------------------------------------|:---------|---------:|:---------------------------------------------|
| sram_ctrl.[`ALERT_TEST`](#alert_test) | 0x0 | 4 | Alert Test Register |
| sram_ctrl.[`STATUS`](#status) | 0x4 | 4 | SRAM status register. |
| sram_ctrl.[`EXEC_REGWEN`](#exec_regwen) | 0x8 | 4 | Lock register for execution enable register. |
| sram_ctrl.[`EXEC`](#exec) | 0xc | 4 | Sram execution enable. |
| sram_ctrl.[`CTRL_REGWEN`](#ctrl_regwen) | 0x10 | 4 | Lock register for control register. |
| sram_ctrl.[`CTRL`](#ctrl) | 0x14 | 4 | SRAM ctrl register. |
| sram_ctrl.[`SCR_KEY_ROTATED`](#scr_key_rotated) | 0x18 | 4 | Clearable SRAM key request status. |

## ALERT_TEST
Alert Test Register
Expand Down Expand Up @@ -174,5 +175,30 @@ can poll its status. Note that requesting a new scrambling key takes ~200 OTP cy
to ~800 CPU cycles (OTP runs at 24MHz, CPU runs at 100MHz). Note that writing 1 to this register while
a key request is pending has no effect.

## SCR_KEY_ROTATED
Clearable SRAM key request status.
- Offset: `0x18`
- Reset default: `0x9`
- Reset mask: `0xf`

### Fields

```wavejson
{"reg": [{"name": "SUCCESS", "bits": 4, "attr": ["rw1c"], "rotate": -90}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 90}}
```

| Bits | Type | Reset | Name |
|:------:|:------:|:-------:|:-------------------------------------|
| 31:4 | | | Reserved |
| 3:0 | rw1c | 0x9 | [SUCCESS](#scr_key_rotated--success) |

### SCR_KEY_ROTATED . SUCCESS
This status register is similar to [`SCR_KEY_VALID`](#scr_key_valid) with the difference that the status is multibit encoded,
SW clearable and sticky (i.e., HW does not auto-clear the register except during escalation). That way,
SW can use this for a hardened acknowledgement mechanism where it clears the register before requesting a key.

kMultiBitBool4True indicates that a valid scrambling key has been obtained from OTP.
Write kMultiBitBool4True to clear.

This interface does not expose any registers.
<!-- END CMDGEN -->
12 changes: 12 additions & 0 deletions hw/ip/sram_ctrl/dv/env/sram_ctrl_scoreboard.sv
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class sram_ctrl_scoreboard #(parameter int AddrWidth = 10) extends cip_base_scor
// local variables

bit [TL_DW-1:0] exp_status = '0;
mubi4_t exp_renew_scr_key = MuBi4False;

bit in_key_req = 0;

Expand Down Expand Up @@ -356,6 +357,7 @@ class sram_ctrl_scoreboard #(parameter int AddrWidth = 10) extends cip_base_scor
exp_status[SramCtrlScrKeySeedValid] = 0;
exp_status[SramCtrlScrKeyValid] = 0;
exp_status[SramCtrlInitDone] = 0;
exp_renew_scr_key = MuBi4False;

// escalation resets the key and nonce back to defaults
reset_key_nonce();
Expand Down Expand Up @@ -439,6 +441,7 @@ class sram_ctrl_scoreboard #(parameter int AddrWidth = 10) extends cip_base_scor

// if we are in escalated state, key_valid and scr_key_seed_valid will remain low
if (status_lc_esc == EscNone) begin
exp_renew_scr_key = MuBi4True;
exp_status[SramCtrlScrKeyValid] = 1;
exp_status[SramCtrlScrKeySeedValid] = seed_valid;
end
Expand Down Expand Up @@ -523,6 +526,11 @@ class sram_ctrl_scoreboard #(parameter int AddrWidth = 10) extends cip_base_scor
void'(ral.ctrl.init.predict(.value(0), .kind(UVM_PREDICT_READ)));
end
end
"renew_scr_key": begin
if (addr_phase_read) begin
void'(ral.renew_scr_key.predict(.value(exp_renew_scr_key), .kind(UVM_PREDICT_READ)));
end
end
default: begin
`uvm_fatal(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name()))
end
Expand All @@ -541,6 +549,9 @@ class sram_ctrl_scoreboard #(parameter int AddrWidth = 10) extends cip_base_scor
mirrored_value[SramCtrlScrKeySeedValid] !=
item.d_data[SramCtrlScrKeySeedValid])) begin
new_key_received = 0;
end else if (csr.get_name() == "renew_scr_key" && new_key_received && (
mirrored_value != item.d_data)) begin
new_key_received = 0;
end else if (csr.get_name() == "status" && init_after_new_key &&
mirrored_value[SramCtrlInitDone] !=
item.d_data[SramCtrlInitDone]) begin
Expand Down Expand Up @@ -571,6 +582,7 @@ class sram_ctrl_scoreboard #(parameter int AddrWidth = 10) extends cip_base_scor
mem_bkdr_scb.reset();
mem_bkdr_scb.update_key(key, nonce);
exp_status = '0;
exp_renew_scr_key = MuBi4False;
write_item_q.delete();
exp_mem[cfg.sram_ral_name].init();

Expand Down
16 changes: 10 additions & 6 deletions hw/ip/sram_ctrl/rtl/sram_ctrl.sv
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ module sram_ctrl
import lc_ctrl_pkg::lc_tx_or_hi;
import lc_ctrl_pkg::lc_tx_inv;
import lc_ctrl_pkg::lc_to_mubi4;
import prim_mubi_pkg::mubi4_t;
import prim_mubi_pkg::mubi8_t;
import prim_mubi_pkg::MuBi4True;
import prim_mubi_pkg::MuBi4False;
import prim_mubi_pkg::mubi8_test_true_strict;

// This is later on pruned to the correct width at the SRAM wrapper interface.
parameter int unsigned Depth = MemSizeRam >> 2;
Expand Down Expand Up @@ -265,6 +270,11 @@ module sram_ctrl
assign hw2reg.status.scr_key_valid.d = key_ack & ~key_req & ~local_esc;
assign hw2reg.status.scr_key_valid.de = key_req | key_ack | local_esc;

// As opposed to scr_key_valid, SW is responsible for clearing this register.
// It is not automatically cleared by HW, except when escalating.
assign hw2reg.scr_key_rotated.d = (key_ack & ~local_esc) ? MuBi4True : MuBi4False;
assign hw2reg.scr_key_rotated.de = key_ack | local_esc;

// Clear this bit on local escalation.
logic key_seed_valid;
assign hw2reg.status.scr_key_seed_valid.d = key_seed_valid & ~local_esc;
Expand Down Expand Up @@ -322,12 +332,6 @@ module sram_ctrl
// SRAM Execution //
////////////////////

import prim_mubi_pkg::mubi4_t;
import prim_mubi_pkg::mubi8_t;
import prim_mubi_pkg::MuBi4True;
import prim_mubi_pkg::MuBi4False;
import prim_mubi_pkg::mubi8_test_true_strict;

mubi4_t en_ifetch;
if (InstrExec) begin : gen_instr_ctrl
lc_tx_t lc_hw_debug_en;
Expand Down
17 changes: 13 additions & 4 deletions hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ package sram_ctrl_reg_pkg;
} init_done;
} sram_ctrl_hw2reg_status_reg_t;

typedef struct packed {
logic [3:0] d;
logic de;
} sram_ctrl_hw2reg_scr_key_rotated_reg_t;

// Register -> HW type for regs interface
typedef struct packed {
sram_ctrl_reg2hw_alert_test_reg_t alert_test; // [14:13]
Expand All @@ -92,7 +97,8 @@ package sram_ctrl_reg_pkg;

// HW -> register type for regs interface
typedef struct packed {
sram_ctrl_hw2reg_status_reg_t status; // [11:0]
sram_ctrl_hw2reg_status_reg_t status; // [16:5]
sram_ctrl_hw2reg_scr_key_rotated_reg_t scr_key_rotated; // [4:0]
} sram_ctrl_regs_hw2reg_t;

// Register offsets for regs interface
Expand All @@ -102,6 +108,7 @@ package sram_ctrl_reg_pkg;
parameter logic [RegsAw-1:0] SRAM_CTRL_EXEC_OFFSET = 5'h c;
parameter logic [RegsAw-1:0] SRAM_CTRL_CTRL_REGWEN_OFFSET = 5'h 10;
parameter logic [RegsAw-1:0] SRAM_CTRL_CTRL_OFFSET = 5'h 14;
parameter logic [RegsAw-1:0] SRAM_CTRL_SCR_KEY_ROTATED_OFFSET = 5'h 18;

// Reset values for hwext registers and their fields for regs interface
parameter logic [0:0] SRAM_CTRL_ALERT_TEST_RESVAL = 1'h 0;
Expand All @@ -114,17 +121,19 @@ package sram_ctrl_reg_pkg;
SRAM_CTRL_EXEC_REGWEN,
SRAM_CTRL_EXEC,
SRAM_CTRL_CTRL_REGWEN,
SRAM_CTRL_CTRL
SRAM_CTRL_CTRL,
SRAM_CTRL_SCR_KEY_ROTATED
} sram_ctrl_regs_id_e;

// Register width information to check illegal writes for regs interface
parameter logic [3:0] SRAM_CTRL_REGS_PERMIT [6] = '{
parameter logic [3:0] SRAM_CTRL_REGS_PERMIT [7] = '{
4'b 0001, // index[0] SRAM_CTRL_ALERT_TEST
4'b 0001, // index[1] SRAM_CTRL_STATUS
4'b 0001, // index[2] SRAM_CTRL_EXEC_REGWEN
4'b 0001, // index[3] SRAM_CTRL_EXEC
4'b 0001, // index[4] SRAM_CTRL_CTRL_REGWEN
4'b 0001 // index[5] SRAM_CTRL_CTRL
4'b 0001, // index[5] SRAM_CTRL_CTRL
4'b 0001 // index[6] SRAM_CTRL_SCR_KEY_ROTATED
};

endpackage
49 changes: 45 additions & 4 deletions hw/ip/sram_ctrl/rtl/sram_ctrl_regs_reg_top.sv
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ module sram_ctrl_regs_reg_top (

// also check for spurious write enables
logic reg_we_err;
logic [5:0] reg_we_check;
logic [6:0] reg_we_check;
prim_reg_we_check #(
.OneHotWidth(6)
.OneHotWidth(7)
) u_prim_reg_we_check (
.clk_i(clk_i),
.rst_ni(rst_ni),
Expand Down Expand Up @@ -144,6 +144,9 @@ module sram_ctrl_regs_reg_top (
logic ctrl_we;
logic ctrl_renew_scr_key_wd;
logic ctrl_init_wd;
logic scr_key_rotated_we;
logic [3:0] scr_key_rotated_qs;
logic [3:0] scr_key_rotated_wd;

// Register instances
// R[alert_test]: V(True)
Expand Down Expand Up @@ -489,8 +492,36 @@ module sram_ctrl_regs_reg_top (
assign reg2hw.ctrl.init.qe = ctrl_qe;


// R[scr_key_rotated]: V(False)
prim_subreg #(
.DW (4),
.SwAccess(prim_subreg_pkg::SwAccessW1C),
.RESVAL (4'h9),
.Mubi (1'b1)
) u_scr_key_rotated (
.clk_i (clk_i),
.rst_ni (rst_ni),

logic [5:0] addr_hit;
// from register interface
.we (scr_key_rotated_we),
.wd (scr_key_rotated_wd),

// from internal hardware
.de (hw2reg.scr_key_rotated.de),
.d (hw2reg.scr_key_rotated.d),

// to internal hardware
.qe (),
.q (),
.ds (),

// to register interface (read)
.qs (scr_key_rotated_qs)
);



logic [6:0] addr_hit;
always_comb begin
addr_hit = '0;
addr_hit[0] = (reg_addr == SRAM_CTRL_ALERT_TEST_OFFSET);
Expand All @@ -499,6 +530,7 @@ module sram_ctrl_regs_reg_top (
addr_hit[3] = (reg_addr == SRAM_CTRL_EXEC_OFFSET);
addr_hit[4] = (reg_addr == SRAM_CTRL_CTRL_REGWEN_OFFSET);
addr_hit[5] = (reg_addr == SRAM_CTRL_CTRL_OFFSET);
addr_hit[6] = (reg_addr == SRAM_CTRL_SCR_KEY_ROTATED_OFFSET);
end

assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
Expand All @@ -511,7 +543,8 @@ module sram_ctrl_regs_reg_top (
(addr_hit[2] & (|(SRAM_CTRL_REGS_PERMIT[2] & ~reg_be))) |
(addr_hit[3] & (|(SRAM_CTRL_REGS_PERMIT[3] & ~reg_be))) |
(addr_hit[4] & (|(SRAM_CTRL_REGS_PERMIT[4] & ~reg_be))) |
(addr_hit[5] & (|(SRAM_CTRL_REGS_PERMIT[5] & ~reg_be)))));
(addr_hit[5] & (|(SRAM_CTRL_REGS_PERMIT[5] & ~reg_be))) |
(addr_hit[6] & (|(SRAM_CTRL_REGS_PERMIT[6] & ~reg_be)))));
end

// Generate write-enables
Expand All @@ -532,6 +565,9 @@ module sram_ctrl_regs_reg_top (
assign ctrl_renew_scr_key_wd = reg_wdata[0];

assign ctrl_init_wd = reg_wdata[1];
assign scr_key_rotated_we = addr_hit[6] & reg_we & !reg_error;

assign scr_key_rotated_wd = reg_wdata[3:0];

// Assign write-enables to checker logic vector.
always_comb begin
Expand All @@ -542,6 +578,7 @@ module sram_ctrl_regs_reg_top (
reg_we_check[3] = exec_gated_we;
reg_we_check[4] = ctrl_regwen_we;
reg_we_check[5] = ctrl_gated_we;
reg_we_check[6] = scr_key_rotated_we;
end

// Read data return
Expand Down Expand Up @@ -578,6 +615,10 @@ module sram_ctrl_regs_reg_top (
reg_rdata_next[1] = '0;
end

addr_hit[6]: begin
reg_rdata_next[3:0] = scr_key_rotated_qs;
end

default: begin
reg_rdata_next = '1;
end
Expand Down

0 comments on commit 9e72212

Please sign in to comment.