Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Встроенный ассемблер

Иногда нужно использовать ассемблер для того, что невозможно сделать кодом 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.