Exceções

AArch64 define uma tabela de vetor de exceção com 16 entradas, para 4 tipos de exceções (síncronas, IRQ, FIQ, SError) de 4 estados (EL atual com SP0, EL atual com SPx, EL inferior usando AArch64, EL inferior usando AArch32). Implementamos isso em assembly para salvar os registradores voláteis na pilha antes de chamar o código Rust:

use log::error;
use smccc::psci::system_off;
use smccc::Hvc;

#[no_mangle]
extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
    error!("sync_exception_current");
    system_off::<Hvc>().unwrap();
}

#[no_mangle]
extern "C" fn irq_current(_elr: u64, _spsr: u64) {
    error!("irq_current");
    system_off::<Hvc>().unwrap();
}

#[no_mangle]
extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
    error!("fiq_current");
    system_off::<Hvc>().unwrap();
}

#[no_mangle]
extern "C" fn serr_current(_elr: u64, _spsr: u64) {
    error!("serr_current");
    system_off::<Hvc>().unwrap();
}

#[no_mangle]
extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
    error!("sync_lower");
    system_off::<Hvc>().unwrap();
}

#[no_mangle]
extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
    error!("irq_lower");
    system_off::<Hvc>().unwrap();
}

#[no_mangle]
extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
    error!("fiq_lower");
    system_off::<Hvc>().unwrap();
}

#[no_mangle]
extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
    error!("serr_lower");
    system_off::<Hvc>().unwrap();
}
  • EL é nível de exceção; todos os nossos exemplos esta tarde são executados em EL1.
  • Para simplificar, não estamos distinguindo entre SP0 e SPx para as exceções do EL atual, ou entre AArch32 e AArch64 para as exceções do EL inferior.
  • Neste exemplo, apenas registramos a exceção e desligamos, pois não esperamos que nenhuma delas realmente aconteça.
  • Podemos pensar nos manipuladores de exceção e no nosso contexto de execução principal mais ou menos como em threads diferentes. Send e Sync controlarão o que podemos compartilhar entre eles, assim como com threads. Por exemplo, se quisermos compartilhar algum valor entre os manipuladores de exceção e o restante do programa, e ele for Send mas não Sync, então precisaremos envolvê-lo em algo como um Mutex e colocá-lo em um estático.