riscv64: skip satp Bare-mode switch when already Bare (§V.3 item 7 audit fix)
arch_early_init() unconditionally cleared satp on every boot, justified only by behavior observed under QEMU/EDK2 firmware (satp.MODE=10/Sv57, kernel identity-mapped within it). That reasoning never applied to the native U-Boot+OpenSBI boot path, where satp is conventionally already 0 at S-mode handoff -- the unconditional clear was likely a harmless no-op there, but on an unverified assumption. Fix: read satp.MODE first and return early when it's already 0 (nothing to switch away from, no safety argument needed). The unconditional csrw/sfence pair still runs unchanged for the confirmed QEMU/EDK2 case. No Sv39/Sv48/Sv57 page-table walker built -- out of proportion to this finding's severity. 3-arch acceptance: amd64/aarch64 don't compile this file, so their runs are non-regression on untouched files only. riscv64's own boot log confirms satp.MODE = 0xa at entry, so the mode != 0 branch ran and "satp cleared -- Bare mode, explicit" printed exactly as before the fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
350287850f
commit
90ee8deb6d
@@ -26,7 +26,10 @@ extern char __kernel_start[]; /* same pattern pmm.c:67 already uses */
|
||||
* 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. */
|
||||
* switch below being safe *when firmware leaves a translation active at
|
||||
* all* -- see arch_early_init()'s own comment (FABRIC-3.md §V.3 item 7
|
||||
* fix, 2026-09-04) for why that no longer covers every boot path this
|
||||
* kernel now has. */
|
||||
static void print_hex64(uint64_t val)
|
||||
{
|
||||
char buf[19];
|
||||
@@ -49,6 +52,27 @@ static void print_hex64(uint64_t val)
|
||||
* via @c riscv64_install_vectors(). This stub satisfies the common
|
||||
* @c arch_early_init() call site in @c kernel_main() without any
|
||||
* RISC-V-specific action.
|
||||
*
|
||||
* **Correction, 2026-09-04 (FABRIC-3.md §V.3 item 7's code audit).** The
|
||||
* unconditional Bare-mode switch this function used to perform was
|
||||
* justified entirely by behaviour observed under this system's QEMU/EDK2
|
||||
* RISC-V firmware (@c satp.MODE=10/Sv57, kernel identity-mapped within
|
||||
* it — see the comment on @c print_hex64() above). That observation
|
||||
* cannot apply to the native boot path (U-Boot+OpenSBI, no EDK2 at all,
|
||||
* FABRIC-3.md §V.1) this kernel now also has, and OpenSBI's own S-mode
|
||||
* handoff convention leaves @c satp already at 0 (Bare) in the common
|
||||
* case — meaning the switch below was very likely running as a harmless
|
||||
* no-op there, but on an unverified assumption rather than a checked one.
|
||||
* Rather than build a general Sv39/Sv48/Sv57 page-table walker just to
|
||||
* *prove* the running address is identity-mapped before switching (out of
|
||||
* proportion to this item's real scope), the fix narrows what actually
|
||||
* needs the QEMU-specific safety argument: **skip the switch entirely
|
||||
* when @c satp is already 0.** That is the expected case on both a
|
||||
* from-Bare native boot and any firmware that already left translation
|
||||
* off, and it needs no safety argument at all — there is nothing to
|
||||
* switch away from. The unconditional-switch path still exists for the
|
||||
* confirmed QEMU/EDK2 case (@c mode != 0), where the identity-mapping
|
||||
* argument above remains the actual justification, unchanged.
|
||||
*/
|
||||
void arch_early_init(void)
|
||||
{
|
||||
@@ -64,18 +88,33 @@ void arch_early_init(void)
|
||||
console_puts(" satp.PPN = "); print_hex64(ppn); console_puts("\n");
|
||||
console_puts(" __kernel_start = "); print_hex64((uint64_t)__kernel_start); console_puts("\n");
|
||||
|
||||
if (mode == 0) {
|
||||
/* Already Bare -- the expected case on a native (OpenSBI) boot.
|
||||
* Nothing to switch away from, so no identity-mapping assumption
|
||||
* is needed at all: skipping is strictly safer than an
|
||||
* unconditional csrw+sfence that would just write back the same
|
||||
* zero value. */
|
||||
console_println("riscv64: satp already Bare -- no switch needed (item 4.3.5a)");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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-0.md item 4.3.5a).
|
||||
* ExitBootServices() has already completed several checkpoints before
|
||||
* this function runs (ConOut/GOP done, BootServices exited per the
|
||||
* reason to inherit firmware's mapping -- which is confirmed, for the
|
||||
* QEMU/EDK2 case this branch was written for, to have at least one
|
||||
* hole (PLIC_THRESHOLD, FABRIC-0.md item 4.3.5a). ExitBootServices()
|
||||
* has already completed several checkpoints before this function
|
||||
* runs on that path (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). */
|
||||
* table surviving there. On the native boot path, reaching this
|
||||
* branch at all means OpenSBI's handoff left satp non-zero -- not
|
||||
* the case this kernel has confirmed, so the identity-mapping safety
|
||||
* argument is unverified here; flagged, not guessed past. 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"
|
||||
|
||||
Reference in New Issue
Block a user