Skip to content

Commit

Permalink
hw-model-verilator: Set SRAM to random PUF state on start. (#1064)
Browse files Browse the repository at this point in the history
To simulate the worst-case power-on behavior of real SRAM, this will trigger ECC errors if firmware tries to read from uninitialized memory. Addresses #1041
  • Loading branch information
korran authored Nov 14, 2023
1 parent 9af061e commit ec9c7f9
Show file tree
Hide file tree
Showing 16 changed files with 274 additions and 15 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions builder/src/firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ pub mod hw_model_tests {
..BASE_FWID
};

pub const TEST_UNITIALIZED_READ: FwId = FwId {
bin_name: "test_uninitialized_read",
..BASE_FWID
};

pub const TEST_PCR_EXTEND: FwId = FwId {
bin_name: "test_pcr_extend",
..BASE_FWID
Expand Down Expand Up @@ -353,6 +358,7 @@ pub const REGISTERED_FW: &[&FwId] = &[
&hw_model_tests::TEST_WRITE_TO_ROM,
&hw_model_tests::TEST_ICCM_DOUBLE_BIT_ECC,
&hw_model_tests::TEST_DCCM_DOUBLE_BIT_ECC,
&hw_model_tests::TEST_UNITIALIZED_READ,
&hw_model_tests::TEST_PCR_EXTEND,
&driver_tests::DOE,
&driver_tests::ECC384,
Expand Down
24 changes: 16 additions & 8 deletions drivers/tests/drivers_integration_tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,20 @@ use openssl::{hash::MessageDigest, pkey::PKey};
use ureg::ResettableReg;
use zerocopy::{AsBytes, FromBytes};

fn default_init_params() -> InitParams<'static> {
InitParams {
// The test harness doesn't clear memory on startup.
random_sram_puf: false,
..Default::default()
}
}

fn start_driver_test(test_rom: &'static FwId) -> Result<DefaultHwModel, Box<dyn Error>> {
let rom = caliptra_builder::build_firmware_rom(test_rom)?;
caliptra_hw_model::new(BootParams {
init_params: InitParams {
rom: &rom,
..Default::default()
..default_init_params()
},
..Default::default()
})
Expand Down Expand Up @@ -205,7 +213,7 @@ fn test_doe_when_debug_not_locked() {
security_state: *SecurityState::from(0)
.set_debug_locked(false)
.set_device_lifecycle(DeviceLifecycle::Unprovisioned),
..Default::default()
..default_init_params()
},
..Default::default()
})
Expand Down Expand Up @@ -299,7 +307,7 @@ fn test_doe_when_debug_locked() {
security_state: *SecurityState::from(0)
.set_debug_locked(true)
.set_device_lifecycle(DeviceLifecycle::Unprovisioned),
..Default::default()
..default_init_params()
},
..Default::default()
})
Expand Down Expand Up @@ -781,7 +789,7 @@ fn test_csrng_with_nibbles(
init_params: InitParams {
rom: &rom,
itrng_nibbles,
..Default::default()
..default_init_params()
},
..Default::default()
})
Expand Down Expand Up @@ -850,7 +858,7 @@ fn test_csrng_repetition_count() {
init_params: InitParams {
rom: &rom,
itrng_nibbles,
..Default::default()
..default_init_params()
},
initial_repcnt_thresh_reg: soc_repcnt_threshold,
..Default::default()
Expand Down Expand Up @@ -972,7 +980,7 @@ fn test_csrng_adaptive_proportion() {
init_params: InitParams {
rom: &rom,
itrng_nibbles,
..Default::default()
..default_init_params()
},
initial_adaptp_thresh_reg: Some(threshold_reg),
..Default::default()
Expand Down Expand Up @@ -1013,7 +1021,7 @@ fn test_trng_in_itrng_mode() {
rom: &rom,
itrng_nibbles: Box::new(trng_nibbles()),
trng_mode: Some(TrngMode::Internal),
..Default::default()
..default_init_params()
},
..Default::default()
})
Expand Down Expand Up @@ -1081,7 +1089,7 @@ fn test_trng_in_etrng_mode() {
.into_iter(),
),
trng_mode: Some(TrngMode::External),
..Default::default()
..default_init_params()
},
..Default::default()
})
Expand Down
1 change: 1 addition & 0 deletions hw-latest/verilated/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ verilator = []
itrng = []

[dependencies]
rand.workspace = true
11 changes: 11 additions & 0 deletions hw-latest/verilated/caliptra_verilated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ void caliptra_verilated_eval(struct caliptra_verilated* model,
v->ext_imem_addr = in->imem_addr;
v->ext_imem_wdata = in->imem_wdata;

v->ext_dccm_we = in->ext_dccm_we;
v->ext_iccm_we = in->ext_iccm_we;
v->ext_mbox_we = in->ext_mbox_we;
v->ext_xccm_addr = in->ext_xccm_addr;
v->ext_xccm_wdata[0] = in->ext_xccm_wdata[0];
v->ext_xccm_wdata[1] = in->ext_xccm_wdata[1];
v->ext_xccm_wdata[2] = in->ext_xccm_wdata[2];
v->ext_xccm_wdata[3] = in->ext_xccm_wdata[3];
v->ext_xccm_wdata[4] = in->ext_xccm_wdata[4];

v->itrng_data = in->itrng_data;
v->itrng_valid = in->itrng_valid;

Expand Down Expand Up @@ -98,3 +108,4 @@ void caliptra_verilated_eval(struct caliptra_verilated* model,
out->uc_hready = v->uc_hready;
out->uc_hresp = v->uc_hresp;
}

7 changes: 7 additions & 0 deletions hw-latest/verilated/caliptra_verilated.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ struct caliptra_verilated_sig_in {
bool itrng_valid;

uint8_t sram_error_injection_mode;

bool ext_iccm_we;
bool ext_dccm_we;
bool ext_mbox_we;
uint32_t ext_xccm_addr;
// 4 39-bit ECC words shoved together
uint32_t ext_xccm_wdata[5];
};

struct caliptra_verilated_sig_out {
Expand Down
35 changes: 28 additions & 7 deletions hw-latest/verilated/caliptra_verilated.sv
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ module caliptra_verilated (
input bit [`CALIPTRA_IMEM_ADDR_WIDTH-1:0] ext_imem_addr,
input bit [`CALIPTRA_IMEM_DATA_WIDTH-1:0] ext_imem_wdata,

input bit ext_iccm_we,
input bit ext_dccm_we,
input bit ext_mbox_we,
input bit [14:0] ext_xccm_addr,
input bit [155:0] ext_xccm_wdata,

input bit [7:0][31:0] cptra_obf_key,

input bit [3:0] security_state,
Expand Down Expand Up @@ -101,7 +107,7 @@ module caliptra_verilated (
logic [MBOX_DATA_AND_ECC_W-1:0] mbox_sram_wdata_bitflip;
logic [MBOX_DATA_AND_ECC_W-1:0] mbox_sram_rdata;

el2_mem_if el2_mem_export ();
el2_mem_if cpu_mem ();


initial begin
Expand Down Expand Up @@ -140,7 +146,7 @@ caliptra_top caliptra_top_dut (
.qspi_d_o(),
.qspi_d_en_o(),

.el2_mem_export(el2_mem_export.veer_sram_src),
.el2_mem_export(cpu_mem.veer_sram_src),

.ready_for_fuses(ready_for_fuses),
.ready_for_fw_push(ready_for_fw_push),
Expand Down Expand Up @@ -199,11 +205,26 @@ assign veer_sram_error_injection_mode.iccm_double_bit_error = sram_error_injecti
assign veer_sram_error_injection_mode.dccm_single_bit_error = sram_error_injection_mode[2];
assign veer_sram_error_injection_mode.dccm_double_bit_error = sram_error_injection_mode[3];

el2_mem_if real_mem();

caliptra_veer_sram_export veer_sram_export_inst (
.sram_error_injection_mode(sram_error_injection_mode),
.el2_mem_export(el2_mem_export.veer_sram_sink)
.el2_mem_export(real_mem.veer_sram_sink)
);

assign real_mem.clk = core_clk;
assign real_mem.iccm_clken = cpu_mem.iccm_clken | ext_iccm_we;
assign real_mem.iccm_wren_bank = cpu_mem.iccm_wren_bank | ext_iccm_we;
assign real_mem.iccm_addr_bank = ext_iccm_we ? {ext_xccm_addr[12:0], ext_xccm_addr[12:0], ext_xccm_addr[12:0], ext_xccm_addr[12:0]} : cpu_mem.iccm_addr_bank;
assign real_mem.iccm_bank_wr_data = ext_iccm_we ? ext_xccm_wdata : cpu_mem.iccm_bank_wr_data;
assign cpu_mem.iccm_bank_dout = real_mem.iccm_bank_dout;

assign real_mem.dccm_clken = cpu_mem.dccm_clken | ext_dccm_we;
assign real_mem.dccm_wren_bank = cpu_mem.dccm_wren_bank | ext_dccm_we;
assign real_mem.dccm_addr_bank = ext_dccm_we ? {ext_xccm_addr[12:0], ext_xccm_addr[12:0], ext_xccm_addr[12:0], ext_xccm_addr[12:0]} : cpu_mem.dccm_addr_bank;
assign real_mem.dccm_wr_data_bank = ext_dccm_we ? ext_xccm_wdata : cpu_mem.dccm_wr_data_bank;
assign cpu_mem.dccm_bank_dout = real_mem.dccm_bank_dout;

//SRAM for mbox (preload raw data here)
caliptra_sram
#(
Expand Down Expand Up @@ -231,10 +252,10 @@ mbox_ram1
(
.clk_i(core_clk),

.cs_i(mbox_sram_cs),
.we_i(mbox_sram_we),
.addr_i(mbox_sram_addr),
.wdata_i(mbox_sram_wdata ^ mbox_sram_wdata_bitflip),
.cs_i(mbox_sram_cs | ext_mbox_we),
.we_i(mbox_sram_we | ext_mbox_we),
.addr_i(ext_mbox_we ? ext_xccm_addr : mbox_sram_addr),
.wdata_i(ext_mbox_we ? ext_xccm_wdata[38:0] : mbox_sram_wdata ^ mbox_sram_wdata_bitflip),

.rdata_o(mbox_sram_rdata)
);
Expand Down
5 changes: 5 additions & 0 deletions hw-latest/verilated/src/bindings/real.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ pub struct caliptra_verilated_sig_in {
pub itrng_data: u8,
pub itrng_valid: bool,
pub sram_error_injection_mode: u8,
pub ext_iccm_we: bool,
pub ext_dccm_we: bool,
pub ext_mbox_we: bool,
pub ext_xccm_addr: u32,
pub ext_xccm_wdata: [u32; 5usize],
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
Expand Down
21 changes: 21 additions & 0 deletions hw-latest/verilated/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::ptr::null;
pub use bindings::caliptra_verilated_init_args as InitArgs;
pub use bindings::caliptra_verilated_sig_in as SigIn;
pub use bindings::caliptra_verilated_sig_out as SigOut;
use rand::Rng;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AhbTxnType {
Expand Down Expand Up @@ -101,6 +102,26 @@ impl CaliptraVerilated {
}
}

fn iccm_dccm_mbox_write(&mut self, addr: u32, data: [u32; 5]) {
self.input.ext_dccm_we = true;
self.input.ext_iccm_we = true;
self.input.ext_mbox_we = true;
self.input.ext_xccm_addr = addr;
self.input.ext_xccm_wdata = data;

self.next_cycle_high(1);
self.input.ext_dccm_we = false;
self.input.ext_iccm_we = false;
self.input.ext_mbox_we = false;
}

pub fn init_random_puf_state(&mut self, rng: &mut impl Rng) {
// Randomize all of ICCM and DCCM, first 32k of mailbox
for addr in 0..8192 {
self.iccm_dccm_mbox_write(addr, rng.gen::<[u32; 5]>());
}
}

/// Returns the total number of cycles since simulation start
pub fn total_cycles(&self) -> u64 {
self.total_cycles
Expand Down
22 changes: 22 additions & 0 deletions hw-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ pub struct InitParams<'a> {

pub wdt_timeout_cycles: u64,

// If true (and the HwModel supports it), initialize the SRAM with random
// data. This will likely result in a ECC double-bit error if the CPU
// attempts to read uninitialized memory.
pub random_sram_puf: bool,

// A trace path to use. If None, the CPTRA_TRACE_PATH environment variable
// will be used
pub trace_path: Option<PathBuf>,
Expand Down Expand Up @@ -180,6 +185,7 @@ impl<'a> Default for InitParams<'a> {
etrng_responses,
trng_mode: Default::default(),
wdt_timeout_cycles: EXPECTED_CALIPTRA_BOOT_TIME_IN_CYCLES,
random_sram_puf: true,
trace_path: None,
}
}
Expand Down Expand Up @@ -560,6 +566,22 @@ pub trait HwModel {
}
}

fn step_until_exit_failure(&mut self) -> std::io::Result<()> {
loop {
match self.output().exit_status() {
Some(ExitStatus::Failed) => return Ok(()),
Some(ExitStatus::Passed) => {
return Err(std::io::Error::new(
ErrorKind::Other,
"firmware exited with success when failure was expected",
))
}
None => {}
}
self.step();
}
}

/// Execute until the output buffer starts with `expected_output`
fn step_until_output(&mut self, expected_output: &str) -> Result<(), Box<dyn Error>> {
self.step_until(|m| m.output().peek().len() >= expected_output.len());
Expand Down
4 changes: 4 additions & 0 deletions hw-model/src/model_verilated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ impl crate::HwModel for ModelVerilated {

m.tracing_hint(true);

if params.random_sram_puf {
m.v.init_random_puf_state(&mut rand::thread_rng());
}

m.v.input.cptra_pwrgood = true;
m.v.next_cycle_high(1);

Expand Down
5 changes: 5 additions & 0 deletions hw-model/test-fw/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ name = "test_dccm_double_bit_ecc"
path = "test_dccm_double_bit_ecc.rs"
required-features = ["riscv"]

[[bin]]
name = "test_uninitialized_read"
path = "test_uninitialized_read.rs"
required-features = ["riscv"]

[[bin]]
name = "test_pcr_extend"
path = "test_pcr_extend.rs"
Expand Down
41 changes: 41 additions & 0 deletions hw-model/test-fw/test_uninitialized_read.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Licensed under the Apache-2.0 license

#![no_main]
#![no_std]

use caliptra_registers::{self, mbox::MboxCsr, soc_ifc::SocIfcReg};

// Needed to bring in startup code
#[allow(unused)]
use caliptra_test_harness;

#[panic_handler]
pub fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}

#[no_mangle]
extern "C" fn main() {
let mut mbox = unsafe { MboxCsr::new() };
let mut soc_ifc = unsafe { SocIfcReg::new() };

let ptr = soc_ifc.regs_mut().cptra_rsvd_reg().at(0).read() as *const u32;
let size = soc_ifc.regs_mut().cptra_rsvd_reg().at(1).read() as usize;

// Lock the mailbox so we can access the mailbox SRAM if necessary
mbox.regs_mut().lock().read();

let mut i = 0;
while i < size / 4 {
unsafe { ptr.add(i).read_volatile() };
i += 1;
}

// Exit success
soc_ifc
.regs_mut()
.cptra_generic_output_wires()
.at(0)
.write(|_| 0xff);
loop {}
}
Loading

0 comments on commit ec9c7f9

Please sign in to comment.