diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:24:56 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-07-10 11:24:56 +0800 |
| commit | 1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (patch) | |
| tree | 0f5e01cd7c7a05abb6b1c7472d7f00f49caf02cc /na/arch/riscv/boot | |
| parent | 63dc025705f6533b91fb1a7d26e6ed864efd9900 (diff) | |
| download | lume-1767d390fbf3d0c65389de46caf0b6d43ef3b6ad.tar.gz lume-1767d390fbf3d0c65389de46caf0b6d43ef3b6ad.tar.xz | |
feat: establish bootable new architecture checkpoint
Replace the compressed boot path with a relocatable higher-half RISC-V entry, expand memory and SMP support, and add the driver, TTY, VFS, exec, signal, syscall, initramfs, and self-test infrastructure needed for a bootable kernel checkpoint.
Diffstat (limited to 'na/arch/riscv/boot')
| -rw-r--r-- | na/arch/riscv/boot/compressed.cc | 471 | ||||
| -rw-r--r-- | na/arch/riscv/boot/entry.S | 309 |
2 files changed, 0 insertions, 780 deletions
diff --git a/na/arch/riscv/boot/compressed.cc b/na/arch/riscv/boot/compressed.cc deleted file mode 100644 index 27513bf..0000000 --- a/na/arch/riscv/boot/compressed.cc +++ /dev/null @@ -1,471 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* Copyright (C) 2026 Richard Qin */ - -#include <arch/config.h> -#include <lume/boot_params.h> -#include <lume/compressed.h> -#include <lume/console.h> -#include <lume/config.h> -#include <lume/decompress.h> -#include <lume/fdt.h> -#include <lume/klog.h> -#include <lume/relocate.h> -#include <lume/types.h> - -extern "C" const CompressedKernelHeader __lume_image_header; -extern "C" char _start[]; -extern "C" char __lume_image_end[]; -extern "C" char __lume_reloc_start[]; -extern "C" char __lume_reloc_end[]; - -struct FdtHeader { - uint32 magic; - uint32 totalsize; - uint32 off_dt_struct; - uint32 off_dt_strings; - uint32 off_mem_rsvmap; - uint32 version; - uint32 last_comp_version; - uint32 boot_cpuid_phys; - uint32 size_dt_strings; - uint32 size_dt_struct; -}; - -struct ReservedRange { - uint64 start; - uint64 end; -}; - -static inline uint32 bswap32(uint32 x) -{ - return ((x & 0xFF000000u) >> 24) | - ((x & 0x00FF0000u) >> 8) | - ((x & 0x0000FF00u) << 8) | - ((x & 0x000000FFu) << 24); -} - -static inline uint64 read_be64(const uint8* p) -{ - uint64 v = 0; - for (int i = 0; i < 8; ++i) { - v = (v << 8) | p[i]; - } - return v; -} - -static inline uint64 addr_to_phys_early(const void* ptr) -{ - uint64 addr = reinterpret_cast<uint64>(ptr); - if (addr >= arch::kDirectMapBaseDefault) { - return addr - arch::kDirectMapBaseDefault; - } - return addr; -} - -static inline uint64 align_down_page(uint64 v) -{ - return v & ~(kPageSize - 1); -} - -static inline bool ranges_overlap(uint64 base, uint64 size, - const ReservedRange& r) -{ - if (size == 0) { - return false; - } - if (base > ~0ULL - size) { - return true; - } - uint64 end = base + size; - return (base < r.end) && (end > r.start); -} - -static uint32 crc32_init() -{ - return 0xFFFFFFFFu; -} - -static uint32 crc32_update(uint32 crc, const uint8* data, uint64 len) -{ - for (uint64 i = 0; i < len; ++i) { - crc ^= data[i]; - for (int b = 0; b < 8; ++b) { - uint32 mask = static_cast<uint32>(-(crc & 1u)); - crc = (crc >> 1) ^ (0xEDB88320u & mask); - } - } - return crc; -} - -static uint32 crc32_final(uint32 crc) -{ - return crc ^ 0xFFFFFFFFu; -} - -static uint32 crc32_bytes(const uint8* data, uint64 len) -{ - return crc32_final(crc32_update(crc32_init(), data, len)); -} - -static void early_put_hex_u64(const char* label, uint64 value) -{ - static const char kHex[] = "0123456789abcdef"; - early_puts(label); - early_puts("0x"); - for (int i = 60; i >= 0; i -= 4) { - early_putc(kHex[(value >> i) & 0xF]); - } - early_putc('\n'); -} - -/* - * boot_stage3_trace — lightweight early-boot diagnostic hook. - * - * Called from entry.S at three points during the decompress/relocate - * flow. Arguments: a0=fdt_paddr, a1=link_base, a2=load_base, a3=phase. - * - * Phase 0: before decompress (load_base not yet known → 0) - * Phase 1: after decompress, before jump - * Phase 2: after flag-set, before re-entry jump - */ -extern "C" void boot_stage3_trace(uint64 fdt_paddr, uint64 link_base, - uint64 load_base, uint64 phase) -{ - /* Phase 0 may fire before console is initialised — keep it cheap. */ - if (phase == 0) { - console_early_init(fdt_paddr); - early_puts("[boot] stage3 trace: phase 0 (pre-decompress)\n"); - return; - } - - static const char* labels[] = { - "[boot] stage3 trace: phase 0\n", - "[boot] stage3 trace: phase 1 (post-decompress)\n", - "[boot] stage3 trace: phase 2 (pre-reentry)\n", - }; - if (phase < 3) { - early_puts(labels[phase]); - } - early_put_hex_u64(" link_base=", link_base); - early_put_hex_u64(" load_base=", load_base); -} - -extern "C" void boot_stage3_loop_panic(uint64 fdt_paddr, uint64 link_base) -{ - console_early_init(fdt_paddr); - early_puts("[boot] stage3 loop detected\n"); - - auto* hdr = reinterpret_cast<const CompressedKernelHeader*>(link_base + 64); - early_put_hex_u64("link_base=", link_base); - early_put_hex_u64("hdr.flags=", hdr->flags); - early_put_hex_u64("hdr.comp=", hdr->compression); - early_put_hex_u64("hdr.uncomp=", hdr->uncompressed_size); - early_put_hex_u64("hdr.comp_size=", hdr->compressed_size); - early_put_hex_u64("hdr.payload_off=", hdr->payload_offset); - early_put_hex_u64("hdr.load_base=", hdr->load_phys_base); - early_put_hex_u64("hdr.reloc_off=", hdr->reloc_offset); - early_put_hex_u64("hdr.reloc_size=", hdr->reloc_size); - - kernel_panic("boot: stage3 loop"); -} - -static int collect_fdt_reserved(uint64 fdt_paddr, ReservedRange* out, int max) -{ - if (!out || max <= 0 || fdt_paddr == 0) { - return 0; - } - - const FdtHeader* hdr = reinterpret_cast<const FdtHeader*>(fdt_paddr); - if (bswap32(hdr->magic) != 0xd00dfeedu) { - return 0; - } - - int count = 0; - uint64 totalsize = bswap32(hdr->totalsize); - if (totalsize != 0 && count < max) { - out[count++] = ReservedRange{fdt_paddr, fdt_paddr + totalsize}; - } - - uint64 rsv_off = bswap32(hdr->off_mem_rsvmap); - const uint8* p = reinterpret_cast<const uint8*>(fdt_paddr + rsv_off); - while (count < max) { - uint64 addr = read_be64(p); - uint64 size = read_be64(p + 8); - p += 16; - if (addr == 0 && size == 0) { - break; - } - if (size == 0) { - continue; - } - out[count++] = ReservedRange{addr, addr + size}; - } - - return count; -} - -static uint64 xorshift64(uint64* state) -{ - uint64 x = *state; - x ^= x << 13; - x ^= x >> 7; - x ^= x << 17; - *state = x; - return x; -} - -static uint64 find_gap_from(uint64 start, uint64 min_base, - const ReservedRange* ranges, int count, - uint64 image_size) -{ - uint64 candidate = align_down_page(start); - - for (int iter = 0; iter < 64; ++iter) { - if (candidate < min_base) { - return 0; - } - - bool hit = false; - uint64 next = candidate; - for (int i = 0; i < count; ++i) { - if (!ranges_overlap(candidate, image_size, ranges[i])) { - continue; - } - hit = true; - if (ranges[i].start < image_size) { - return 0; - } - uint64 below = ranges[i].start - image_size; - below = align_down_page(below); - if (below < next) { - next = below; - } - } - - if (!hit) { - return candidate; - } - if (next >= candidate) { - return 0; - } - candidate = next; - } - - return 0; -} - -static uint64 choose_load_base(uint64 fdt_paddr, uint64 image_size, - uint64 link_base, uint64 payload_base, - uint64 payload_size) -{ - uint64 mem_base = 0; - uint64 mem_size = 0; - FdtManager::early_scan_mem(fdt_paddr, &mem_base, &mem_size); - if (mem_size == 0) { - return link_base; - } - - uint64 mem_top = mem_base + mem_size; - if (mem_top < mem_base || mem_top < image_size) { - return link_base; - } - - ReservedRange reserved[32] = {}; - int count = 0; - - if (count < static_cast<int>(sizeof(reserved) / sizeof(reserved[0]))) { - reserved[count++] = ReservedRange{link_base, link_base + image_size}; - } - if (payload_size != 0 && - count < static_cast<int>(sizeof(reserved) / sizeof(reserved[0]))) { - reserved[count++] = ReservedRange{payload_base, payload_base + payload_size}; - } - count += collect_fdt_reserved(fdt_paddr, reserved + count, - static_cast<int>(sizeof(reserved) / - sizeof(reserved[0])) - count); - - uint64 min_base = align_down_page(mem_base); - uint64 max_base = align_down_page(mem_top - image_size); - if (max_base < min_base) { - return link_base; - } - - uint64 seed = 0; - FdtManager::early_scan_kaslr(fdt_paddr, &seed); - uint64 candidate = max_base; - if (seed != 0) { - seed ^= link_base; - uint64 slots = (max_base - min_base) / kPageSize; - uint64 pick = xorshift64(&seed) % (slots + 1); - candidate = min_base + pick * kPageSize; - } - - uint64 base = find_gap_from(candidate, min_base, reserved, count, image_size); - if (base != 0) { - return base; - } - if (candidate != max_base) { - base = find_gap_from(max_base, min_base, reserved, count, image_size); - if (base != 0) { - return base; - } - } - - return link_base; -} - -extern "C" uint64 boot_decompress_and_relocate(uint64 fdt_paddr) -{ - console_early_init(fdt_paddr); - early_puts("[boot] stage3 start\n"); - - const uint64 image_va_base = reinterpret_cast<uint64>(_start); - uint64 image_size = reinterpret_cast<uint64>(__lume_image_end) - image_va_base; - uint64 reloc_offset = reinterpret_cast<uint64>(__lume_reloc_start) - image_va_base; - uint64 reloc_size = reinterpret_cast<uint64>(__lume_reloc_end) - - reinterpret_cast<uint64>(__lume_reloc_start); - - const uint64 link_base = addr_to_phys_early(_start); - uint64 load_base = link_base; - - uint32 comp = KERNEL_COMP_NONE; - uint32 flags = 0; - uint64 compressed_size = 0; - uint64 payload_offset = 0; - - const CompressedKernelHeader* hdr = &__lume_image_header; - const uint64 header_offset = reinterpret_cast<uint64>(&__lume_image_header) - - image_va_base; - if (hdr->magic == kCompressedKernelMagic && - hdr->version == kCompressedKernelVersion && - hdr->header_size >= sizeof(CompressedKernelHeader)) { - if (hdr->header_crc32 != 0) { - uint32 crc = crc32_init(); - const uint8* hbytes = reinterpret_cast<const uint8*>(hdr); - constexpr uint64 crc_off = offsetof(CompressedKernelHeader, header_crc32); - uint64 header_size = hdr->header_size; - if (header_size > sizeof(CompressedKernelHeader)) { - header_size = sizeof(CompressedKernelHeader); - } - crc = crc32_update(crc, hbytes, crc_off); - uint32 zero = 0; - crc = crc32_update(crc, reinterpret_cast<const uint8*>(&zero), sizeof(zero)); - uint64 tail_off = crc_off + sizeof(uint32); - if (header_size > tail_off) { - crc = crc32_update(crc, hbytes + tail_off, header_size - tail_off); - } - uint32 calc = crc32_final(crc); - if (calc != hdr->header_crc32) { - early_puts("[boot] header crc mismatch\n"); - kernel_panic("boot: header crc mismatch"); - } - } - comp = hdr->compression; - compressed_size = hdr->compressed_size; - if (hdr->uncompressed_size != 0) { - image_size = hdr->uncompressed_size; - } - if (hdr->load_phys_base != 0) { - load_base = hdr->load_phys_base; - } else if (comp != KERNEL_COMP_NONE) { - uint64 payload_base = link_base + payload_offset; - load_base = choose_load_base(fdt_paddr, image_size, link_base, - payload_base, compressed_size); - } - if (hdr->reloc_size != 0) { - reloc_offset = hdr->reloc_offset; - reloc_size = hdr->reloc_size; - } - payload_offset = (hdr->payload_offset != 0) - ? hdr->payload_offset - : hdr->header_size; - } - - if (comp != KERNEL_COMP_NONE && load_base == link_base) { - early_puts("[boot] no safe relocation base\n"); - flags |= BOOT_IMAGE_RELOC_FAILED; - boot_params_set_image_info(load_base, image_size, reloc_offset, - reloc_size, comp, flags); - kernel_panic("boot: no safe relocation base"); - } - - if (comp != KERNEL_COMP_NONE) { - flags |= BOOT_IMAGE_COMPRESSED; - - if (compressed_size == 0 || payload_offset == 0) { - early_puts("[boot] compressed header invalid\n"); - flags |= BOOT_IMAGE_DECOMP_FAILED; - boot_params_set_image_info(load_base, image_size, reloc_offset, - reloc_size, comp, flags); - kernel_panic("boot: compressed header invalid"); - } - - if (hdr->payload_crc32 != 0) { - const uint8* payload = reinterpret_cast<const uint8*>( - image_va_base + payload_offset); - uint32 calc = crc32_bytes(payload, compressed_size); - if (calc != hdr->payload_crc32) { - early_puts("[boot] payload crc mismatch\n"); - flags |= BOOT_IMAGE_DECOMP_FAILED; - boot_params_set_image_info(load_base, image_size, reloc_offset, - reloc_size, comp, flags); - kernel_panic("boot: payload crc mismatch"); - } - } - - if (comp == KERNEL_COMP_LZ4) { - const uint8* payload = reinterpret_cast<const uint8*>( - image_va_base + payload_offset); - uint8* out = reinterpret_cast<uint8*>(load_base); - int written = lz4_decompress(payload, - static_cast<uint32>(compressed_size), - out, static_cast<uint32>(image_size)); - if (written < 0 || static_cast<uint64>(written) != image_size) { - early_puts("[boot] lz4 decompress failed\n"); - flags |= BOOT_IMAGE_DECOMP_FAILED; - boot_params_set_image_info(load_base, image_size, reloc_offset, - reloc_size, comp, flags); - kernel_panic("boot: lz4 decompress failed"); - } - } else { - early_puts("[boot] unsupported compression\n"); - flags |= BOOT_IMAGE_DECOMP_FAILED; - boot_params_set_image_info(load_base, image_size, reloc_offset, - reloc_size, comp, flags); - kernel_panic("boot: unsupported compression"); - } - } - - if (reloc_size != 0 && load_base != link_base) { - if (reloc_offset + reloc_size > image_size) { - early_puts("[boot] reloc table out of range\n"); - flags |= BOOT_IMAGE_RELOC_FAILED; - boot_params_set_image_info(load_base, image_size, reloc_offset, - reloc_size, comp, flags); - kernel_panic("boot: reloc table out of range"); - } - const void* reloc_blob = reinterpret_cast<const void*>( - image_va_base + reloc_offset); - RelocStatus st = relocate_apply(load_base, image_size, link_base, - reloc_blob, reloc_size); - if (st != RELOC_OK) { - early_puts("[boot] relocation failed\n"); - flags |= BOOT_IMAGE_RELOC_FAILED; - boot_params_set_image_info(load_base, image_size, reloc_offset, - reloc_size, comp, flags); - kernel_panic("boot: relocation failed", reloc_status_str(st)); - } - flags |= BOOT_IMAGE_RELOCATED; - } - - if (load_base != link_base) { - auto* new_hdr = reinterpret_cast<CompressedKernelHeader*>( - load_base + header_offset); - new_hdr->flags |= LUME_HDR_FLAG_STAGE3_DONE; - } - - early_puts("[boot] stage3 done\n"); - boot_params_set_image_info(load_base, image_size, reloc_offset, - reloc_size, comp, flags); - return load_base; -} diff --git a/na/arch/riscv/boot/entry.S b/na/arch/riscv/boot/entry.S deleted file mode 100644 index 9154b7f..0000000 --- a/na/arch/riscv/boot/entry.S +++ /dev/null @@ -1,309 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* Copyright (C) 2026 Richard Qin */ - -/* - * LumeOS Kernel Entry Point (RISC-V 64) - * - * This file implements the earliest boot sequence: - * 1. RISC-V Linux Boot Protocol Image Header (64 bytes) - * 2. BSP/AP synchronization - * 3. BSS zeroing (BSP only) - * 4. Early page table setup (1GB superpages for identity + higher-half) - * 5. MMU enable and higher-half trampoline - * 6. C++ global constructor invocation - * 7. Jump to kernel_main() - * - * Register contract on entry (from OpenSBI / GRUB / U-Boot): - * a0 = CPU ID (Hart ID) - * a1 = FDT physical base address - * - * Reference: docs/specs/linker_and_entry.md - */ - -#include <lume/config.h> - -#define PAGE_OFFSET 0xFFFFFFC000000000 -#define BOOT_STACK_SIZE 8192 - -/* SV39 PTE flags */ -#define PTE_V (1 << 0) /* Valid */ -#define PTE_R (1 << 1) /* Readable */ -#define PTE_W (1 << 2) /* Writable */ -#define PTE_X (1 << 3) /* Executable */ -#define PTE_A (1 << 6) /* Accessed */ -#define PTE_D (1 << 7) /* Dirty */ - -/* SATP mode field for SV39 */ -#define SATP_SV39 (8UL << 60) - -/* LumeOS compressed image header constants */ -#define LUME_COMP_NONE 0 -#define LUME_HDR_SIZE 80 -#define LUME_HDR_MAGIC 0x4C554D45434F4D50 /* "LUMECOMP" */ -#define LUME_HDR_OFF 64 -#define LUME_HDR_FLAGS_OFF 14 -#define LUME_HDR_FLAG_STAGE3_DONE 0x1 - -/* ======================================================================== - * Section: .head.text — RISC-V Linux Boot Protocol Image Header - * Must be at byte 0 of the kernel binary. - * ======================================================================== */ - .section .head.text, "ax" - .globl _start -_start: - /* code0 (u32, offset 0): executable jump for OpenSBI bare boot */ - j real_start - /* code1 (u32, offset 4): reserved */ - .word 0 - /* text_offset (u64, offset 8): load offset from RAM base */ - .dword 0x200000 - /* image_size (u64, offset 16): will be filled post-link, 0 = unknown */ - .dword 0 - /* flags (u64, offset 24): bit 0: 0=LE, 1=BE */ - .dword 0 - /* version (u32, offset 32): header version 0.2 */ - .word 0x0002 - /* res1 (u32, offset 36) */ - .word 0 - /* res2 (u64, offset 40) */ - .dword 0 - /* magic (u64, offset 48): RISCV_IMAGE_MAGIC "RISCV\0\0\0" LE */ - .dword 0x5643534952 - /* magic2 (u32, offset 56): RISCV_IMAGE_MAGIC2 "RSC\x05" LE */ - .word 0x05435352 - /* res3 (u32, offset 60): reserved for PE/COFF */ - .word 0 - - /* LumeOS compressed kernel header (80 bytes) */ - .align 3 - .globl __lume_image_header -__lume_image_header: - .dword LUME_HDR_MAGIC /* magic */ - .word 1 /* version */ - .half LUME_HDR_SIZE /* header_size */ - .half 0 /* flags */ - .word LUME_COMP_NONE /* compression */ - .word 0 /* reserved0 */ - .dword __lume_image_end - _start /* uncompressed_size */ - .dword 0 /* compressed_size */ - .dword 0 /* load_phys_base (0 = auto) */ - .dword __lume_reloc_start - _start /* reloc_offset */ - .dword __lume_reloc_end - __lume_reloc_start /* reloc_size */ - .dword _ebss - _start /* payload_offset (when compressed) */ - .word 0 /* header_crc32 */ - .word 0 /* payload_crc32 */ - -/* ======================================================================== - * real_start: Actual boot logic begins here (all CPUs land here) - * ======================================================================== */ - .text - .globl real_start -real_start: - /* ---- Step 1: Disable interrupts ---- */ - csrw sie, zero - csrw sip, zero - - /* ---- Step 2: Set up gp (global pointer) ---- */ - /* Critical for medany model: all global variable access goes through gp */ - .option push - .option norelax - la gp, __global_pointer$ - .option pop - - /* ---- Step 3: Set up per-CPU boot stack ---- */ - /* sp = boot_stack + (cpu_id + 1) * BOOT_STACK_SIZE */ - la t0, boot_stack - li t1, BOOT_STACK_SIZE - addi t2, a0, 1 /* t2 = cpu_id + 1 */ - mul t1, t1, t2 /* t1 = (cpu_id + 1) * BOOT_STACK_SIZE */ - add sp, t0, t1 - - /* ---- Step 4: Store boot args (cpu_id and fdt_paddr) ---- */ - mv tp, a0 /* tp = cpu_id */ - mv s0, a1 /* s0 = fdt_paddr (preserved across all C++ calls) */ - /* ---- Step 5: BSP / AP divergence ---- */ - /* CPU 0 is the BSP; all others spin-wait */ - bnez a0, .Lap_wait - -/* =================================================================== - * BSP-only path: Clear BSS, set up early page table, release APs - * =================================================================== */ -.Lbsp_init: - /* ---- 5.1: Clear BSS ---- */ - la t0, _sbss - la t1, _ebss -.Lbss_loop: - bgeu t0, t1, .Lbss_done - sd zero, 0(t0) - addi t0, t0, 8 - j .Lbss_loop -.Lbss_done: - - - /* ---- 5.2: Build early page table (1GB superpages) ---- */ - /* - * SV39 root page table (512 entries x 8 bytes = 4KB) - * We need 4 entries: - * [0] = Identity map: 0x00000000 -> 0x00000000 (MMIO: UART, PLIC, CLINT) - * [2] = Identity map: 0x80000000 -> 0x80000000 (RAM) - * [256] = Higher-half: 0xFFFFFFC000000000 -> 0x00000000 (MMIO via VA) - * [258] = Higher-half: 0xFFFFFFC080000000 -> 0x80000000 (RAM via VA) - * - * VPN[2] index = (VA >> 30) & 0x1FF - * 0x00000000 -> 0 0xFFFFFFC000000000 -> 256 - * 0x80000000 -> 2 0xFFFFFFC080000000 -> 258 - */ - la t0, early_pgdir - - /* PTE flags: V|R|W|X|A|D (1GB leaf superpage) */ - li t2, (PTE_V | PTE_R | PTE_W | PTE_X | PTE_A | PTE_D) - - /* --- MMIO region: physical 0x00000000 --- */ - /* PPN = 0x00000000 >> 12 = 0, PTE = flags only */ - mv t1, t2 /* PTE = 0 | flags */ - - /* Entry [0]: Identity map MMIO */ - sd t1, (0 * 8)(t0) - - /* Entry [256]: Higher-half MMIO (0xFFFFFFC000000000) */ - li t3, (256 * 8) - add t3, t0, t3 - sd t1, 0(t3) - - /* --- RAM region: physical 0x80000000 --- */ - li t1, 0x80000 /* PPN = 0x80000000 >> 12 */ - slli t1, t1, 10 /* PPN field in PTE */ - or t1, t1, t2 /* t1 = complete PTE */ - - /* Entry [2]: Identity map RAM */ - sd t1, (2 * 8)(t0) - - /* Entry [258]: Higher-half RAM (0xFFFFFFC080000000) */ - li t3, (258 * 8) - add t3, t0, t3 - sd t1, 0(t3) - - - /* ---- 5.3: Memory fence ---- */ - fence rw, rw - - /* ---- 5.4: Release APs ---- */ - la t0, boot_sync_flag - li t1, 1 - amoswap.w.rl zero, t1, (t0) - j .Lenable_mmu - -/* =================================================================== - * AP path: spin-wait until BSP signals readiness - * =================================================================== */ -.Lap_wait: - la t0, boot_sync_flag -.Lap_spin: - lw t1, 0(t0) - beqz t1, .Lap_spin - fence r, rw /* Acquire: ensure we see BSP's writes */ - -/* =================================================================== - * All CPUs: Enable MMU and jump to higher-half virtual addresses - * =================================================================== */ -.Lenable_mmu: - - - /* ---- 6.1: Write satp = SV39 mode | (early_pgdir >> 12) ---- */ - /* NOTE: `la` at this point is PC-relative. Since we are still executing - * at physical addresses, it yields the PHYSICAL address directly. - * No VA-to-PA conversion needed. */ - la t0, early_pgdir - srli t0, t0, 12 /* PPN = PA >> 12 */ - li t1, SATP_SV39 - or t0, t0, t1 /* satp = mode | PPN */ - csrw satp, t0 - - /* ---- 6.2: Flush TLB ---- */ - sfence.vma zero, zero - - /* ---- 6.3: Jump to higher-half virtual address ---- */ - /* Now we are executing via the identity map (PA == VA for 0x8...). - * `la` is PC-relative (medany), so it yields a PHYSICAL address. - * We must add PAGE_OFFSET to convert to the higher-half VA. */ - la t0, .Lhigher_half - li t1, PAGE_OFFSET - add t0, t0, t1 - jr t0 - -.Lhigher_half: - /* We are now running at virtual addresses (0xFFFFFFC0...) ! - * The identity map is still active but will be removed by vmm_init(). */ - - /* ---- 6.4: Fix sp and gp to virtual addresses ---- */ - /* sp was set up before MMU using PC-relative `la`, so it holds a - * physical address. Add PAGE_OFFSET to convert to higher-half VA. - * gp is similarly reloaded — now that PC is at VA, `la` resolves - * correctly via PC-relative addressing. */ - li t0, PAGE_OFFSET - add sp, sp, t0 - .option push - .option norelax - la gp, __global_pointer$ - .option pop - - /* Mark MMU enabled for early console mapping logic */ - call console_set_mmu_enabled - - /* ---- Step 7: BSP calls early_cpp_init ---- */ - bnez tp, .Lskip_cpp_init - - /* BSP only: invoke C++ global constructors */ - call early_cpp_init - -.Lskip_cpp_init: - - /* All CPUs: enter kernel_main(cpu_id, fdt_paddr) */ - mv a0, tp /* a0 = cpu_id (from tp) */ - mv a1, s0 /* a1 = fdt_paddr (from s0) */ - call kernel_main - - /* kernel_main should never return; if it does, halt */ -.Lhalt: - csrc sstatus, 2 /* Clear SIE */ - wfi - j .Lhalt - - -/* ======================================================================== - * early_cpp_init: Traverse .init_array and call global constructors - * Called by BSP only, before kernel_main. - * ======================================================================== */ - .globl early_cpp_init -early_cpp_init: - /* Prologue: save ra and callee-saved regs we use as loop state */ - addi sp, sp, -32 - sd ra, 0(sp) - sd s1, 8(sp) - sd s2, 16(sp) - - la s1, __init_array_start - la s2, __init_array_end -.Linit_loop: - bgeu s1, s2, .Linit_done - ld t0, 0(s1) /* Load function pointer */ - jalr ra, t0 /* Call constructor (sets ra = return addr) */ - addi s1, s1, 8 /* Next entry */ - j .Linit_loop -.Linit_done: - /* Epilogue: restore and return */ - ld ra, 0(sp) - ld s1, 8(sp) - ld s2, 16(sp) - addi sp, sp, 32 - ret - - -/* ======================================================================== - * BSS Data: boot_sync_flag - * ======================================================================== */ - .section .bss - .align 2 - .globl boot_sync_flag -boot_sync_flag: - .word 0 |
