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

44 lines
2 KiB
Markdown

---
name: schunix-ioremap-and-bars
description: "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"
metadata:
node_type: memory
type: project
originSessionId: d4821aa9-2e49-40da-91e7-90ef9ed9997e
modified: 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.