Вбудований асемблер

Іноді нам потрібно використовувати асемблер для того, щоб робити речі, які неможливо зробити за допомогою коду на 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 – це значення регістрів x0x3, які традиційно використовуються завантажувачем для передачі таких речей, як покажчик на дерево пристроїв. Відповідно до стандартної угоди про виклики aarch64 (це те, що вказує extern "C"), регістри x0x7 використовуються для перших 8 аргументів, що передаються до функції, тому entry.S не потрібно робити нічого особливого, окрім як переконатися, що він не змінює ці регістри.
  • Запустіть приклад у QEMU за допомогою make qemu_psci в src/bare-metal/aps/examples.