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 usar inout em vez de in porque a chamada pode potencialmente destruir o conteúdo dos registradores.
  • Esta função main precisa ser #[no_mangle] e extern "C" porque é chamada de nosso ponto de entrada em entry.S.
  • _x0_x3 são os valores dos registradores x0x3, 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 que extern "C" especifica para usar), os registradores x0x7 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 em src/bare-metal/aps/examples.