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>
44 lines
2 KiB
Markdown
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.
|