riscv64: explicit Bare-mode satp switch (item 4.3.5a)

Punch list §25 item 4.3.5a complete.

Firmware (EDK2 RISC-V) leaves Sv57 paging active at kernel entry with an
identity mapping that has at least one confirmed hole (PLIC threshold
register). Verified live before acting: satp.MODE/PPN and __kernel_start's
address confirmed identity mapping; switched to Bare mode (csrw satp, x0 +
sfence.vma) in arch_early_init(), ahead of pmm_init()/vmm_init().
Three-arch acceptance boot clean, zero exceptions; riscv64's PLIC_THRESHOLD
write now survives (PLIC driver code itself lands separately with 4.3.5b).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-08 11:07:29 -04:00
co-authored by Claude Sonnet 5
parent 06283e5364
commit 36965cf812
16 changed files with 73348 additions and 94 deletions
+57
View File
@@ -9,9 +9,36 @@
*/
#include "arch.h"
#include "console.h"
#include <stdint.h>
extern void riscv64_install_vectors(void);
extern char __kernel_start[]; /* same pattern pmm.c:67 already uses */
/* Item 4.3.5a. Prints satp's MODE/PPN fields and a known running address
* as a permanent boot record (same diagnostic-verbosity convention as
* apic.c's "AArch64: running at EL..." on the other ISA). Confirmed live,
* 2026-08-08: firmware (EDK2 RISC-V) leaves satp.MODE=10 (Sv57) active at
* kernel entry -- not Sv39/Sv48 as this file's own arch_mmu_init() stub
* comment assumed; that comment is stale, corrected below. __kernel_start
* printing here (0xbdd56982 in the confirming boot) landed inside the
* UEFI-reported total physical RAM window (0x80000000 + 1020 MB), near the
* top past the PMM-free region -- consistent with the kernel's own running
* range being identity-mapped (VA==PA) under firmware's Sv57 table, not
* some high canonical virtual range. That is the basis for the Bare-mode
* switch below being safe. */
static void print_hex64(uint64_t val)
{
char buf[19];
buf[0] = '0'; buf[1] = 'x';
for (int i = 15; i >= 0; i--) {
int nibble = (int)(val & 0xF);
buf[2 + i] = (char)(nibble < 10 ? '0' + nibble : 'a' + nibble - 10);
val >>= 4;
}
buf[18] = '\0';
console_puts(buf);
}
/**
* @brief Perform the earliest RISC-V architecture initialisation (no-op).
@@ -26,6 +53,36 @@ extern void riscv64_install_vectors(void);
void arch_early_init(void)
{
/* No GDT/IDT on RISC-V; privilege via exception levels */
uint64_t satp;
__asm__ volatile ("csrr %0, satp" : "=r"(satp));
uint64_t mode = satp >> 60;
uint64_t ppn = satp & 0xFFFFFFFFFFFULL;
console_println("riscv64 item 4.3.5a: satp state at kernel entry (before switch)");
console_puts(" satp.MODE = "); print_hex64(mode); console_puts("\n");
console_puts(" satp.PPN = "); print_hex64(ppn); console_puts("\n");
console_puts(" __kernel_start = "); print_hex64((uint64_t)__kernel_start); console_puts("\n");
/* Explicit switch to Bare mode (satp.MODE=0): this kernel builds no
* riscv64 page table of its own (vmm.c's is x86-64-shaped and never
* activated here, per its own load_cr3() no-op outside __x86_64__) and
* has no present use for virtual memory on this ISA, so there is no
* reason to inherit firmware's Sv57 mapping -- which is confirmed to
* have at least one hole (PLIC_THRESHOLD, FABRIC.md item 4.3.5a).
* ExitBootServices() has already completed several checkpoints before
* this function runs (ConOut/GOP done, BootServices exited per the
* "[CKPT 008]" trace), so nothing downstream depends on firmware's
* table surviving. Single asm block: the CSR write and SFENCE.VMA
* must not be separated by a compiler-scheduled memory access (RISC-V
* Privileged Spec §4.2.1, SFENCE.VMA ordering). */
__asm__ volatile (
"csrw satp, x0\n"
"sfence.vma\n"
::: "memory"
);
console_println("riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a)");
}
/**