行內組語
有時候,我們需要使用組語,才能執行 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
是暫存器x0
到x3
的值。按照慣例,系統啟動載入程式會使用這些值,將指標等項目傳遞給裝置樹狀結構。根據標準的 aarch64 呼叫慣例 (即extern "C"
指定使用的項目),前 8 個傳遞至函式的引數會使用暫存器x0
到x7
,因此entry.S
不需執行任何特殊操作,只要確保不會變更這些暫存器。- 使用
src/bare-metal/aps/examples
下的make qemu_psci
,在 QEMU 中執行範例。