Ensamblaje integrado
Sometimes we need to use assembly to do things that aren't possible with Rust code. For example, to make an HVC (hypervisor call) to tell the firmware to power off the system:
#![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 {} }
(Si realmente quieres hacer esto, utiliza el crate smccc
que tiene envoltorios para todas estas funciones).
- PSCI es la interfaz de coordinación de estado de alimentación de Arm, un conjunto estándar de funciones para gestionar los estados de alimentación del sistema y de la CPU, entre otras cosas. Lo implementan el firmware EL3 y los hipervisores en muchos sistemas.
- La sintaxis
0 => _
significa inicializar el registro a 0 antes de ejecutar el código de ensamblaje integrado e ignorar su contenido después. Necesitamos utilizarinout
en lugar dein
porque la llamada podría alterar el contenido de los registros. - Esta función
main
debe ser#[no_mangle]
yextern "C"
, ya que se llama desde nuestro punto de entrada enentry.S
. _x0
–_x3
son los valores de los registrosx0
–x3
, que el bootloader utiliza habitualmente para pasar elementos al árbol de dispositivos, como un puntero. De acuerdo con la convención de llamadas estándar de aarch64 (que es lo queextern "C"
usa), los registrosx0
–x7
se utilizan para los primeros ocho argumentos que se pasan a una función, de modo queentry.S
no tiene que hacer nada especial, salvo asegurarse de que no cambia estos registros.- Ejecuta el ejemplo en QEMU con
make qemu_psci
ensrc/bare-metal/aps/examples
.