例外

AArch64は16エントリを持つ例外ベクターテーブルを定義しており、これらは4つのステート(現在のELでSP0利用、現在のELでSPx利用、低位のELでAArch64、低位のELでAArch32)における4つのタイプの例外(同期、IRQ、FIQ、SError)に対応します。ここでは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で実行されています。
  • 簡単化のために、ここでは現在のEL例外におけるSP0とSPxの違い、低位のELレベルにおけるAArch32とAArch64の違いを区別していません。
  • ここではこれらの例外が発生しないはずなので、ただ例外に関するログを出力し、電源を落としています。
  • 例外ハンドラとメインの実行コンテキストは異なるスレッドのようなものだと考えることができます。ちょうどスレッド間の共有と同じように、SendSyncにより何を共有するかを制御することができます。例えば、例外ハンドラとプログラムの他のコンテキストでとある値を共有したい場合に、もしそれが SendでありSyncでなければ、Mutex のようなものでラップして、staticに定義しなければなりません。