Встроенный ассемблер
Иногда нужно использовать ассемблер для того, что невозможно сделать кодом Rust. Например, чтобы выполнить HVC (hypervisor call), сообщая прошивке, что нужно выключить систему:
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
#![no_main]
#![no_std]
use core::arch::asm;
use core::panic::PanicInfo;
mod asm;
mod exceptions;
const PSCI_SYSTEM_OFF: u32 = 0x84000008;
// SAFETY: Нет другой глобальной функции с таким именем.
#[unsafe(no_mangle)]
extern "C" fn main(_x0: u64, _x1: u64, _x2: u64, _x3: u64) {
// SAFETY: здесь используются только объявленные регистры, и мы ничего не делаем
// с памятью.
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, стандартный набор функций для управления состояниями питания системы и процессоров, среди прочего. Реализуется прошивкой EL3 и гипервизорами на многих системах.
- Синтаксис
0 => _означает, что регистр инициализируется нулём перед выполнением встроенного ассемблерного кода, а его содержимое после этого игнорируется. Нужно использоватьinout, а неin, потому что вызов потенциально может перезаписать содержимое регистров. - Эта функция
mainдолжна быть#[unsafe(no_mangle)]иextern "C", потому что её вызывает наша точка входа вentry.S.- Достаточно было бы просто
#[no_mangle], но RFC3325 использует эту запись, чтобы привлечь внимание рецензентов к атрибутам, которые могут вызвать неопределённое поведение при неправильном использовании.
- Достаточно было бы просто
_x0–_x3— значения регистровx0–x3, которые по соглашению загрузчик использует для передачи, например, указателя на дерево устройств. Согласно стандартному соглашению о вызовах aarch64 (которое задаётextern "C"), регистрыx0–x7используются для первых 8 аргументов функции, поэтомуentry.Sне нужно делать ничего особенного, кроме того, чтобы не менять эти регистры.- Запустите пример в QEMU командой
make qemu_psciв каталогеsrc/bare-metal/aps/examples.