README: rewritten around what runs (Linux software, Xorg, apk, Linux's drivers), the honest gaps, measured numbers. plan/: 1.0.md is the finish line, where each clause of the acceptance test stands, and the register (one failing clause: a root that survives a reboot); built plans (foundations, hybrid, alpine, xorg) and the decided-against one (wayland) are gone, their content lives in architecture/; roadmap.md is only what is still open. guides: building/layout/testing/adding-a-driver (Linux code may be used). history: four entries (ls -lR, TLB shootdowns, MDIO 0x02460246, netlink MSG_TRUNC). Website: cards, stack, download page, docs index. Code comments that pointed at deleted plan docs point at the architecture docs. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
202 lines
6.8 KiB
C
202 lines
6.8 KiB
C
#pragma once
|
|
|
|
// virtio 1.0 over PCI — the transport, and virtio-gpu's 2D protocol.
|
|
//
|
|
// It lived next to the driver while exactly one driver read it, with a note
|
|
// saying it should move when a second reader appeared. One has: cmd/vgpud is
|
|
// the same device driven from userspace (docs/architecture/devices.md's first
|
|
// eviction), and it needs the same register offsets and the same commands.
|
|
//
|
|
// Still one file rather than transport-and-protocol split in two. Both readers
|
|
// want both halves, so a seam here would be drawn for the sake of having one.
|
|
// virtio-net or virtio-blk arriving is when that changes.
|
|
//
|
|
// Written from the OASIS specification (virtio 1.1, chapters 2, 4.1 and 5.7),
|
|
// which is a public document with no licence on what you write from it. Same
|
|
// reasoning as kernel/drivers/xhci.c.
|
|
//
|
|
// Why virtio-gpu at all, when there is already a framebuffer: the VBE
|
|
// framebuffer is a flat block of memory the loader happened to be told about.
|
|
// It has no mode setting, no notion of a frame being complete, and no way to
|
|
// ask the host to present anything -- so a compositor drawing into it is
|
|
// racing the scanout with no way to synchronise. virtio-gpu has resources,
|
|
// explicit transfer and an explicit flush, which is the model every real GPU
|
|
// driver has. It is the smallest device that teaches the right shape.
|
|
|
|
// --- PCI transport ---------------------------------------------------------
|
|
|
|
#define VIRTIO_VENDOR 0x1AF4
|
|
// Modern (1.0) device IDs are 0x1040 + the virtio device type. GPU is type 16.
|
|
#define VIRTIO_DEV_GPU 0x1050
|
|
|
|
// Vendor-specific PCI capability, which is how a virtio device says where in
|
|
// its BARs each configuration structure lives.
|
|
#define PCI_CAP_ID_VNDR 0x09
|
|
|
|
#define VIRTIO_PCI_CAP_COMMON_CFG 1
|
|
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
|
|
#define VIRTIO_PCI_CAP_ISR_CFG 3
|
|
#define VIRTIO_PCI_CAP_DEVICE_CFG 4
|
|
|
|
// Offsets within the common configuration structure. Written out rather than
|
|
// declared as a struct: the fields are little-endian by specification and of
|
|
// mixed width, and a struct invites the compiler to pad or a caller to forget
|
|
// that these are MMIO and must be accessed at exactly the stated width.
|
|
#define VCOMMON_DFEAT_SEL 0x00 // le32
|
|
#define VCOMMON_DFEAT 0x04 // le32
|
|
#define VCOMMON_GFEAT_SEL 0x08 // le32
|
|
#define VCOMMON_GFEAT 0x0C // le32
|
|
#define VCOMMON_MSIX_CFG 0x10 // le16
|
|
#define VCOMMON_NUM_QUEUES 0x12 // le16
|
|
#define VCOMMON_STATUS 0x14 // u8
|
|
#define VCOMMON_CFG_GEN 0x15 // u8
|
|
#define VCOMMON_Q_SELECT 0x16 // le16
|
|
#define VCOMMON_Q_SIZE 0x18 // le16
|
|
#define VCOMMON_Q_MSIX 0x1A // le16
|
|
#define VCOMMON_Q_ENABLE 0x1C // le16
|
|
#define VCOMMON_Q_NOTIFY_OFF 0x1E // le16
|
|
#define VCOMMON_Q_DESC 0x20 // le64
|
|
#define VCOMMON_Q_DRIVER 0x28 // le64
|
|
#define VCOMMON_Q_DEVICE 0x30 // le64
|
|
|
|
// device_status bits, set in this order during bring-up.
|
|
#define VSTATUS_ACK 1
|
|
#define VSTATUS_DRIVER 2
|
|
#define VSTATUS_DRIVER_OK 4
|
|
#define VSTATUS_FEATURES_OK 8
|
|
#define VSTATUS_FAILED 0x80
|
|
|
|
#define VIRTIO_F_VERSION_1 32 // feature bit: this is a 1.0 device
|
|
|
|
// --- split virtqueue -------------------------------------------------------
|
|
|
|
#define VRING_DESC_F_NEXT 1
|
|
|
|
// Set in vring_avail.flags to tell the device not to interrupt on completion.
|
|
//
|
|
// A driver that polls the used ring wants this, and wants it before the queue
|
|
// is enabled. Without it the device raises its interrupt line on every
|
|
// completed command -- and if nothing is registered to acknowledge it, a
|
|
// level-triggered PCI line stays asserted and re-fires for ever. That is the
|
|
// failure in docs/history/kernel.md section 13, and cmd/vgpud reproduced it
|
|
// exactly on its first working run.
|
|
#define VRING_AVAIL_F_NO_INTERRUPT 1
|
|
#define VRING_DESC_F_WRITE 2 // device writes it; i.e. this is our buffer
|
|
|
|
struct vring_desc {
|
|
uint64 addr;
|
|
uint32 len;
|
|
uint16 flags;
|
|
uint16 next;
|
|
} __attribute__((packed));
|
|
|
|
struct vring_avail {
|
|
uint16 flags;
|
|
uint16 idx;
|
|
uint16 ring[];
|
|
} __attribute__((packed));
|
|
|
|
struct vring_used_elem {
|
|
uint32 id;
|
|
uint32 len;
|
|
} __attribute__((packed));
|
|
|
|
struct vring_used {
|
|
uint16 flags;
|
|
uint16 idx;
|
|
struct vring_used_elem ring[];
|
|
} __attribute__((packed));
|
|
|
|
// --- virtio-gpu, 2D --------------------------------------------------------
|
|
|
|
#define VIRTIO_GPU_CMD_GET_DISPLAY_INFO 0x0100
|
|
#define VIRTIO_GPU_CMD_RESOURCE_CREATE_2D 0x0101
|
|
#define VIRTIO_GPU_CMD_RESOURCE_UNREF 0x0102
|
|
#define VIRTIO_GPU_CMD_SET_SCANOUT 0x0103
|
|
#define VIRTIO_GPU_CMD_RESOURCE_FLUSH 0x0104
|
|
#define VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D 0x0105
|
|
#define VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING 0x0106
|
|
|
|
#define VIRTIO_GPU_RESP_OK_NODATA 0x1100
|
|
#define VIRTIO_GPU_RESP_OK_DISPLAY_INFO 0x1101
|
|
|
|
#define VIRTIO_GPU_MAX_SCANOUTS 16
|
|
|
|
// B8G8R8X8, which is what a 32-bit little-endian 0x00RRGGBB word looks like in
|
|
// memory -- the same layout vga.c already draws into, so a framebuffer can be
|
|
// handed over without a conversion pass.
|
|
#define VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM 2
|
|
|
|
struct virtio_gpu_ctrl_hdr {
|
|
uint32 type;
|
|
uint32 flags;
|
|
uint64 fence_id;
|
|
uint32 ctx_id;
|
|
uint32 padding;
|
|
} __attribute__((packed));
|
|
|
|
struct virtio_gpu_rect {
|
|
uint32 x, y, width, height;
|
|
} __attribute__((packed));
|
|
|
|
struct virtio_gpu_display_one {
|
|
struct virtio_gpu_rect r;
|
|
uint32 enabled;
|
|
uint32 flags;
|
|
} __attribute__((packed));
|
|
|
|
struct virtio_gpu_resp_display_info {
|
|
struct virtio_gpu_ctrl_hdr hdr;
|
|
struct virtio_gpu_display_one pmodes[VIRTIO_GPU_MAX_SCANOUTS];
|
|
} __attribute__((packed));
|
|
|
|
struct virtio_gpu_resource_create_2d {
|
|
struct virtio_gpu_ctrl_hdr hdr;
|
|
uint32 resource_id;
|
|
uint32 format;
|
|
uint32 width;
|
|
uint32 height;
|
|
} __attribute__((packed));
|
|
|
|
// Releasing a resource, which a modeset has to do before it can create one of
|
|
// a different size. The backing pages are detached with it; they belong to the
|
|
// driver and are not freed by this.
|
|
struct virtio_gpu_resource_unref {
|
|
struct virtio_gpu_ctrl_hdr hdr;
|
|
uint32 resource_id;
|
|
uint32 padding;
|
|
} __attribute__((packed));
|
|
|
|
struct virtio_gpu_mem_entry {
|
|
uint64 addr;
|
|
uint32 length;
|
|
uint32 padding;
|
|
} __attribute__((packed));
|
|
|
|
struct virtio_gpu_resource_attach_backing {
|
|
struct virtio_gpu_ctrl_hdr hdr;
|
|
uint32 resource_id;
|
|
uint32 nr_entries;
|
|
} __attribute__((packed));
|
|
|
|
struct virtio_gpu_set_scanout {
|
|
struct virtio_gpu_ctrl_hdr hdr;
|
|
struct virtio_gpu_rect r;
|
|
uint32 scanout_id;
|
|
uint32 resource_id;
|
|
} __attribute__((packed));
|
|
|
|
struct virtio_gpu_transfer_to_host_2d {
|
|
struct virtio_gpu_ctrl_hdr hdr;
|
|
struct virtio_gpu_rect r;
|
|
uint64 offset;
|
|
uint32 resource_id;
|
|
uint32 padding;
|
|
} __attribute__((packed));
|
|
|
|
struct virtio_gpu_resource_flush {
|
|
struct virtio_gpu_ctrl_hdr hdr;
|
|
struct virtio_gpu_rect r;
|
|
uint32 resource_id;
|
|
uint32 padding;
|
|
} __attribute__((packed));
|