use crate::mmio::MmioAccess; use crate::queue::{Descriptor, VirtioQueue}; use types::address::{PhysicalAddress, VirtualAddress}; use types::display::Dimension; pub struct GpuDmaAddrs { pub cmd_pa: PhysicalAddress, pub cmd_va: VirtualAddress, pub resp_pa: PhysicalAddress, } 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); 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) } pub fn attach_backing(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, fb_pa: PhysicalAddress, fb_size: u32) -> bool { 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); core::ptr::write_volatile(p.add(28) as *mut u32, 1); 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) } 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; 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); 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) } 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; core::ptr::write_volatile(p.add(24) as *mut u32, x); core::ptr::write_volatile(p.add(28) as *mut u32, y); core::ptr::write_volatile(p.add(32) as *mut u32, w); core::ptr::write_volatile(p.add(36) as *mut u32, h); 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) } pub fn resource_flush(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, 0x0104); unsafe { let p = dma.cmd_va.raw() as *mut u8; core::ptr::write_volatile(p.add(24) as *mut u32, x); core::ptr::write_volatile(p.add(28) as *mut u32, y); core::ptr::write_volatile(p.add(32) as *mut u32, w); 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) } fn write_cmd_header(cmd_va: VirtualAddress, cmd_type: u32) { unsafe { let p = cmd_va.raw() as *mut u8; // 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); } } pub fn get_display_info(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs) -> Option<(u32, u32)> { write_cmd_header(dma.cmd_va, 0x0100); let descs = [ Descriptor { addr: dma.cmd_pa.raw() as u64, len: 24, writable: false }, Descriptor { addr: dma.resp_pa.raw() as u64, len: 408, writable: true }, ]; if !queue.submit(mmio, &descs) { return None; } unsafe { let resp = dma.resp_pa.raw() as usize; let resp_va = dma.cmd_va.raw() + 512; let resp_type = core::ptr::read_volatile(resp_va as *const u32); if resp_type != 0x1101 { return None; } let w = core::ptr::read_volatile((resp_va + 24 + 8) as *const u32); let h = core::ptr::read_volatile((resp_va + 24 + 12) as *const u32); if w > 0 && h > 0 { Some((w, h)) } else { None } } } 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) }