From 00b0503594a0ad7540b649ad93d8afbad797b8ae Mon Sep 17 00:00:00 2001 From: Kor Nielsen Date: Wed, 13 Sep 2023 14:16:51 -0700 Subject: [PATCH] ROM: Log NMI/exception details to CPTRA_FW_EXTENDED_ERROR_INFO. (#753) This information is useful to debug unexpected ROM or hardware failures. --- drivers/src/soc_ifc.rs | 13 ------------ rom/dev/src/main.rs | 46 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/drivers/src/soc_ifc.rs b/drivers/src/soc_ifc.rs index eeb623323b..197c57fd2a 100644 --- a/drivers/src/soc_ifc.rs +++ b/drivers/src/soc_ifc.rs @@ -14,7 +14,6 @@ Abstract: use caliptra_error::{CaliptraError, CaliptraResult}; use caliptra_registers::soc_ifc::enums::DeviceLifecycleE; -use caliptra_registers::soc_ifc::regs::CptraWdtStatusReadVal; use caliptra_registers::soc_ifc::{self, SocIfcReg}; use crate::{memory_layout, FuseBank}; @@ -164,18 +163,6 @@ impl SocIfc { .write(|w| w.timer1_en(false)); } - /// Get the WDT status. - /// - /// This is useful to call from a fatal-error-handling routine. - /// - /// # Safety - /// - /// This function is safe to call from a trap handler. - pub unsafe fn wdt_status() -> CptraWdtStatusReadVal { - let soc_ifc = SocIfcReg::new(); - soc_ifc.regs().cptra_wdt_status().read() - } - pub fn get_cycle_count(&self, seconds: u32) -> CaliptraResult { const GIGA_UNIT: u32 = 1_000_000_000; let clock_period_picosecs = self.soc_ifc.regs().cptra_timer_config().read(); diff --git a/rom/dev/src/main.rs b/rom/dev/src/main.rs index 12811bcea4..bb0c51cd57 100644 --- a/rom/dev/src/main.rs +++ b/rom/dev/src/main.rs @@ -17,6 +17,7 @@ Abstract: use crate::{lock::lock_registers, print::HexBytes}; use caliptra_cfi_lib::CfiCounter; +use caliptra_registers::soc_ifc::SocIfcReg; use core::hint::black_box; use caliptra_drivers::{ @@ -217,29 +218,64 @@ fn launch_fmc(env: &mut RomEnv) -> ! { #[inline(never)] extern "C" fn exception_handler(exception: &exception::ExceptionRecord) { cprintln!( - "EXCEPTION mcause=0x{:08X} mscause=0x{:08X} mepc=0x{:08X}", + "EXCEPTION mcause=0x{:08X} mscause=0x{:08X} mepc=0x{:08X} ra=0x{:08X}", exception.mcause, exception.mscause, - exception.mepc + exception.mepc, + exception.ra ); + { + let mut soc_ifc = unsafe { SocIfcReg::new() }; + let soc_ifc = soc_ifc.regs_mut(); + let ext_info = soc_ifc.cptra_fw_extended_error_info(); + ext_info.at(0).write(|_| exception.mcause); + ext_info.at(1).write(|_| exception.mscause); + ext_info.at(2).write(|_| exception.mepc); + ext_info.at(3).write(|_| exception.ra); + } + handle_fatal_error(CaliptraError::ROM_GLOBAL_EXCEPTION.into()); } #[no_mangle] #[inline(never)] extern "C" fn nmi_handler(exception: &exception::ExceptionRecord) { + let mut soc_ifc = unsafe { SocIfcReg::new() }; + + // 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(), + ); + cprintln!( - "NMI mcause=0x{:08X} mscause=0x{:08X} mepc=0x{:08X}", + "NMI mcause=0x{:08X} mscause=0x{:08X} mepc=0x{:08X} ra=0x{:08X} error_internal_intr_r={:08X}", exception.mcause, exception.mscause, - exception.mepc + exception.mepc, + exception.ra, + err_interrupt_status, ); + { + let soc_ifc = soc_ifc.regs_mut(); + let ext_info = soc_ifc.cptra_fw_extended_error_info(); + ext_info.at(0).write(|_| exception.mcause); + ext_info.at(1).write(|_| exception.mscause); + ext_info.at(2).write(|_| exception.mepc); + ext_info.at(3).write(|_| exception.ra); + ext_info.at(4).write(|_| err_interrupt_status); + } + // Check if the NMI was due to WDT expiry. let mut error = CaliptraError::ROM_GLOBAL_NMI; - let wdt_status = unsafe { SocIfc::wdt_status() }; + let wdt_status = soc_ifc.regs().cptra_wdt_status().read(); if wdt_status.t1_timeout() || wdt_status.t2_timeout() { cprintln!("WDT Expired"); error = CaliptraError::ROM_GLOBAL_WDT_EXPIRED;