{"record":{"id":"3962405476265864","repo":"rust-embedded/rust-raspberrypi-OS-tutorials","slug":"cpu-exception","errorCode":null,"errorMessage":"CPU Exception!\n\n{}","messagePattern":"CPU Exception!\n\n(.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs","lineNumber":63,"sourceCode":"    lr: u64,\n\n    /// Exception link register. The program counter at the time the exception happened.\n    elr_el1: u64,\n\n    /// Saved program status.\n    spsr_el1: SpsrEL1,\n\n    /// Exception syndrome register.\n    esr_el1: EsrEL1,\n}\n\n//--------------------------------------------------------------------------------------------------\n// Private Code\n//--------------------------------------------------------------------------------------------------\n\n/// Prints verbose information about the exception and then panics.\nfn default_exception_handler(exc: &ExceptionContext) {\n    panic!(\n        \"CPU Exception!\\n\\n\\\n        {}\",\n        exc\n    );\n}\n\n//------------------------------------------------------------------------------\n// Current, EL0\n//------------------------------------------------------------------------------\n\n#[no_mangle]\nextern \"C\" fn current_el0_synchronous(_e: &mut ExceptionContext) {\n    panic!(\"Should not be here. Use of SP_EL0 in EL1 is not supported.\")\n}\n\n#[no_mangle]\nextern \"C\" fn current_el0_irq(_e: &mut ExceptionContext) {\n    panic!(\"Should not be here. Use of SP_EL0 in EL1 is not supported.\")","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials/blob/644474cc09f755249f9c55d99a5d1e07a2562fc7/20_timer_callbacks/kernel/src/_arch/aarch64/exception.rs#L45-L81","documentation":"The kernel's default exception vector handler panics whenever the CPU takes an exception (synchronous, IRQ, SError, from any EL) that is routed to the catch-all handler in the aarch64 exception vector table. It prints the full ExceptionContext (ESR, FAR, PC, SP) so the developer can see exactly which exception occurred and where. This library throws it because an unexpected CPU exception indicates the kernel executed an invalid or unhandled condition and cannot safely continue.","triggerScenarios":"Any CPU exception routed to default_exception_handler via current_elx_synchronous, current_elx_serror, lower_aarch64_synchronous/irq/serror, or lower_aarch32_* vector entries: e.g. a data abort from a bad pointer dereference, an unaligned access, an undefined instruction, or an IRQ/SError arriving while a more specific handler is not wired into the vector table for that routing.","commonSituations":"Dereferencing null or unmapped addresses in kernel code, executing invalid instructions on a target that lacks a feature, misconfigured vector table entries (wrong target EL or stack), enabling interrupts before handlers exist, or porting the kernel to hardware whose exception routing differs from the BSP assumptions.","solutions":["Read the printed ExceptionContext: decode the ESR (Exception Syndrome Register) to identify the exact exception class and the FAR for the faulting address.","Locate the PC recorded in the context and inspect the kernel code/instruction at that address for the invalid access or instruction.","Fix the offending kernel code (bad pointer, unaligned access, unsupported instruction) or register a proper handler for that exception class in the vector table.","If it happens in lower-EL (EL0) entry paths, ensure user-mode transitions and SP_EL0 usage are actually supported before triggering them.","Rebuild with debug symbols and run under QEMU -d int,cpu_reset to trace exception entry if the context alone is insufficient."],"exampleFix":"// before\nlet val = unsafe { *(0x0 as *const u64) }; // unmapped address -> synchronous abort -> CPU Exception!\n// after\nif let Some(ptr) = VALID_MMIO_RANGE.contains_ptr(addr) {\n    let val = unsafe { ptr.read_volatile() };\n}","handlingStrategy":"validation","validationCode":"// Before dereferencing an address in kernel code, assert it is within a mapped range:\nfn addr_is_mapped(addr: usize) -> bool {\n    addr >= KERNEL_MEM_START && addr < KERNEL_MEM_END\n}","typeGuard":"fn is_valid_mmio(addr: usize) -> bool {\n    const MMIO_START: usize = 0x3F00_0000;\n    const MMIO_END: usize = 0x4000_0000;\n    (MMIO_START..MMIO_END).contains(&addr)\n}","tryCatchPattern":null,"preventionTips":["Never dereference raw addresses without checking them against known memory maps.","Run under QEMU with -d int to catch exceptions early during development.","Keep a decode table of ESR exception classes handy when reading panic output.","Enable and test every vector-table entry during bring-up instead of relying on the catch-all panic.","Use volatile accesses and correct alignment for all MMIO operations."],"tags":["aarch64","bare-metal","exception-handling","panic"],"backgroundTag":"cpu-exception","analyzedSha":"644474cc09f755249f9c55d99a5d1e07a2562fc7","analyzedAt":"2026-09-06T09:25:56.584Z","contentChangedAt":"2026-09-06T09:25:56.584Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}