行內組語

有時候,我們需要使用組語,才能執行 Rust 程式碼無法執行的作業。舉例來說,如要發出 HVC (管理程序呼叫) 指示韌體關閉系統:

#![no_main]
#![no_std]

use core::arch::asm;
use core::panic::PanicInfo;

mod exceptions;

const PSCI_SYSTEM_OFF: u32 = 0x84000008;

#[no_mangle]
extern "C" fn main(_x0: u64, _x1: u64, _x2: u64, _x3: u64) {
    // Safe because this only uses the declared registers and doesn't do
    // anything with memory.
    unsafe {
        asm!("hvc #0",
            inout("w0") PSCI_SYSTEM_OFF => _,
            inout("w1") 0 => _,
            inout("w2") 0 => _,
            inout("w3") 0 => _,
            inout("w4") 0 => _,
            inout("w5") 0 => _,
            inout("w6") 0 => _,
            inout("w7") 0 => _,
            options(nomem, nostack)
        );
    }

    loop {}
}

(如果您確實想執行這項操作,請使用 smccc Crate,其中包含所有這些函式的包裝函式。)

  • PSCI 是 Arm 電源狀態協調介面,這組標準函式可管理系統和 CPU 電源狀態及其他項目,是由 EL3 韌體和管理程序在許多系統上實作。
  • 0 => _ 語法是指在行內組語程式碼執行之前,將暫存器初始化為 0,之後就忽略其內容。我們需要使用 inout (而非 in),因為呼叫可能會破壞暫存器的內容。
  • 這個 main 函式需為 #[no_mangle]extern "C",因為此函式是從 entry.S 的進入點呼叫。
  • _x0_x3 是暫存器 x0x3 的值。按照慣例,系統啟動載入程式會使用這些值,將指標等項目傳遞給裝置樹狀結構。根據標準的 aarch64 呼叫慣例 (即 extern "C" 指定使用的項目),前 8 個傳遞至函式的引數會使用暫存器 x0x7,因此 entry.S 不需執行任何特殊操作,只要確保不會變更這些暫存器。
  • 使用 src/bare-metal/aps/examples 下的 make qemu_psci,在 QEMU 中執行範例。