SchOS/.claude/memory/schunix-ioremap-and-bars.md
Nexoniarz b428a50145 memory: UEFI reaches userspace, and the ISO grows a hierarchy
Records the four bugs between "boots to cpu0: starting" and "boots to an
interactive shell", the new ioremap rule for device registers, and what
the disc now contains -- including that it is still not a live CD, and
what that would take.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 22:04:12 +02:00

2 KiB

name description metadata
schunix-ioremap-and-bars ioremap() maps device registers; never use P2V on a BAR, because firmware may place a 64-bit BAR far above the 4 GB direct map
node_type type originSessionId modified
memory project d4821aa9-2e49-40da-91e7-90ef9ed9997e 2026-08-09T20:03:56.063Z

Never reach a device's registers with P2V(bar.base). Use ioremap(pa, size) from kernel/arch/x86_64/vm.c (declared in include/defs.h).

Every driver used to do the P2V thing, which silently assumes the BAR lands inside the 0-4 GB that kvmalloc() direct-maps with four 1 GB pages. Under SeaBIOS it always does. Under OVMF it does not — virtio-gpu's 64-bit BAR came back at about 768 GB, P2V produced an address with no translation behind it, and the first register write page faulted, then double faulted, then triple faulted into a reboot loop. Coming out of a driver bind, that reads as broken hardware rather than a missing mapping.

How it works

PDPT entries 4-511 were unused: the direct map occupies 0-3, and kpml4[0], kpml4[KERNBASE] and every process's PML4 (see setupkvm) all point at that same table. So each MMIO region takes one 1 GB page there — no page table to allocate, and the mapping appears in every address space at once. Entries are PTE_PCD | PTE_PWT for the same reason the top GB of the direct map is: these are registers, and a write sitting in a cache line is a write the device never sees.

A physical address below 4 GB is returned unchanged, as P2V would have. That is what makes the BIOS path — where every BAR is low — provably identical rather than merely tested.

Where this bites next

Converted: virtio-gpu, e1000, xhci. xHCI had already been refusing to bind above 4 GB with a comment saying the mapping did not exist yet.

Any new driver that reads a BAR needs the same treatment. grep -rn 'P2V(d->bar' kernel/ should stay empty.

See schos-uefi-loader for the boot path this unblocked.