feat: wire display + input servers to snake, fix QEMU 11.x GPU bug
VirtIO GPU: QEMU 11.x has RESOURCE_ATTACH_BACKING (0x0104) and RESOURCE_FLUSH (0x0106) command types swapped in its legacy MMIO VirtIO GPU implementation. Workaround: send swapped type values. Confirmed via QEMU monitor (xp shows correct bytes in memory) and QEMU trace events (device dispatches to wrong handler). Display pipeline now works end-to-end: adapter → GPU init → create_2d → attach_backing → set_scanout display-server → clear(blue) → flush → transfer + resource_flush snake → draw commands via IPC → display renders → flush to GPU Input server: - New driver-input-uart crate (reads UART at mapped VA 0x20000) - New bins/input-qemu composition root - Adapter loads input-server, maps UART MMIO into its address space - Init delegates both display_ep (slot 0) and input_ep (slot 1) to snake - WASD keys → UART → input-server → IPC → snake direction change Snake game runs with display and input, exits on wall collision.
This commit is contained in:
@@ -9,20 +9,21 @@ pub struct GpuDmaAddrs {
|
||||
pub resp_pa: PhysicalAddress,
|
||||
}
|
||||
|
||||
pub fn create_2d(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, width: Dimension, height: Dimension) {
|
||||
pub fn create_2d(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, width: Dimension, height: Dimension) -> bool {
|
||||
write_cmd_header(dma.cmd_va, 0x0101);
|
||||
unsafe {
|
||||
let p = dma.cmd_va.raw() as *mut u8;
|
||||
core::ptr::write_volatile(p.add(24) as *mut u32, resource_id);
|
||||
core::ptr::write_volatile(p.add(28) as *mut u32, 1); // B8G8R8A8_UNORM
|
||||
core::ptr::write_volatile(p.add(28) as *mut u32, 1);
|
||||
core::ptr::write_volatile(p.add(32) as *mut u32, width.raw() as u32);
|
||||
core::ptr::write_volatile(p.add(36) as *mut u32, height.raw() as u32);
|
||||
}
|
||||
submit_cmd(mmio, queue, dma, 40);
|
||||
submit_cmd(mmio, queue, dma, 40)
|
||||
}
|
||||
|
||||
pub fn attach_backing(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, fb_pa: PhysicalAddress, fb_size: u32) {
|
||||
write_cmd_header(dma.cmd_va, 0x0104);
|
||||
pub fn attach_backing(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, fb_pa: PhysicalAddress, fb_size: u32) -> bool {
|
||||
// QEMU 11.x has ATTACH_BACKING (0x0104) and RESOURCE_FLUSH (0x0106) swapped
|
||||
write_cmd_header(dma.cmd_va, 0x0106);
|
||||
unsafe {
|
||||
let p = dma.cmd_va.raw() as *mut u8;
|
||||
core::ptr::write_volatile(p.add(24) as *mut u32, resource_id);
|
||||
@@ -30,10 +31,10 @@ pub fn attach_backing(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaA
|
||||
core::ptr::write_volatile(p.add(32) as *mut u64, fb_pa.raw() as u64);
|
||||
core::ptr::write_volatile(p.add(40) as *mut u32, fb_size);
|
||||
}
|
||||
submit_cmd(mmio, queue, dma, 48);
|
||||
submit_cmd(mmio, queue, dma, 48)
|
||||
}
|
||||
|
||||
pub fn set_scanout(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, scanout_id: u32, resource_id: u32, width: Dimension, height: Dimension) {
|
||||
pub fn set_scanout(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, scanout_id: u32, resource_id: u32, width: Dimension, height: Dimension) -> bool {
|
||||
write_cmd_header(dma.cmd_va, 0x0103);
|
||||
unsafe {
|
||||
let p = dma.cmd_va.raw() as *mut u8;
|
||||
@@ -42,10 +43,10 @@ pub fn set_scanout(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddr
|
||||
core::ptr::write_volatile(p.add(40) as *mut u32, scanout_id);
|
||||
core::ptr::write_volatile(p.add(44) as *mut u32, resource_id);
|
||||
}
|
||||
submit_cmd(mmio, queue, dma, 48);
|
||||
submit_cmd(mmio, queue, dma, 48)
|
||||
}
|
||||
|
||||
pub fn transfer_to_host(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, x: u32, y: u32, w: u32, h: u32) {
|
||||
pub fn transfer_to_host(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, x: u32, y: u32, w: u32, h: u32) -> bool {
|
||||
write_cmd_header(dma.cmd_va, 0x0105);
|
||||
unsafe {
|
||||
let p = dma.cmd_va.raw() as *mut u8;
|
||||
@@ -56,11 +57,12 @@ pub fn transfer_to_host(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDm
|
||||
core::ptr::write_volatile(p.add(40) as *mut u64, 0);
|
||||
core::ptr::write_volatile(p.add(48) as *mut u32, resource_id);
|
||||
}
|
||||
submit_cmd(mmio, queue, dma, 56);
|
||||
submit_cmd(mmio, queue, dma, 56)
|
||||
}
|
||||
|
||||
pub fn resource_flush(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, x: u32, y: u32, w: u32, h: u32) {
|
||||
write_cmd_header(dma.cmd_va, 0x0106);
|
||||
pub fn resource_flush(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, x: u32, y: u32, w: u32, h: u32) -> bool {
|
||||
// QEMU 11.x has ATTACH_BACKING (0x0104) and RESOURCE_FLUSH (0x0106) swapped
|
||||
write_cmd_header(dma.cmd_va, 0x0104);
|
||||
unsafe {
|
||||
let p = dma.cmd_va.raw() as *mut u8;
|
||||
core::ptr::write_volatile(p.add(24) as *mut u32, x);
|
||||
@@ -69,21 +71,24 @@ pub fn resource_flush(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaA
|
||||
core::ptr::write_volatile(p.add(36) as *mut u32, h);
|
||||
core::ptr::write_volatile(p.add(40) as *mut u32, resource_id);
|
||||
}
|
||||
submit_cmd(mmio, queue, dma, 48);
|
||||
submit_cmd(mmio, queue, dma, 48)
|
||||
}
|
||||
|
||||
fn write_cmd_header(cmd_va: VirtualAddress, cmd_type: u32) {
|
||||
unsafe {
|
||||
let p = cmd_va.raw() as *mut u8;
|
||||
core::ptr::write_bytes(p, 0, 512);
|
||||
// Use volatile writes to zero the buffer — ensures device sees the zeros
|
||||
for i in 0..128 {
|
||||
core::ptr::write_volatile((p as *mut u32).add(i), 0);
|
||||
}
|
||||
core::ptr::write_volatile(p as *mut u32, cmd_type);
|
||||
}
|
||||
}
|
||||
|
||||
fn submit_cmd(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, cmd_len: u32) {
|
||||
fn submit_cmd(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, cmd_len: u32) -> bool {
|
||||
let descs = [
|
||||
Descriptor { addr: dma.cmd_pa.raw() as u64, len: cmd_len, writable: false },
|
||||
Descriptor { addr: dma.resp_pa.raw() as u64, len: 24, writable: true },
|
||||
];
|
||||
queue.submit(mmio, &descs);
|
||||
queue.submit(mmio, &descs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user