内嵌汇编
有时,如果无法通过 Rust 代码实现某些操作,我们就需要使用汇编来解决。例如,如需发出 HVC(Hypervisor 调用)来指示固件关闭系统,请使用以下命令:
#![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) {
// SAFETY: 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 固件和 Hypervisor 来实现该函数。
0 => _
语法表示在运行内嵌汇编代码之前将寄存器初始化为 0,并在之后忽略寄存器中的内容。我们需要使用inout
而非in
,因为该调用操作可能会破坏寄存器中的内容。- 所用
main
函数必须是#[no_mangle]
和extern "C"
,因为是从entry.S
中的入口点调用该函数。 _x0
–_x3
表示寄存器x0
-x3
的值,引导加载程序通常使用这些值来传递各种内容(例如将指针传递到设备树)。根据标准的 aarch64 调用规范(extern "C"
指定使用此规范),需要使用寄存器x0
-x7
将前 8 个参数传递给函数,因此entry.S
无需执行任何特殊操作,只要确保不会更改这些寄存器。- 在 QEMU 中,使用
src/bare-metal/aps/examples
目录下的make qemu_psci
运行该示例。