Skip to content

Commit

Permalink
Enhance PAUSER tests (#1667)
Browse files Browse the repository at this point in the history
* - Modify HwModel  trait so it boots with a set of  five valid pausers for all supported model types.
- Add a negative test to ascertain that , when FpgaRealTime is selected, a  SIGBUS is raised if an invalid
  PAUSER tries to access the mailbox.

* Use a Vec<u32> to store valid pausers

* Add SocManager trait definition to the newly created test
  • Loading branch information
rusty1968 authored Oct 22, 2024
1 parent a9ad8a6 commit f102017
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 11 deletions.
6 changes: 6 additions & 0 deletions hw-model/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,9 @@ caliptra-image-types.workspace = true
caliptra-builder.workspace = true
caliptra-registers.workspace = true
caliptra-test-harness-types.workspace = true
nix.workspace = true

[[bin]]
name = "fpga_realtime_mbox_pauser"
path = "src/bin/fpga_realtime_mbox_pauser.rs"
required-features = ["fpga_realtime", "itrng"]
116 changes: 116 additions & 0 deletions hw-model/src/bin/fpga_realtime_mbox_pauser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Licensed under the Apache-2.0 license

use caliptra_hw_model::{mmio::Rv32GenMmio, HwModel, InitParams};
use nix::sys::signal;
use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet};
use std::process::exit;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;

use caliptra_api::soc_mgr::SocManager;
use caliptra_registers::soc_ifc;

fn gen_image_hi() -> Vec<u8> {
let rv32_gen = Rv32GenMmio::new();
let soc_ifc =
unsafe { soc_ifc::RegisterBlock::new_with_mmio(0x3003_0000 as *mut u32, &rv32_gen) };
soc_ifc
.cptra_generic_output_wires()
.at(0)
.write(|_| b'h'.into());
soc_ifc
.cptra_generic_output_wires()
.at(0)
.write(|_| b'i'.into());
soc_ifc
.cptra_generic_output_wires()
.at(0)
.write(|_| 0x100 | u32::from(b'i'));
soc_ifc.cptra_generic_output_wires().at(0).write(|_| 0xff);
rv32_gen.into_inner().empty_loop().build()
}

// Atomic flag to indicate if SIGBUS was received
static SIGBUS_RECEIVED: AtomicBool = AtomicBool::new(false);

// Signal handler function
extern "C" fn handle_sigbus(_: i32) {
SIGBUS_RECEIVED.store(true, Ordering::SeqCst);
}

fn main() {
println!("Setup signal handler...");
// Define the signal action
let sig_action = SigAction::new(
SigHandler::Handler(handle_sigbus),
SaFlags::empty(),
SigSet::empty(),
);

// Set the signal handler for SIGBUS
unsafe {
signal::sigaction(signal::Signal::SIGBUS, &sig_action)
.expect("Failed to set SIGBUS handler");
}

// Spawn a thread that causes a SIGBUS error
thread::spawn(|| {
// Sleep for a short duration to ensure the main thread is ready
thread::sleep(Duration::from_secs(2));

let mut model = caliptra_hw_model::new_unbooted(InitParams {
rom: &gen_image_hi(),
..Default::default()
})
.unwrap();

model.soc_ifc().cptra_fuse_wr_done().write(|w| w.done(true));
model.soc_ifc().cptra_bootfsm_go().write(|w| w.go(true));

// Set up the PAUSER as valid for the mailbox (using index 0)
model
.soc_ifc()
.cptra_mbox_valid_pauser()
.at(0)
.write(|_| 0x1);
model
.soc_ifc()
.cptra_mbox_pauser_lock()
.at(0)
.write(|w| w.lock(true));

// Set the PAUSER to something invalid
model.set_apb_pauser(0x2);

// The accesses below trigger sigbus
assert!(!model.soc_mbox().lock().read().lock());
// Should continue to read 0 because the reads are being blocked by valid PAUSER
assert!(!model.soc_mbox().lock().read().lock());

// Set the PAUSER back to valid
model.set_apb_pauser(0x1);

// Should read 0 the first time still for lock available
assert!(!model.soc_mbox().lock().read().lock());
// Should read 1 now for lock taken
assert!(model.soc_mbox().lock().read().lock());

model.soc_mbox().cmd().write(|_| 4242);

assert_eq!(model.soc_mbox().cmd().read(), 4242);
// Continue with the rest of your program
println!("Continuing execution...");
});

// Simulate some work in the main thread
loop {
if SIGBUS_RECEIVED.load(Ordering::SeqCst) {
println!("Received SIGBUS signal!");
// Handle the SIGBUS signal here
exit(42);
}
println!("Working...");
thread::sleep(Duration::from_secs(1));
}
}
27 changes: 16 additions & 11 deletions hw-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ pub type DefaultHwModel = ModelVerilated;
#[cfg(feature = "fpga_realtime")]
pub type DefaultHwModel = ModelFpgaRealtime;

pub const DEFAULT_APB_PAUSER: u32 = 0x01;

/// Constructs an HwModel based on the cargo features and environment
/// variables. Most test cases that need to construct a HwModel should use this
/// function over HwModel::new_unbooted().
Expand Down Expand Up @@ -252,7 +254,7 @@ pub struct BootParams<'a> {
pub initial_dbg_manuf_service_reg: u32,
pub initial_repcnt_thresh_reg: Option<CptraItrngEntropyConfig1WriteVal>,
pub initial_adaptp_thresh_reg: Option<CptraItrngEntropyConfig0WriteVal>,
pub valid_pauser: u32,
pub valid_pauser: Vec<u32>,
pub wdt_timeout_cycles: u64,
}

Expand All @@ -264,7 +266,7 @@ impl<'a> Default for BootParams<'a> {
initial_dbg_manuf_service_reg: Default::default(),
initial_repcnt_thresh_reg: Default::default(),
initial_adaptp_thresh_reg: Default::default(),
valid_pauser: 0x1,
valid_pauser: vec![0, 1, 2, 3, 4],
wdt_timeout_cycles: EXPECTED_CALIPTRA_BOOT_TIME_IN_CYCLES,
}
}
Expand Down Expand Up @@ -514,15 +516,18 @@ pub trait HwModel: SocManager {
.write(|_| reg);
}

// Set up the PAUSER as valid for the mailbox (using index 0)
self.soc_ifc()
.cptra_mbox_valid_pauser()
.at(0)
.write(|_| boot_params.valid_pauser);
self.soc_ifc()
.cptra_mbox_pauser_lock()
.at(0)
.write(|w| w.lock(true));
{
for idx in 0..boot_params.valid_pauser.len() {
self.soc_ifc()
.cptra_mbox_valid_pauser()
.at(idx)
.write(|_| boot_params.valid_pauser[idx]);
self.soc_ifc()
.cptra_mbox_pauser_lock()
.at(idx)
.write(|w| w.lock(true));
}
}

writeln!(self.output().logger(), "writing to cptra_bootfsm_go")?;
self.soc_ifc().cptra_bootfsm_go().write(|w| w.go(true));
Expand Down
48 changes: 48 additions & 0 deletions hw-model/tests/model_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,27 @@ use caliptra_hw_model::{BootParams, DefaultHwModel, HwModel, InitParams};
use caliptra_hw_model_types::ErrorInjectionMode;
use caliptra_test_harness_types as harness;

#[cfg(feature = "fpga_realtime")]
use std::process::{Child, Command};
#[cfg(feature = "fpga_realtime")]
use std::thread;
#[cfg(feature = "fpga_realtime")]
use std::time::{Duration, Instant};

#[cfg(feature = "fpga_realtime")]
fn wait_with_timeout(child: &mut Child, timeout: Duration) -> Option<i32> {
let start = Instant::now();
while start.elapsed() < timeout {
match child.try_wait() {
Ok(Some(status)) => return status.code(),
Ok(None) => thread::sleep(Duration::from_millis(100)), // Check every 100ms
Err(_) => return None,
}
}
let _ = child.kill();
None
}

fn run_fw_elf(elf: &[u8]) -> DefaultHwModel {
let rom = caliptra_builder::elf2rom(elf).unwrap();
let model = caliptra_hw_model::new(
Expand Down Expand Up @@ -272,3 +293,30 @@ fn test_pcr_extend() {

model.step_until_exit_success().unwrap();
}

#[test]
#[cfg(feature = "fpga_realtime")]
fn test_mbox_pauser_sigbus() {
fn find_binary_path() -> Option<&'static str> {
// Use this path when running on github.
const TEST_BIN_PATH_SQUASHFS:&str = "/tmp/caliptra-test-binaries/target/aarch64-unknown-linux-gnu/release/fpga_realtime_mbox_pauser";

const TEST_BIN_PATH: &str = env!("CARGO_BIN_EXE_fpga_realtime_mbox_pauser");
if std::path::Path::new(TEST_BIN_PATH_SQUASHFS).exists() {
Some(TEST_BIN_PATH_SQUASHFS)
} else if std::path::Path::new(TEST_BIN_PATH).exists() {
Some(TEST_BIN_PATH)
} else {
None
}
}

let mut child = Command::new(find_binary_path().unwrap())
.spawn()
.expect("Failed to start mbox_pauser test utility");

let exit_code = wait_with_timeout(&mut child, Duration::from_secs(120));

// Check if the exit code is 42
assert_eq!(exit_code, Some(42));
}

0 comments on commit f102017

Please sign in to comment.