Exceptions

aarch64-rt provides a trait to define exception handlers, and a macro to generate the assembly code for the exception vector to call them.

The trait has default implementations for each method which simply panic, so we can omit methods for exceptions we don’t expect to happen.

use aarch64_rt::{ExceptionHandlers, RegisterStateRef, exception_handlers};
use log::error;
use smccc::Hvc;
use smccc::psci::system_off;

struct Handlers;

impl ExceptionHandlers for Handlers {
    extern "C" fn sync_current(_state: RegisterStateRef) {
        error!("sync_current");
        system_off::<Hvc>().unwrap();
    }

    extern "C" fn irq_current(_state: RegisterStateRef) {
        error!("irq_current");
        system_off::<Hvc>().unwrap();
    }

    extern "C" fn fiq_current(_state: RegisterStateRef) {
        error!("fiq_current");
        system_off::<Hvc>().unwrap();
    }

    extern "C" fn serror_current(_state: RegisterStateRef) {
        error!("serror_current");
        system_off::<Hvc>().unwrap();
    }
}

exception_handlers!(Handlers);
  • The exception_handlers macro generates a global_asm! block with the exception vector to call into the Rust code, similar to the exceptions.S we had before.
  • RegisterStateRef wraps a reference to the stack frame where the register values were saved by the assembly code when the exception happed. This can be used for example to extract the parameters for an SMC or HVC call from a lower EL, and update the values to be restored when the exception handler returns.