M2 step 3: route every physical dereference through the physmap

paging.init now builds the physmap (physToVirt(phys)) alongside the low
identity map, so both addressing modes resolve during the transition.
tableAt (the page-table walk hinge), the pmm bitmap, the framebuffer,
LAPIC/IOAPIC/HPET/PM-timer/SPCR MMIO, the ACPI table walk, AML
OperationRegions, the ACPI power registers, the user-ELF frame fills,
and the AP trampoline arm/disarm all reach physical memory through the
physmap. Hal.mapMmio now maps into the physmap and returns the virtual
address, so the device layer never learns the layout. boot_info and its
pointees are converted at kmain entry. The kernel still links and runs
low; identity is the safety net until it's removed. Suite 27/27.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Samson
2026-07-08 22:41:42 +01:00
co-authored by Claude Fable 5
parent 75bc429aa1
commit 724de7bbd0
16 changed files with 143 additions and 59 deletions
+8 -4
View File
@@ -41,7 +41,11 @@ var ap_trampoline_page: u64 = 0;
/// pointer to the handoff data. There is no runtime, no stack unwinding, and no
/// caller to return to, so this never returns.
export fn _start(boot_info: *const BootInfo) callconv(kernel_abi) noreturn {
kmain(boot_info);
// The loader passes a low physical pointer (its own stack). Reach it — and
// everything it points at — through the physmap, so it stays valid once the
// low identity map is gone. The physmap base is the same under the loader's
// bootstrap tables and the kernel's own.
kmain(@ptrFromInt(danos.physToVirt(@intFromPtr(boot_info))));
}
fn kmain(boot_info: *const BootInfo) noreturn {
@@ -82,7 +86,7 @@ fn kmain(boot_info: *const BootInfo) noreturn {
// Summarise the physical memory the loader handed us. The array is danos's
// own MemoryRegion, so this is a plain slice — no firmware layout in sight.
const regions = @as([*]const danos.MemoryRegion, @ptrFromInt(boot_info.memory_map.regions))[0..boot_info.memory_map.len];
const regions = @as([*]const danos.MemoryRegion, @ptrFromInt(danos.physToVirt(boot_info.memory_map.regions)))[0..boot_info.memory_map.len];
var usable_pages: u64 = 0;
var reserved_pages: u64 = 0; // reserved RAM only — MMIO is device space, not RAM
for (regions) |r| {
@@ -141,7 +145,7 @@ fn kmain(boot_info: *const BootInfo) noreturn {
// mapped) and maps PCIe config space on demand via the VMM. A failure here is
// not fatal yet — log it and carry on.
const hal = platform.Hal{
.mapMmio = arch.mapPage,
.mapMmio = arch.mapMmio,
.pioRead = arch.pioRead,
.pioWrite = arch.pioWrite,
};
@@ -253,7 +257,7 @@ fn kmain(boot_info: *const BootInfo) noreturn {
// idle). init becomes a real schedulable process in M3.
if (boot_info.init_len != 0) {
status("starting /sbin/init...\n");
const image = @as([*]const u8, @ptrFromInt(boot_info.init_base))[0..boot_info.init_len];
const image = @as([*]const u8, @ptrFromInt(danos.physToVirt(boot_info.init_base)))[0..boot_info.init_len];
scheduler.setPreemption(false);
const code = usermode.runInitElf(image);
scheduler.setPreemption(true);