virtio-gpu: a modern virtio 1.0 display driver, bring-up to a flushed frame (v2 V3)
The first native scanout backend's driver half. The device manager matches the
virtio-gpu PCI function by its Display/Other class triple and spawns the driver,
which claims the device, confirms vendor 0x1AF4/device 0x1050 from config space,
enables memory-space + bus mastering, and walks the virtio vendor capabilities to
find the common-config and notify structures in its BAR.
From there it is the standard modern-virtio bring-up: reset, negotiate VERSION_1,
stand up the control virtqueue in coherent DMA, then drive the GPU end to end —
RESOURCE_CREATE_2D, ATTACH_BACKING (a coherent DMA buffer; V4 swaps in the shm-
shared surface), SET_SCANOUT, paint a known pattern, TRANSFER_TO_HOST_2D,
RESOURCE_FLUSH, and wait for the device's used-ring ack. Reading the backing back
proves it is CPU-visible RAM; the ack proves the device consumed the frame —
together the automated stand-in for "it's on screen", no screenshot.
- system/drivers/virtio-gpu/: the driver, plus virtio-gpu-protocol.zig (control
commands) and virtio-pci.zig (the 1.0 PCI transport + split-virtqueue), both with
host-tested struct sizes.
- device-manager matches the display/other class triple to "virtio-gpu"; the driver
self-confirms the vendor/device id, since the class alone cannot distinguish it.
- ServiceId.scanout (11): the driver registers it so the compositor finds it in V4.
Gate: python3 test/qemu_test.py virtio-gpu (QEMU -device virtio-gpu-pci) — the
device-manager stack discovers the function, the driver brings up a 640x480 scanout
and flushes a test pattern: "virtio-gpu: scanout 640x480 online" + "flush acked,
pixel check ok". host tests, display-service, shm, and device-list still pass.
Note: the pre-existing pci-scan case triple-faults on main (verified at 88ad432,
before this change); it is unrelated and tracked separately.
This commit is contained in:
@@ -103,6 +103,8 @@ pub fn run(case: []const u8, boot_information: *const BootInformation) void {
|
||||
displayDemoTest(boot_information);
|
||||
} else if (eql(case, "shm")) {
|
||||
shmTest(boot_information);
|
||||
} else if (eql(case, "virtio-gpu")) {
|
||||
virtioGpuTest(boot_information);
|
||||
} else if (eql(case, "clock")) {
|
||||
clockTest();
|
||||
} else if (eql(case, "smp")) {
|
||||
@@ -2409,6 +2411,50 @@ fn shmTest(boot_information: *const BootInformation) void {
|
||||
while (true) scheduler.yield();
|
||||
}
|
||||
|
||||
/// V3 — the virtio-gpu driver, end to end (docs/display-v2.md). Boot the device-manager
|
||||
/// stack (in its normal mode) so it discovers the virtio-gpu PCI function — present because
|
||||
/// the harness boots this case with QEMU's `-device virtio-gpu-pci` — and spawns the driver.
|
||||
/// The driver claims the device, brings up the control virtqueue, creates a 2D scanout,
|
||||
/// paints a known pattern, flushes it, and waits for the device's used-ring ack. Its serial
|
||||
/// heartbeats — `virtio-gpu: scanout WxH online` and `virtio-gpu: flush acked, pixel check
|
||||
/// ok` — are the harness's markers (it reads serial directly, like the display cases). The
|
||||
/// used-ring ack is the device confirming it consumed the frame; the pixel read-back proves
|
||||
/// the backing is CPU-visible RAM — together the automated stand-in for "it's on screen".
|
||||
fn virtioGpuTest(boot_information: *const BootInformation) void {
|
||||
log("DANOS-TEST-BEGIN: virtio-gpu\n", .{});
|
||||
if (boot_information.initial_ramdisk_len == 0) {
|
||||
check("bootloader handed over an initial_ramdisk", false);
|
||||
result();
|
||||
return;
|
||||
}
|
||||
const image = @as([*]const u8, @ptrFromInt(boot_handoff.physicalToVirtual(boot_information.initial_ramdisk_base)))[0..boot_information.initial_ramdisk_len];
|
||||
const rd = initial_ramdisk.Reader.init(image) orelse {
|
||||
check("initial_ramdisk image is valid", false);
|
||||
result();
|
||||
return;
|
||||
};
|
||||
|
||||
// Spawn device-manager in its normal mode: its initialise discovers the PCI host bridge
|
||||
// from the kernel device tree, spawns pci-bus, and matches the virtio-gpu class triple to
|
||||
// spawn our driver with the function's device id as argv[1].
|
||||
process.setInitialRamdisk(image);
|
||||
var manager: u32 = 0;
|
||||
var i: u32 = 0;
|
||||
while (i < rd.count) : (i += 1) {
|
||||
const item = rd.entry(i) orelse continue;
|
||||
if (!eql(item.name, "device-manager")) continue;
|
||||
manager = process.spawnProcessSupervised(item.blob, 4, &.{"device-manager"}, scheduler.currentId(), null) catch 0;
|
||||
break;
|
||||
}
|
||||
if (manager == 0) {
|
||||
log("virtio-gpu: could not spawn device-manager\n", .{});
|
||||
result();
|
||||
return;
|
||||
}
|
||||
scheduler.setPriority(1); // below the manager and the driver it spawns, so they run
|
||||
while (true) scheduler.yield();
|
||||
}
|
||||
|
||||
/// Process arguments, end to end: spawn args-echo bare (its argv[0] is the
|
||||
/// initial-ramdisk name). Instance 1 sees argc == 1 and respawns itself through
|
||||
/// `system_spawn` with the extra arguments "alpha beta-42" — the syscall argument
|
||||
|
||||
Reference in New Issue
Block a user