SchOS/.claude/memory/schunix-virtio-gpu.md
Nexoniarz 3182da3965 Carry project memory in the repo, with tools/memory-sync.sh
Claude Code keeps per-project memory at <home>/.claude/projects/<key>/,
where <key> is the project's absolute path with every separator and the
drive colon turned into a dash. That makes it both rename-fragile and
machine-specific, and this project has hit each of those once:

  - D:\DEV\Schunix -> D:\DEV\SchOS changed the key, and 43 memories were
    invisible until moved across by hand.
  - Development happens from Windows and from Linux, and each looks in a
    different place for the same checkout.

Committing .claude/memory/ fixes both -- git carries it across renames
and between hosts -- and `import` puts it wherever the local machine
expects. .claude/settings.local.json stays ignored: those are per-machine
permissions.

The colon maps to a dash rather than being dropped. Deleting it gives
D-DEV-SchOS, which matches nothing and silently finds zero memories; that
was the first attempt. On Git Bash the key comes from `cygpath -w`,
because Claude Code is a Windows program and sees D:\DEV\SchOS, not
/d/DEV/SchOS.
2026-08-09 14:27:22 +02:00

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/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.