Sixty-five headers sat side by side in include/, so `#include "irq.h"` said nothing about where irq.h was or what it belonged to, and errno.h, stat.h and fcntl.h at the top shadowed the system's for any host tool built with -I./include. They are in folders now -- arch/ core/ fs/ dev/ gfx/ net/ uapi/ (and ldls/ for the Linux driver layer) -- and every include names the folder, as Linux's do: "core/proc.h". Done mechanically and checked the hard way: the kernel built from this tree disassembles identically to the one built from the tree before it. The full image boots, and userland is the same set of programs. Paths in docs and comments follow; docs/guides/layout.md has a table of what is where, and tools/fix-includes.py rewrites old-style includes from the folders in the tree, for code written before this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
59 lines
3 KiB
Markdown
59 lines
3 KiB
Markdown
---
|
|
name: schunix-virtio-gpu
|
|
description: "virtio-gpu 2D driver — the display class's second implementation; how to run it and the transport details that matter."
|
|
metadata:
|
|
node_type: memory
|
|
type: project
|
|
originSessionId: 9d8a2aef-bcf0-47a0-96c6-f706efab4a95
|
|
modified: 2026-08-08T19:59:27.522Z
|
|
---
|
|
|
|
Written 2026-08-08 from the OASIS virtio 1.1 specification (chapters 2, 4.1,
|
|
5.7). `include/dev/virtio.h` + `kernel/drivers/virtio_gpu.c`. Worked on the first
|
|
boot.
|
|
|
|
virtio-gpu: 1280x800, 4000 KB framebuffer, queue 64
|
|
display: 1280x800 32bpp stride 5120
|
|
display: presented a full frame
|
|
|
|
**Run it with:** `-vga std -device virtio-gpu-pci`. Keep `-vga std` — the
|
|
bootloader draws the splash through VBE and there is no virtio path that early,
|
|
so a machine with *only* virtio-gpu boots blind until the kernel is up. Both
|
|
register as `DEVCLASS_DISPLAY`; `registry.c` lists virtio-gpu **first** so
|
|
`device_find_class()` returns it, and vga_pci still claims the stdvga card
|
|
underneath for the splash and text console.
|
|
|
|
**Why it matters over VBE:** presenting is explicit. VBE is a flat aperture with
|
|
no notion of a finished frame, so a compositor races the scanout. Here you
|
|
`TRANSFER_TO_HOST_2D` a rectangle then `RESOURCE_FLUSH` it, and the host never
|
|
shows a half-drawn frame. `acquire()` returns the guest-side framebuffer
|
|
directly — no separate back buffer is needed, because the host cannot see it
|
|
until the transfer. `wait_vblank` is deliberately null: whole rectangles are
|
|
atomic, so there is nothing to synchronise against, and the wrappers in
|
|
device.c handle a null op.
|
|
|
|
**Transport details that are easy to get wrong:**
|
|
- Structures live at an offset inside *whichever BAR the device names* in a
|
|
vendor-specific PCI capability (`PCI_CAP_ID_VNDR`, 0x09). Assuming BAR 0 works
|
|
on QEMU and is exactly the assumption that breaks on the next device.
|
|
- The status handshake order is not negotiable: reset → ACK → DRIVER → read
|
|
features → write features → FEATURES_OK → **read FEATURES_OK back** (the
|
|
device clears it to reject, and that readback is the only way it ever tells
|
|
you) → queues → DRIVER_OK.
|
|
- `VIRTIO_F_VERSION_1` is bit 32, so it lives in the *second* 32-bit window —
|
|
hence the feature-select registers.
|
|
- Notify address is `notify_base + queue_notify_off * notify_off_multiplier`;
|
|
the multiplier is a trailing field of the notify capability only.
|
|
- MMIO accessed at exact widths. The common config has 8/16/32-bit fields
|
|
adjacent, and a device may ignore a wrong-width access silently.
|
|
- 64-bit queue address registers are written as two 32-bit halves, low first.
|
|
|
|
Polled, not interrupt-driven: every caller wants the answer before continuing,
|
|
and the wait is microseconds. The poll loop is bounded so a wedged device
|
|
cannot hang boot.
|
|
|
|
`/proc/devices` name and driver columns are 14 wide because `virtio-gpu0` is
|
|
eleven characters and overran ten.
|
|
|
|
**Not done:** cursor queue, multiple scanouts, mode setting (the resolution is
|
|
whatever the host reports), resource reuse on resolution change, and 3D/virgl.
|