灵符lingfu

ling-lang

↓ 0 downloads

Ling - The Omniglot Systems Language

Keywords systems, polyglot, ai, crypto, game
lingfu install ling-lang
LicenseApache-2.0 OR MIT
AuthorsLing Lin, Sanny Lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / Files (995)

crates/ling-kernel/src/arch/aarch64/boot.rs
//! aarch64 entry point. Raspberry Pi firmware loads `kernel8.img` as a raw
//! binary (no ELF program headers), so unlike the x86/Multiboot2 path, nobody
//! else sets up a stack or zeroes .bss for us — this module does both before
//! handing off to the per-project generated `kernel_entry`.
use core::arch::global_asm;

#[cfg(not(test))]
global_asm!(
    ".section .text.boot",
    ".global _start",
    "_start:",
    // The firmware's device tree address arrives in x0: keep it (in .data, so
    // `zero_bss` cannot wipe it) before the register is reused.
    "    ldr x1, =DTB_PTR",
    "    str x0, [x1]",
    "    mrs x0, mpidr_el1",
    "    and x0, x0, #0xFF",
    "    cbz x0, primary",
    "1:  wfe", // secondary cores: park forever
    "    b 1b",
    "primary:",
    // Drop EL2 -> EL1 if the firmware handed off with the hypervisor
    // extension present (QEMU's `raspi3b` and real Pi firmware both do)
    // but unused -- this kernel has no hypervisor role, and every register
    // Phase 2 touches (VBAR_EL1, the physical generic timer's CNTP_*_EL0)
    // is either EL1-only or traps to EL2 by default, so staying at EL2
    // would silently break both.
    "    mrs x0, CurrentEL",
    "    lsr x0, x0, #2",
    "    cmp x0, #2",
    "    b.ne el1_entry",
    "    mov x0, #(1 << 31)", // HCR_EL2.RW: EL1 runs AArch64
    "    msr hcr_el2, x0",
    "    mrs x0, cnthctl_el2",
    "    orr x0, x0, #3", // EL1PCTEN | EL1PCEN: untrap CNTP_*_EL0 from EL1
    "    msr cnthctl_el2, x0",
    "    msr cntvoff_el2, xzr",
    // CPTR_EL2.TFP (bit 10) defaults to an implementation-defined value on
    // real hardware and QEMU alike -- leaving it set traps every EL1 FP/
    // NEON instruction to EL2 instead of EL1's own CPACR_EL1 (below) ever
    // getting a say. Clearing it here is the aarch64 counterpart of
    // `boot.rs`'s x86_64 twin explicitly enabling SSE via CR0/CR4 before
    // any Rust code runs: confirmed necessary the same way that one was --
    // LLVM auto-vectorizes even an ordinary `[u8; 16]` fill loop into a
    // NEON `str q0` on this target (NEON is baseline, not optional, for
    // AArch64 unlike x86's SSE), and every such instruction trapped until
    // this was set, recursively re-trapping the fault handler's own
    // `console_write` calls into a self-sustaining exception storm.
    "    msr cptr_el2, xzr",
    "    mov x0, #0x3C5", // SPSR: EL1h, D|A|I|F all masked
    "    msr spsr_el2, x0",
    "    adr x0, el1_entry",
    "    msr elr_el2, x0",
    "    eret",
    "el1_entry:",
    // CPACR_EL1.FPEN = 0b11 (bits 21:20): don't trap FP/NEON access at
    // EL1 (or, later, EL0) to EL1 itself either -- the other half of the
    // same fix, needed even when boot skipped the EL2 drop entirely (an
    // EL1-native boot path would still reset with FP/NEON trapped).
    "    mov x0, #(0b11 << 20)",
    "    msr cpacr_el1, x0",
    "    isb",
    "    ldr x0, =_stack_top",
    "    mov sp, x0",
    "    bl kernel_entry",
    "    b 1b",
);

extern "C" {
    static mut __bss_start: u8;
    static mut __bss_end: u8;
    static _kernel_end: u8;
    static _stack_top: u8;
}

/// The device tree address the firmware passed in `x0` (1 = never set; a
/// non-zero initial value keeps this in .data rather than .bss).
#[no_mangle]
pub static mut DTB_PTR: u64 = 1;

/// Repoint the tree (at a copy that survives memory init).
pub fn set_dtb_ptr(p: u64) {
    unsafe { core::ptr::write_volatile(&raw mut DTB_PTR, p) }
}

/// The device tree's address, or 0 when the boot did not provide one.
pub fn dtb_ptr() -> u64 {
    let v = unsafe { core::ptr::read_volatile(&raw const DTB_PTR) };
    if v <= 1 || v & 3 != 0 {
        0
    } else {
        v
    }
}

/// Top of the boot stack `el1_entry` switched onto -- the one stack every
/// Ling program on this target runs on, which `lingrt`'s collector scans.
pub fn boot_stack_top() -> u64 {
    (&raw const _stack_top) as u64
}

/// First physical address past the kernel's own image + boot stack
/// (`RPI_LINKER_SCRIPT`'s `_kernel_end`, right after `_stack_top`) — the
/// low-water mark `mm::frame`'s mailbox-based memory detection clips
/// against, same reasoning as the x86_64 backend's `kernel_end`.
pub fn kernel_end() -> u64 {
    (&raw const _kernel_end) as u64
}

/// Zero the .bss region (linker-defined `__bss_start`/`__bss_end`). Must run
/// before any Rust code relies on zero-initialized statics.
pub unsafe fn zero_bss() {
    let start = &raw mut __bss_start as usize;
    let end = &raw mut __bss_end as usize;
    let mut p = start as *mut u8;
    while (p as usize) < end {
        core::ptr::write_volatile(p, 0);
        p = p.add(1);
    }
}

← Back to index