use crate::mmio::MmioAccess; use crate::queue::{Descriptor, VirtioQueue}; use libkos::Window; use types::address::{ByteOffset, PhysicalAddress}; use types::display::Dimension; /// The command page: commands go out from its start, responses come back /// at `RESPONSE`. pub struct GpuDmaAddrs { pub cmd_pa: PhysicalAddress, pub cmd: Window, pub resp_pa: PhysicalAddress, } pub const RESPONSE: ByteOffset = ByteOffset::new(512); /// Command fields (virtio spec 5.7.6.7): a 24-byte header, then the body. const TYPE: ByteOffset = ByteOffset::new(0); const BODY: ByteOffset = ByteOffset::new(24); /// Most bodies start with a rectangle: x, y, width, height. const RECT_X: ByteOffset = ByteOffset::new(24); const RECT_Y: ByteOffset = ByteOffset::new(28); const RECT_W: ByteOffset = ByteOffset::new(32); const RECT_H: ByteOffset = ByteOffset::new(36); /// The 24 bytes of header and 16 of rectangle in a display-info response. const DISPLAY_W: ByteOffset = ByteOffset::new(24 + 8); const DISPLAY_H: ByteOffset = ByteOffset::new(24 + 12); pub fn create_2d(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, width: Dimension, height: Dimension) -> bool { write_cmd_header(&dma.cmd, 0x0101); // Resource id, format (1: B8G8R8A8), width, height. dma.cmd.write(BODY, resource_id); dma.cmd.write(BODY + 4, 1u32); dma.cmd.write(BODY + 8, width.raw() as u32); dma.cmd.write(BODY + 12, 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, 0x0106); // Resource id, one memory entry: its address and length. dma.cmd.write(BODY, resource_id); dma.cmd.write(BODY + 4, 1u32); dma.cmd.write(BODY + 8, fb_pa.raw() as u64); dma.cmd.write(BODY + 16, 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, 0x0103); // The rectangle (from 0, 0), then scanout and resource ids. dma.cmd.write(RECT_W, width.raw() as u32); dma.cmd.write(RECT_H, height.raw() as u32); dma.cmd.write(BODY + 16, scanout_id); dma.cmd.write(BODY + 20, 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, 0x0105); put_rect(&dma.cmd, x, y, w, h); // Offset into the resource's memory, then the resource id. dma.cmd.write(BODY + 16, 0u64); dma.cmd.write(BODY + 24, 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, 0x0104); put_rect(&dma.cmd, x, y, w, h); dma.cmd.write(BODY + 16, resource_id); submit_cmd(mmio, queue, dma, 48) } fn write_cmd_header(cmd: &Window, cmd_type: u32) { cmd.fill_u32(ByteOffset::ZERO, 128, 0); cmd.write(TYPE, cmd_type); } fn put_rect(cmd: &Window, x: u32, y: u32, w: u32, h: u32) { cmd.write(RECT_X, x); cmd.write(RECT_Y, y); cmd.write(RECT_W, w); cmd.write(RECT_H, h); } pub fn get_display_info(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs) -> Option<(u32, u32)> { write_cmd_header(&dma.cmd, 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; } if dma.cmd.read::(RESPONSE) != 0x1101 { return None; } let w: u32 = dma.cmd.read(RESPONSE + DISPLAY_W.raw()); let h: u32 = dma.cmd.read(RESPONSE + DISPLAY_H.raw()); 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) }