Вбудований асемблер
Іноді нам потрібно використовувати асемблер для того, щоб робити речі, які неможливо зробити за допомогою коду на Rust. Наприклад, зробити HVC (виклик гіпервізора), щоб сказати прошивці вимкнути систему:
#![no_main]
#![no_std]
use core::arch::asm;
use core::panic::PanicInfo;
mod exceptions;
const PSCI_SYSTEM_OFF: u32 = 0x84000008;
// БЕЗПЕКА: Не існує іншої глобальної функції з таким іменем.
#[unsafe(no_mangle)]
extern "C" fn main(_x0: u64, _x1: u64, _x2: u64, _x3: u64) {
// БЕЗПЕКА: тут використовуються тільки оголошені регістри
// і нічого не робиться з пам'яттю.
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, у якому є оболонки для всіх цих функцій.)
- PSCI — це Arm Power State Coordination Interface, стандартний набір функцій для керування станами живлення системи та CPU, серед іншого. Він реалізований прошивкою EL3 і гіпервізорами на багатьох системах.
- Синтаксис
0 => _означає ініціалізацію реєстру до 0 перед виконанням вбудованого асемблеру та ігнорування його вмісту після цього. Нам потрібно використовуватиinout, а неin, оскільки виклик потенційно може знищити вміст реєстрів. - Ця
mainфункція має бути#[unsafe(no_mangle)]іextern "C", оскільки вона викликається з нашої точки входу вentry.S. _x0–_x3– це значення регістрівx0–x3, які традиційно використовуються завантажувачем для передачі таких речей, як покажчик на дерево пристроїв. Відповідно до стандартної угоди про виклики aarch64 (це те, що вказуєextern "C"), регістриx0–x7використовуються для перших 8 аргументів, що передаються до функції, томуentry.Sне потрібно робити нічого особливого, окрім як переконатися, що він не змінює ці регістри.- Запустіть приклад у QEMU за допомогою
make qemu_psciвsrc/bare-metal/aps/examples.