Skip to content

Commit

Permalink
runtime: Halt the cpu between mailbox commands
Browse files Browse the repository at this point in the history
Use interrupts to wake the CPU from a halted state to deal with mailbox
commands.

Signed-off-by: Arthur Heymans <[email protected]>
  • Loading branch information
ArthurHeymans authored and jhand2 committed Feb 5, 2024
1 parent c77993a commit 3d3c5b1
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 16 deletions.
6 changes: 5 additions & 1 deletion runtime/src/drivers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ use arrayvec::ArrayVec;
use caliptra_drivers::KeyId;
use caliptra_drivers::{
cprint, cprintln, pcr_log::RT_FW_JOURNEY_PCR, Array4x12, CaliptraError, CaliptraResult,
DataVault, Ecc384, KeyVault, Lms, PersistentDataAccessor, ResetReason, Sha1, SocIfc,
DataVault, Ecc384, KeyVault, Lms, PersistentDataAccessor, Pic, ResetReason, Sha1, SocIfc,
};
use caliptra_drivers::{
hand_off::DataStore, Ecc384PubKey, Hmac384, PcrBank, PcrId, Sha256, Sha256Alg, Sha384,
Sha384Acc, Trng,
};
use caliptra_registers::el2_pic_ctrl::El2PicCtrl;
use caliptra_registers::mbox::enums::MboxStatusE;
use caliptra_registers::{
csrng::CsrngReg, dv::DvReg, ecc::EccReg, entropy_src::EntropySrcReg, hmac::HmacReg, kv::KvReg,
Expand Down Expand Up @@ -86,6 +87,8 @@ pub struct Drivers {

pub pcr_bank: PcrBank,

pub pic: Pic,

pub cert_chain: ArrayVec<u8, MAX_CERT_CHAIN_SIZE>,

#[cfg(feature = "fips_self_test")]
Expand Down Expand Up @@ -157,6 +160,7 @@ impl Drivers {
trng,
persistent_data: PersistentDataAccessor::new(),
pcr_bank: PcrBank::new(PvReg::new()),
pic: Pic::new(El2PicCtrl::new()),
#[cfg(feature = "fips_self_test")]
self_test_status: SelfTestStatus::Idle,
cert_chain: ArrayVec::new(),
Expand Down
35 changes: 29 additions & 6 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ use tagging::{GetTaggedTciCmd, TagTciCmd};
use caliptra_common::cprintln;

use caliptra_drivers::{CaliptraError, CaliptraResult, ResetReason};
use caliptra_registers::mbox::enums::MboxStatusE;
use caliptra_registers::el2_pic_ctrl::El2PicCtrl;
use caliptra_registers::{mbox::enums::MboxStatusE, soc_ifc};
use dpe::{
commands::{CommandExecution, DeriveContextCmd, DeriveContextFlags},
dpe_instance::{DpeEnv, DpeTypes},
Expand Down Expand Up @@ -118,14 +119,17 @@ fn enter_idle(drivers: &mut Drivers) {
Ok(_) => drivers.self_test_status = SelfTestStatus::Done,
Err(e) => caliptra_drivers::report_fw_error_non_fatal(e.into()),
}
} else {
// Don't enter low power mode when in progress
return;
}
}

// TODO: Enable interrupts?
//#[cfg(feature = "riscv")]
//unsafe {
//core::arch::asm!("wfi");
//}
#[cfg(feature = "riscv")]
if cfg!(feature = "fpga_realtime") {
// TODO implement in emulator
caliptra_cpu::csr::mpmc_halt();
}
}

/// Handles the pending mailbox command and writes the repsonse back to the mailbox
Expand Down Expand Up @@ -205,6 +209,20 @@ fn handle_command(drivers: &mut Drivers) -> CaliptraResult<MboxStatusE> {
Ok(MboxStatusE::DataReady)
}

#[cfg(feature = "riscv")]
// TODO implement in emulator
fn setup_mailbox_wfi(drivers: &mut Drivers) {
use caliptra_drivers::IntSource;

caliptra_cpu::csr::mie_enable_external_interrupts();

// Set highest priority so that Int can wake CPU
drivers.pic.int_set_max_priority(IntSource::SocIfcNotif);
drivers.pic.int_enable(IntSource::SocIfcNotif);

drivers.soc_ifc.enable_mbox_notif_interrupts();
}

/// Handles mailbox commands when the command is ready
pub fn handle_mailbox_commands(drivers: &mut Drivers) -> CaliptraResult<()> {
// Indicator to SOC that RT firmware is ready
Expand All @@ -229,6 +247,11 @@ pub fn handle_mailbox_commands(drivers: &mut Drivers) -> CaliptraResult<()> {
}
}
}
#[cfg(feature = "riscv")]
if cfg!(feature = "fpga_realtime") {
setup_mailbox_wfi(drivers);
}

loop {
enter_idle(drivers);
if drivers.is_shutdown {
Expand Down
30 changes: 21 additions & 9 deletions runtime/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,33 @@ extern "C" fn exception_handler(trap_record: &TrapRecord) {
handle_fatal_error(caliptra_drivers::CaliptraError::RUNTIME_GLOBAL_EXCEPTION.into());
}

const NON_DCCM_NMI: u32 = 0xF000_1002;

#[no_mangle]
#[inline(never)]
#[allow(clippy::empty_loop)]
extern "C" fn nmi_handler(trap_record: &TrapRecord) {
let soc_ifc = unsafe { SocIfcReg::new() };
let mut soc_ifc = unsafe { SocIfcReg::new() };

let soc_ifc_regs = soc_ifc.regs_mut();
let intr_block = soc_ifc_regs.intr_block_rf();

// TODO implement MMIO reg for emulator
if cfg!(feature = "fpga_realtime") {
let notif_interrupt_status = intr_block.notif_internal_intr_r();

// On wake from mailbox command, clear the interrupt status and mret to continue execution
if notif_interrupt_status.read().notif_cmd_avail_sts() && trap_record.mcause == NON_DCCM_NMI
// Machine Fast Interrupt non-DCCM region NMI
{
notif_interrupt_status.modify(|w| w.notif_cmd_avail_sts(true));
return;
}
}

// If the NMI was fired by caliptra instead of the uC, this register
// contains the reason(s)
let err_interrupt_status = u32::from(
soc_ifc
.regs()
.intr_block_rf()
.error_internal_intr_r()
.read(),
);
let err_interrupt_status = u32::from(intr_block.error_internal_intr_r().read());
log_trap_record(trap_record, Some(err_interrupt_status));
cprintln!(
"RT NMI mcause=0x{:08X} mscause=0x{:08X} mepc=0x{:08X} ra=0x{:08X} error_internal_intr_r={:08X}",
Expand All @@ -104,7 +116,7 @@ extern "C" fn nmi_handler(trap_record: &TrapRecord) {
err_interrupt_status,
);

let wdt_status = soc_ifc.regs().cptra_wdt_status().read();
let wdt_status = soc_ifc_regs.cptra_wdt_status().read();
let error = if wdt_status.t1_timeout() || wdt_status.t2_timeout() {
cprintln!("[rt] WDT Expired");
CaliptraError::RUNTIME_GLOBAL_WDT_EXPIRED
Expand Down

0 comments on commit 3d3c5b1

Please sign in to comment.