RustForge

rust-kernel

Rustbelt: a hobby x86_64 kernel written in Rust

rust-kernel / src / arch / aarch64 / boot.rs
2382 bytes ยท raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//! The entry point. QEMU loads our ELF file (see link.ld) and starts CPU 0
//! at `_start`, with the MMU off, at EL1 (or EL2 with `-M virt,virtualization=on`,
//! the way real boards and firmware usually hand over).
//!
//! What `_start` does, in assembly because there's no stack yet:
//!
//! 1. Any CPU but CPU 0 parks (QEMU's virt keeps the others off anyway;
//!    the Pi 3's firmware spins them, so this matters there).
//! 2. At EL2: make EL1 a 64-bit level (`HCR_EL2.RW`), let it use the
//!    timer (`CNTHCTL_EL2`), give it a safe `SCTLR_EL1`, then `eret` down
//!    to EL1 with interrupts masked.
//! 3. Set the stack pointer (`__stack_top` from link.ld), clear `.bss`
//!    (Rust expects zero-initialised statics), allow FP/SIMD
//!    (`CPACR_EL1.FPEN`; our code doesn't use it, but compiler_builtins
//!    could), and call `kmain(dtb, boot_el)`.

core::arch::global_asm!(
    r#"
.section .text.boot, "ax"
.global _start
_start:
    mrs     x1, mpidr_el1
    and     x1, x1, #0xff
    cbnz    x1, 9f                  // not CPU 0: park
    mov     x19, x0                 // a DTB pointer, if the loader passed one
    mrs     x20, CurrentEL
    lsr     x20, x20, #2            // x20 = the EL we started at
    cmp     x20, #2
    b.ne    1f
    // --- EL2 -> EL1 ---
    mov     x1, #(1 << 31)          // HCR_EL2.RW: EL1 is AArch64
    msr     hcr_el2, x1
    mrs     x1, cnthctl_el2
    orr     x1, x1, #3              // EL1PCTEN | EL1PCEN: EL1 may use the timers
    msr     cnthctl_el2, x1
    msr     cntvoff_el2, xzr        // virtual time = physical time
    movz    x1, #0x0800
    movk    x1, #0x30d0, lsl #16    // SCTLR_EL1: RES1 bits only (MMU, caches off)
    msr     sctlr_el1, x1
    mov     x1, #0x3c5              // SPSR: EL1h, D A I F masked
    msr     spsr_el2, x1
    adr     x1, 1f
    msr     elr_el2, x1
    eret
1:
    msr     spsel, #1               // use SP_EL1
    adrp    x1, __stack_top
    add     x1, x1, :lo12:__stack_top
    mov     sp, x1
    adrp    x1, __bss_start
    add     x1, x1, :lo12:__bss_start
    adrp    x2, __bss_end
    add     x2, x2, :lo12:__bss_end
2:  cmp     x1, x2
    b.hs    3f
    str     xzr, [x1], #8
    b       2b
3:  mov     x1, #(3 << 20)          // CPACR_EL1.FPEN = 0b11
    msr     cpacr_el1, x1
    isb
    mov     x0, x19
    mov     x1, x20
    bl      kmain
9:  wfe
    b       9b
"#
);