gfx: a framebuffer at physical zero is not a framebuffer
Booting with a virtio-gpu as the *only* display reboot-looped. Not a hang, not
a panic: the firmware came back round to the boot menu, started the loader
again, and did it again, for ever, with nothing to say why.
virtio-gpu has no linear aperture, so OVMF's virtio GOP implements Blt and
nothing else. On a machine with one and nothing else, the firmware reports a
width and a height and a FrameBufferBase of **zero**:
schos: framebuffer 0x0000000000000000 0x500x0x320
Two places took that at face value.
**kmain() tested `if (bi.ptr && ...)` with bi.ptr already run through P2V()**,
and P2V(0) is KERNBASE, which is not zero. So the guard could not fail -- and
its own comment, three lines above, said "drawing into address zero is a worse
failure than staying quiet". The intent was exactly right and the test could
never enforce it. It reads the physical value first now and tests that.
**vga_fb_init() attached the scanout regardless**, one layer down, so fixing
kmain alone just moved the same write.
Either one had gfx_clear() write four megabytes over physical 0: the real-mode
IVT, the BIOS data area, the AP trampoline at 0x7000, the early page tables.
Hence a reset with no output -- there was nothing left to run.
Both refuse now, and the refusal says what it is:
vga: firmware reported a 1280x800 display with no framebuffer address;
no graphical console
A machine with no usable linear framebuffer gets no graphical console. That is
the truth about it, and the serial line still has everything.
**It still does not reach a shell on such a machine**, and that is recorded
rather than implied: the console path assumes a framebuffer -- vt_init()
reports a terminal of `0 by 0` cells -- and that path has never been exercised.
What this fixes is a machine that destroyed low memory and reset; what it does
not do is make a headless boot work. Supported remains stdvga, with virtio-gpu
optional beside it, which is what docs/architecture/graphics.md already said.
Both supported configurations verified: stdvga alone and stdvga with
virtio-gpu, one boot each, no traps, socktest and memfdtest green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
3f2c0bdf05
commit
ff0acfc913
3 changed files with 66 additions and 2 deletions
|
|
@ -67,6 +67,37 @@ splash is drawn on — so `-vga std` must stay on the QEMU command line even whe
|
|||
adding `-device virtio-gpu-pci`, because the loader's splash goes through VBE
|
||||
and there is no virtio path that early.
|
||||
|
||||
### A framebuffer at physical zero is not a framebuffer
|
||||
|
||||
That last sentence used to be advice. It is now enforced, because ignoring it
|
||||
did not produce a machine with no splash — it produced a **reboot loop**.
|
||||
|
||||
virtio-gpu has no linear aperture, so OVMF's virtio GOP implements `Blt` and
|
||||
nothing else. On a machine whose only display is one, the firmware reports a
|
||||
width and a height and a `FrameBufferBase` of **zero**. Two places took that at
|
||||
face value:
|
||||
|
||||
- `kmain()` tested `if (bi.ptr && …)` — with `bi.ptr` already run through
|
||||
`P2V()`, and `P2V(0)` is `KERNBASE`, which is not zero. The guard could not
|
||||
fail, and its own comment said *"drawing into address zero is a worse failure
|
||||
than staying quiet"*. It now tests the physical value before translating it.
|
||||
- `vga_fb_init()` attached the scanout regardless, one layer down.
|
||||
|
||||
Either one wrote four megabytes over physical 0 — the real-mode IVT, the BIOS
|
||||
data area, the AP trampoline at `0x7000`, the early page tables — and the
|
||||
machine reset before it could print anything, came back to the firmware, and
|
||||
did it again.
|
||||
|
||||
Both refuse now and say so. A machine with no usable linear framebuffer gets no
|
||||
graphical console, which is the truth about it; the serial line still has
|
||||
everything.
|
||||
|
||||
**A virtio-gpu-only machine still does not reach a shell.** It no longer
|
||||
corrupts memory and it explains itself, but the console path assumes a
|
||||
framebuffer — `vt_init()` reports a terminal of `0 by 0` cells — and that path
|
||||
has never been exercised. Supported today is stdvga, with virtio-gpu optional
|
||||
beside it.
|
||||
|
||||
`/dev/fb0` speaks the Linux fbdev interface: geometry through the fbdev ioctls,
|
||||
and `mmap` of the real framebuffer at its real physical address.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue