Assembly inline
Às vezes, precisamos usar assembly para fazer coisas que não são possíveis com o código Rust. Por exemplo, para fazer uma chamada HVC (hypervisor call) para informar ao firmware para desligar o sistema:
#![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) { // SEGURANÇA: isso só usa os registradores declarados e não faz // nada com a memória. 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 {} }
(Se você realmente quiser fazer isso, use o crate smccc
que possui wrappers para todas essas funções.)
- PSCI é a Interface de Coordenação de Estado de Energia Arm, um conjunto padrão de funções para gerenciar estados de energia do sistema e da CPU, entre outras coisas. É implementado pelo firmware EL3 e hipervisores em muitos sistemas.
- A sintaxe
0 => _
significa inicializar o registrador com 0 antes de executar o código de assembly inline e ignorar seu conteúdo posteriormente. É necessário usarinout
em vez dein
porque a chamada pode potencialmente destruir o conteúdo dos registradores. - Esta função
main
precisa ser#[no_mangle]
eextern "C"
porque é chamada de nosso ponto de entrada ementry.S
. _x0
–_x3
são os valores dos registradoresx0
–x3
, que são convencionalmente usados pelo carregador de inicialização para passar coisas como um ponteiro para a árvore de dispositivos. De acordo com a convenção de chamada aarch64 padrão (que é o queextern "C"
especifica para usar), os registradoresx0
–x7
são usados para os primeiros 8 argumentos passados para uma função, portanto,entry.S
não precisa fazer nada especial, exceto garantir que não altere esses registradores.- Execute o exemplo no QEMU com
make qemu_psci
emsrc/bare-metal/aps/examples
.