diff --git a/src/aes/rtl/aes_clp_reg.rdl b/src/aes/rtl/aes_clp_reg.rdl index 7c166359b..d5d1ba31d 100644 --- a/src/aes/rtl/aes_clp_reg.rdl +++ b/src/aes/rtl/aes_clp_reg.rdl @@ -55,6 +55,27 @@ addrmap aes_clp_reg { } AES_VERSION[2]; + /* ---- Entropy Interface Seed ---- */ + reg { + name = "Entropy Interface Seed"; + desc = "After reset and whenever firmware wants to re-initialize the Trivium stream cipher + primitive driving the EDN interface of AES, it has to perform 9 subsequent write + operations to this register to provide the 288-bit state seed for the Trivium + primitive. + It's fine to write the register while AES is busy and even while it's performing a + a reseed operation of the internal PRNGs via the EDN interface. + + Note: Upon reset, the state of the Trivium primitive is initialized to a netlist + constant. The primitive thus always generates the same output after reset. It is the + job of firmware to provide a new state seed after reset."; + + default hw = r; + default sw = w; + default swmod = true; + + field {desc = "Entropy Interface Seed field";} ENTROPY_IF_SEED[32]; + } ENTROPY_IF_SEED @0x00000110; + /* ---- AES Key Vault Control Reg ---- */ kv_read_ctrl_reg AES_KV_RD_KEY_CTRL @0x00000600; kv_status_reg AES_KV_RD_KEY_STATUS; diff --git a/src/aes/rtl/aes_clp_reg.sv b/src/aes/rtl/aes_clp_reg.sv index a37e93462..ca618fff2 100644 --- a/src/aes/rtl/aes_clp_reg.sv +++ b/src/aes/rtl/aes_clp_reg.sv @@ -68,6 +68,7 @@ module aes_clp_reg ( typedef struct packed{ logic [2-1:0]AES_NAME; logic [2-1:0]AES_VERSION; + logic ENTROPY_IF_SEED; logic AES_KV_RD_KEY_CTRL; logic AES_KV_RD_KEY_STATUS; struct packed{ @@ -105,6 +106,7 @@ module aes_clp_reg ( for(int i0=0; i0<2; i0++) begin decoded_reg_strb.AES_VERSION[i0] = cpuif_req_masked & (cpuif_addr == 12'h108 + i0*12'h4); end + decoded_reg_strb.ENTROPY_IF_SEED = cpuif_req_masked & (cpuif_addr == 12'h110); decoded_reg_strb.AES_KV_RD_KEY_CTRL = cpuif_req_masked & (cpuif_addr == 12'h600); decoded_reg_strb.AES_KV_RD_KEY_STATUS = cpuif_req_masked & (cpuif_addr == 12'h604); decoded_reg_strb.intr_block_rf.global_intr_en_r = cpuif_req_masked & (cpuif_addr == 12'h800); @@ -138,6 +140,12 @@ module aes_clp_reg ( // Field logic //-------------------------------------------------------------------------- typedef struct packed{ + struct packed{ + struct packed{ + logic [31:0] next; + logic load_next; + } ENTROPY_IF_SEED; + } ENTROPY_IF_SEED; struct packed{ struct packed{ logic next; @@ -342,6 +350,11 @@ module aes_clp_reg ( field_combo_t field_combo; typedef struct packed{ + struct packed{ + struct packed{ + logic [31:0] value; + } ENTROPY_IF_SEED; + } ENTROPY_IF_SEED; struct packed{ struct packed{ logic value; @@ -491,6 +504,27 @@ module aes_clp_reg ( } field_storage_t; field_storage_t field_storage; + // Field: aes_clp_reg.ENTROPY_IF_SEED.ENTROPY_IF_SEED + always_comb begin + automatic logic [31:0] next_c; + automatic logic load_next_c; + next_c = field_storage.ENTROPY_IF_SEED.ENTROPY_IF_SEED.value; + load_next_c = '0; + if(decoded_reg_strb.ENTROPY_IF_SEED && decoded_req_is_wr) begin // SW write + next_c = (field_storage.ENTROPY_IF_SEED.ENTROPY_IF_SEED.value & ~decoded_wr_biten[31:0]) | (decoded_wr_data[31:0] & decoded_wr_biten[31:0]); + load_next_c = '1; + end + field_combo.ENTROPY_IF_SEED.ENTROPY_IF_SEED.next = next_c; + field_combo.ENTROPY_IF_SEED.ENTROPY_IF_SEED.load_next = load_next_c; + end + + always_ff @(posedge clk) begin + if(field_combo.ENTROPY_IF_SEED.ENTROPY_IF_SEED.load_next) begin + field_storage.ENTROPY_IF_SEED.ENTROPY_IF_SEED.value <= field_combo.ENTROPY_IF_SEED.ENTROPY_IF_SEED.next; + end + end + assign hwif_out.ENTROPY_IF_SEED.ENTROPY_IF_SEED.value = field_storage.ENTROPY_IF_SEED.ENTROPY_IF_SEED.value; + assign hwif_out.ENTROPY_IF_SEED.ENTROPY_IF_SEED.swmod = decoded_reg_strb.ENTROPY_IF_SEED && decoded_req_is_wr; // Field: aes_clp_reg.AES_KV_RD_KEY_CTRL.read_en always_comb begin automatic logic [0:0] next_c; diff --git a/src/aes/rtl/aes_clp_reg_pkg.sv b/src/aes/rtl/aes_clp_reg_pkg.sv index 92018f9e8..822debbc7 100644 --- a/src/aes/rtl/aes_clp_reg_pkg.sv +++ b/src/aes/rtl/aes_clp_reg_pkg.sv @@ -95,6 +95,15 @@ package aes_clp_reg_pkg; aes_clp_reg__intr_block_t__in_t intr_block_rf; } aes_clp_reg__in_t; + typedef struct packed{ + logic [31:0] value; + logic swmod; + } aes_clp_reg__ENTROPY_IF_SEED__ENTROPY_IF_SEED__out_t; + + typedef struct packed{ + aes_clp_reg__ENTROPY_IF_SEED__ENTROPY_IF_SEED__out_t ENTROPY_IF_SEED; + } aes_clp_reg__ENTROPY_IF_SEED__out_t; + typedef struct packed{ logic value; } kv_read_ctrl_reg__read_en__out_t; @@ -142,6 +151,7 @@ package aes_clp_reg_pkg; } aes_clp_reg__intr_block_t__out_t; typedef struct packed{ + aes_clp_reg__ENTROPY_IF_SEED__out_t ENTROPY_IF_SEED; kv_read_ctrl_reg__out_t AES_KV_RD_KEY_CTRL; aes_clp_reg__intr_block_t__out_t intr_block_rf; } aes_clp_reg__out_t; diff --git a/src/aes/rtl/aes_clp_reg_uvm.sv b/src/aes/rtl/aes_clp_reg_uvm.sv index 3c0fa1194..07ae675ef 100644 --- a/src/aes/rtl/aes_clp_reg_uvm.sv +++ b/src/aes/rtl/aes_clp_reg_uvm.sv @@ -64,6 +64,36 @@ package aes_clp_reg_uvm; endfunction : build endclass : aes_clp_reg__AES_VERSION + // Reg - aes_clp_reg::ENTROPY_IF_SEED + class aes_clp_reg__ENTROPY_IF_SEED extends uvm_reg; + protected uvm_reg_data_t m_current; + protected uvm_reg_data_t m_data; + protected bit m_is_read; + + aes_clp_reg__ENTROPY_IF_SEED_bit_cg ENTROPY_IF_SEED_bit_cg[32]; + aes_clp_reg__ENTROPY_IF_SEED_fld_cg fld_cg; + rand uvm_reg_field ENTROPY_IF_SEED; + + function new(string name = "aes_clp_reg__ENTROPY_IF_SEED"); + super.new(name, 32, build_coverage(UVM_CVR_ALL)); + endfunction : new + extern virtual function void sample_values(); + extern protected virtual function void sample(uvm_reg_data_t data, + uvm_reg_data_t byte_en, + bit is_read, + uvm_reg_map map); + + virtual function void build(); + this.ENTROPY_IF_SEED = new("ENTROPY_IF_SEED"); + this.ENTROPY_IF_SEED.configure(this, 32, 0, "WO", 0, 'h0, 0, 1, 0); + if (has_coverage(UVM_CVR_REG_BITS)) begin + foreach(ENTROPY_IF_SEED_bit_cg[bt]) ENTROPY_IF_SEED_bit_cg[bt] = new(); + end + if (has_coverage(UVM_CVR_FIELD_VALS)) + fld_cg = new(); + endfunction : build + endclass : aes_clp_reg__ENTROPY_IF_SEED + // Reg - kv_read_ctrl_reg class kv_read_ctrl_reg extends uvm_reg; protected uvm_reg_data_t m_current; @@ -899,6 +929,7 @@ package aes_clp_reg_uvm; class aes_clp_reg extends uvm_reg_block; rand aes_clp_reg__AES_NAME AES_NAME[2]; rand aes_clp_reg__AES_VERSION AES_VERSION[2]; + rand aes_clp_reg__ENTROPY_IF_SEED ENTROPY_IF_SEED; rand kv_read_ctrl_reg AES_KV_RD_KEY_CTRL; rand kv_status_reg AES_KV_RD_KEY_STATUS; rand aes_clp_reg__intr_block_t intr_block_rf; @@ -923,6 +954,11 @@ package aes_clp_reg_uvm; this.AES_VERSION[i0].build(); this.default_map.add_reg(this.AES_VERSION[i0], 'h108 + i0*'h4); end + this.ENTROPY_IF_SEED = new("ENTROPY_IF_SEED"); + this.ENTROPY_IF_SEED.configure(this); + + this.ENTROPY_IF_SEED.build(); + this.default_map.add_reg(this.ENTROPY_IF_SEED, 'h110); this.AES_KV_RD_KEY_CTRL = new("AES_KV_RD_KEY_CTRL"); this.AES_KV_RD_KEY_CTRL.configure(this); diff --git a/src/aes/rtl/aes_clp_wrapper.sv b/src/aes/rtl/aes_clp_wrapper.sv index faea7efd5..0edc2d4d9 100644 --- a/src/aes/rtl/aes_clp_wrapper.sv +++ b/src/aes/rtl/aes_clp_wrapper.sv @@ -192,8 +192,8 @@ aes_clp_reg aes_clp_reg_inst ( ); edn_pkg::edn_rsp_t edn_i; - -assign edn_i = '{edn_ack:edn_req.edn_req, edn_fips:0, edn_bus:'0}; //FIXME +logic [edn_pkg::ENDPOINT_BUS_WIDTH-1:0] edn_bus; +assign edn_i = '{edn_ack:edn_req.edn_req, edn_fips:0, edn_bus:edn_bus}; //AES Engine aes @@ -211,7 +211,7 @@ aes_inst ( .clk_edn_i(clk), .rst_edn_ni(reset_n), .edn_o(edn_req), - .edn_i(edn_i), //FIXME + .edn_i(edn_i), // Key manager (keymgr) key sideload interface .keymgr_key_i(keymgr_key), //FIXME @@ -319,5 +319,52 @@ always_ff @(posedge clk or negedge reset_n) begin end end +// Entropy interface +// We use a Trivium stream cipher primitive which is parameterized as follows: +// - It takes 32 bits of seed material at a time provided by firmware via the ENTROPY_IF_SEED +// register. To provide the full 288 bits required to reseed the entire Trivium state, firmware +// has to perform 9 subsequent writes to the register. +// - It delivers 32 bits per clock cycle to AES via the EDN interface. AES will repeatedly request +// fresh entropy via this interface. The rate depends on the value of +// CTRL_SHADOWED.PRNG_RESEED_RATE. +// +// Note: Upon reset, the state of the Trivium primitive is initialized to a netlist constant. The +// primitive thus always generates the same output after reset. It is the job of firmware to +// provide a new state seed after reset. +logic [AHB_DATA_WIDTH-1:0] trivium_seed; +logic trivium_seed_en; +always_ff @(posedge clk or negedge reset_n) begin + if (~reset_n) begin + trivium_seed_en <= 1'b0; + end else begin + trivium_seed_en <= hwif_out.ENTROPY_IF_SEED.ENTROPY_IF_SEED.swmod; + end +end +assign trivium_seed = hwif_out.ENTROPY_IF_SEED.ENTROPY_IF_SEED.value; + +calpitra_prim_trivium #( + .OutputWidth (edn_pkg::ENDPOINT_BUS_WIDTH), + .SeedType (prim_trivium_pkg::SeedTypeStatePartial), + .PartialSeedWidth(AHB_DATA_WIDTH) +) +u_caliptra_prim_trivium +( + .clk_i(clk), + .rst_ni(reset_n), + + .en_i (edn_req.edn_req), + .allow_lockup_i ('0), // Not used. + .seed_en_i (trivium_seed_en), + .seed_done_o (), // Not used. + .seed_req_o (), // Not used. + .seed_ack_i (trivium_seed_en), + .seed_key_i ('0), // Not used. + .seed_iv_i ('0), // Not used. + .seed_state_full_i ('0), // Not used. + .seed_state_partial_i(trivium_seed), + + .key_o(edn_bus), + .err_o() +); endmodule \ No newline at end of file