Виключення

AArch64 визначає векторну таблицю винятків із 16 записами для 4 типів винятків (синхронний, IRQ, FIQ, SError) із 4 станів (поточний EL із SP0, поточний EL із SPx, нижчий EL із використанням AArch64, нижчий EL із застосуванням AArch32). Ми реалізуємо це в асемблері, щоб зберегти непостійні регістри в стеку перед викликом коду Rust:

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

// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) {
    error!("sync_exception_current");
    system_off::<Hvc>().unwrap();
}

// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn irq_current(_elr: u64, _spsr: u64) {
    error!("irq_current");
    system_off::<Hvc>().unwrap();
}

// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn fiq_current(_elr: u64, _spsr: u64) {
    error!("fiq_current");
    system_off::<Hvc>().unwrap();
}

// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn serr_current(_elr: u64, _spsr: u64) {
    error!("serr_current");
    system_off::<Hvc>().unwrap();
}

// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn sync_lower(_elr: u64, _spsr: u64) {
    error!("sync_lower");
    system_off::<Hvc>().unwrap();
}

// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn irq_lower(_elr: u64, _spsr: u64) {
    error!("irq_lower");
    system_off::<Hvc>().unwrap();
}

// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn fiq_lower(_elr: u64, _spsr: u64) {
    error!("fiq_lower");
    system_off::<Hvc>().unwrap();
}

// SAFETY: There is no other global function of this name.
#[unsafe(no_mangle)]
extern "C" fn serr_lower(_elr: u64, _spsr: u64) {
    error!("serr_lower");
    system_off::<Hvc>().unwrap();
}
  • EL - це рівень винятків; усі наші приклади сьогодні працюють на EL1.
  • Для простоти ми не розрізняємо SP0 і SPx для поточних винятків EL або між AArch32 і AArch64 для нижчих винятків EL.
  • У цьому прикладі ми просто реєструємо виняток і вимикаємо живлення, оскільки ми не очікуємо, що будь-що з цього станеться.
  • Ми можемо розглядати обробники винятків і наш основний контекст виконання більш-менш як різні потоки. Send і Sync керуватимуть тим, чим ми можемо обмінюватися між ними, як і з потоками. Наприклад, якщо ми хочемо поділитися деяким значенням між обробниками винятків та рештою програми, і це Send, але не Sync, тоді нам потрібно буде загорнути його в щось на зразок Mutex і помістити у статику.