summaryrefslogtreecommitdiff
path: root/na/arch/riscv/boot
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:24:56 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-07-10 11:24:56 +0800
commit1767d390fbf3d0c65389de46caf0b6d43ef3b6ad (patch)
tree0f5e01cd7c7a05abb6b1c7472d7f00f49caf02cc /na/arch/riscv/boot
parent63dc025705f6533b91fb1a7d26e6ed864efd9900 (diff)
downloadlume-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.cc471
-rw-r--r--na/arch/riscv/boot/entry.S309
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