use core::{
arch::naked_asm,
mem::{offset_of, size_of},
};
use aarch64_cpu_ext::cache::{CacheOp, dcache_all};
use kdef_pgtable::{KLINER_OFFSET, PAGE_SIZE};
#[cfg(not(feature = "hv"))]
use pie_boot_loader_aarch64::el1::{set_table, setup_sctlr, setup_table_regs};
#[cfg(feature = "hv")]
use pie_boot_loader_aarch64::el2::{set_table, setup_sctlr, setup_table_regs};
mod cache;
pub mod context;
pub mod mem;
pub mod power;
pub mod trap;
macro_rules! sym_lma {
($sym:expr) => {{
#[allow(unused_unsafe)]
unsafe{
let out: usize;
core::arch::asm!(
"adrp {r}, {s}",
"add {r}, {r}, :lo12:{s}",
r = out(reg) out,
s = sym $sym,
);
out
}
}};
}
#[cfg_attr(feature = "hv", path = "el2.rs")]
#[cfg_attr(not(feature = "hv"), path = "el1.rs")]
mod el;
use crate::{boot_info, start_code};
use aarch64_cpu::{asm::barrier, registers::*};
use kasm_aarch64::{self as kasm, adr_l};
use pie_boot_loader_aarch64::EarlyBootArgs;
#[unsafe(link_section = ".data")]
static mut UART_DEBUG: usize = 0;
const FLAG_LE: usize = 0b0;
const FLAG_PAGE_SIZE_4K: usize = 0b10;
const FLAG_ANY_MEM: usize = 0b1000;
#[unsafe(naked)]
#[unsafe(no_mangle)]
#[unsafe(link_section = ".head.text")]
pub unsafe extern "C" fn _start() -> ! {
naked_asm!(
"nop",
"bl {entry}",
".quad 0",
".quad __kernel_load_end - _start",
".quad {flags}",
".quad 0",
".quad 0",
".quad 0",
".ascii \"ARM\\x64\"",
".byte 0, 0, 0, 0",
flags = const FLAG_LE | FLAG_PAGE_SIZE_4K | FLAG_ANY_MEM,
entry = sym primary_entry,
)
}
#[start_code(naked)]
fn primary_entry() -> ! {
naked_asm!(
"
bl {preserve_boot_args}",
adr_l!(x0, "{boot_args}"),
adr_l!(x8, "{loader}"),
"
br x8",
preserve_boot_args = sym preserve_boot_args,
boot_args = sym crate::BOOT_ARGS,
loader = sym crate::loader::LOADER_BIN,
)
}
#[start_code(naked)]
fn preserve_boot_args() {
naked_asm!(
adr_l!(x8, "{boot_args}"), "
stp x0, x1, [x8] // x0 .. x3 at kernel entry
stp x2, x3, [x8, #16]
LDR x0, ={virt_entry}
str x0, [x8, {args_of_entry_vma}]",
adr_l!(x0, "_start"),
"
str x0, [x8, {args_of_kimage_addr_lma}]
LDR x0, =_start
str x0, [x8, {args_of_kimage_addr_vma}]",
adr_l!(x0, "__cpu0_stack_top"),
"
str x0, [x8, {args_of_stack_top_lma}]",
"
LDR x0, =__cpu0_stack_top
str x0, [x8, {args_of_stack_top_vma}]
",
adr_l!(x0, "__kernel_code_end"),
"
str x0, [x8, {args_of_kcode_end}]
// set EL
mov x0, {el_value} // Set target EL based on feature
str x0, [x8, {args_of_el}]
LDR x0, ={kliner_offset}
str x0, [x8, {args_of_kliner_offset}]
mov x0, {page_size}
str x0, [x8, {args_of_page_size}]
mov x0, #1
str x0, [x8, {args_of_debug}]
dmb sy // needed before dc ivac with
// MMU off
mov x0, x8
add x1, x0, {boot_arg_size}
b {dcache_inval_poc} // tail call
",
boot_args = sym crate::BOOT_ARGS,
virt_entry = sym switch_sp,
args_of_entry_vma = const offset_of!(EarlyBootArgs, virt_entry),
args_of_kimage_addr_lma = const offset_of!(EarlyBootArgs, kimage_addr_lma),
args_of_kimage_addr_vma = const offset_of!(EarlyBootArgs, kimage_addr_vma),
args_of_stack_top_lma = const offset_of!(EarlyBootArgs, stack_top_lma),
args_of_stack_top_vma = const offset_of!(EarlyBootArgs, stack_top_vma),
args_of_kcode_end = const offset_of!(EarlyBootArgs, kcode_end),
args_of_el = const offset_of!(EarlyBootArgs, el),
el_value = const if cfg!(feature = "hv") { 2 } else { 1 },
kliner_offset = const KLINER_OFFSET,
args_of_kliner_offset = const offset_of!(EarlyBootArgs, kliner_offset),
page_size = const PAGE_SIZE,
args_of_page_size = const offset_of!(EarlyBootArgs, page_size),
args_of_debug = const offset_of!(EarlyBootArgs, debug),
dcache_inval_poc = sym cache::__dcache_inval_poc,
boot_arg_size = const size_of::<EarlyBootArgs>()
)
}
#[start_code(naked)]
pub fn _start_secondary(_stack_top: usize) -> ! {
naked_asm!(
"
mrs x19, mpidr_el1
and x19, x19, #0xffffff // get current CPU id
mov x20, x0
mov sp, x20
mov x0, x20
bl {switch_to_elx}
bl {enable_fp}
bl {init_mmu} // return va_offset x0
add sp, sp, x0
mov x0, x19 // call_secondary_main(cpu_id)
ldr x8, =__pie_boot_secondary
blr x8
b .",
switch_to_elx = sym el::switch_to_elx,
init_mmu = sym init_mmu,
enable_fp = sym enable_fp,
)
}
#[start_code]
fn enable_fp() {
CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing);
barrier::isb(barrier::SY);
}
#[start_code]
fn init_mmu() -> usize {
dcache_all(CacheOp::Invalidate);
setup_table_regs();
let addr = boot_info().pg_start as usize;
set_table(addr);
setup_sctlr();
boot_info().kcode_offset()
}
#[unsafe(naked)]
unsafe extern "C" fn switch_sp(_args: usize) -> ! {
naked_asm!(
"
adrp x8, __cpu0_stack_top
add x8, x8, :lo12:__cpu0_stack_top
mov sp, x8
bl {next}
",
next =sym crate::common::entry::virt_entry,
)
}
pub fn setup_exception_vectors() {
trap::setup();
}