refactor: ByteOffset newtype for window/register/ring offsets; named virtio-gpu cmd fields
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use crate::mmio::MmioAccess;
|
||||
use crate::queue::{Descriptor, VirtioQueue};
|
||||
use libkos::Window;
|
||||
use types::address::PhysicalAddress;
|
||||
use types::address::{ByteOffset, PhysicalAddress};
|
||||
|
||||
const SECTOR_SIZE: usize = 512;
|
||||
|
||||
@@ -16,11 +16,15 @@ pub struct DmaAddrs {
|
||||
pub data: Window,
|
||||
}
|
||||
|
||||
const HEADER_TYPE: ByteOffset = ByteOffset::new(0);
|
||||
const HEADER_RESERVED: ByteOffset = ByteOffset::new(4);
|
||||
const HEADER_SECTOR: ByteOffset = ByteOffset::new(8);
|
||||
|
||||
fn put_header(dma: &DmaAddrs, req_type: u32, sector: u32) {
|
||||
dma.header.write(0, req_type);
|
||||
dma.header.write(4, 0u32);
|
||||
dma.header.write(8, sector as u64);
|
||||
dma.status.write(0, 0xFFu8);
|
||||
dma.header.write(HEADER_TYPE, req_type);
|
||||
dma.header.write(HEADER_RESERVED, 0u32);
|
||||
dma.header.write(HEADER_SECTOR, sector as u64);
|
||||
dma.status.write(ByteOffset::ZERO, 0xFFu8);
|
||||
}
|
||||
|
||||
pub fn read_sector(
|
||||
@@ -42,15 +46,15 @@ pub fn read_sector(
|
||||
|
||||
if !queue.submit(mmio, &descs) { return false; }
|
||||
|
||||
if dma.status.read::<u8>(0) != 0 { return false; }
|
||||
dma.data.copy_to(0, &mut buf[..SECTOR_SIZE]);
|
||||
if dma.status.read::<u8>(ByteOffset::ZERO) != 0 { return false; }
|
||||
dma.data.copy_to(ByteOffset::ZERO, &mut buf[..SECTOR_SIZE]);
|
||||
true
|
||||
}
|
||||
|
||||
/// Request types (virtio spec 5.2.6).
|
||||
const T_OUT: u32 = 1;
|
||||
/// Device configuration: the disk's size in 512-byte sectors (le64).
|
||||
pub const CONFIG_CAPACITY: usize = 0x100;
|
||||
pub const CONFIG_CAPACITY: ByteOffset = ByteOffset::new(0x100);
|
||||
|
||||
/// Writes one sector from `buf`; true once the device reports success.
|
||||
pub fn write_sector(
|
||||
@@ -62,7 +66,7 @@ pub fn write_sector(
|
||||
) -> bool {
|
||||
if buf.len() < SECTOR_SIZE { return false; }
|
||||
|
||||
dma.data.copy_from(0, &buf[..SECTOR_SIZE]);
|
||||
dma.data.copy_from(ByteOffset::ZERO, &buf[..SECTOR_SIZE]);
|
||||
put_header(dma, T_OUT, sector);
|
||||
|
||||
// The device reads the data this time; only the status is written back.
|
||||
@@ -72,5 +76,5 @@ pub fn write_sector(
|
||||
Descriptor { addr: dma.status_pa.raw() as u64, len: 1, writable: true },
|
||||
];
|
||||
if !queue.submit(mmio, &descs) { return false; }
|
||||
dma.status.read::<u8>(0) == 0
|
||||
dma.status.read::<u8>(ByteOffset::ZERO) == 0
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::mmio::MmioAccess;
|
||||
use crate::queue::{Descriptor, VirtioQueue};
|
||||
use libkos::Window;
|
||||
use types::address::PhysicalAddress;
|
||||
use types::address::{ByteOffset, PhysicalAddress};
|
||||
use types::display::Dimension;
|
||||
|
||||
/// The command page: commands go out from its start, responses come back
|
||||
@@ -12,59 +12,76 @@ pub struct GpuDmaAddrs {
|
||||
pub resp_pa: PhysicalAddress,
|
||||
}
|
||||
|
||||
pub const RESPONSE: usize = 512;
|
||||
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);
|
||||
dma.cmd.write(24, resource_id);
|
||||
dma.cmd.write(28, 1u32);
|
||||
dma.cmd.write(32, width.raw() as u32);
|
||||
dma.cmd.write(36, height.raw() as u32);
|
||||
// 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);
|
||||
dma.cmd.write(24, resource_id);
|
||||
dma.cmd.write(28, 1u32);
|
||||
dma.cmd.write(32, fb_pa.raw() as u64 as u64);
|
||||
dma.cmd.write(40, fb_size);
|
||||
// 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);
|
||||
dma.cmd.write(32, width.raw() as u32);
|
||||
dma.cmd.write(36, height.raw() as u32);
|
||||
dma.cmd.write(40, scanout_id);
|
||||
dma.cmd.write(44, resource_id);
|
||||
// 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);
|
||||
dma.cmd.write(24, x);
|
||||
dma.cmd.write(28, y);
|
||||
dma.cmd.write(32, w);
|
||||
dma.cmd.write(36, h);
|
||||
dma.cmd.write(40, 0u64);
|
||||
dma.cmd.write(48, resource_id);
|
||||
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);
|
||||
dma.cmd.write(24, x);
|
||||
dma.cmd.write(28, y);
|
||||
dma.cmd.write(32, w);
|
||||
dma.cmd.write(36, h);
|
||||
dma.cmd.write(40, resource_id);
|
||||
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(0, 128, 0);
|
||||
cmd.write(0, cmd_type);
|
||||
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)> {
|
||||
@@ -75,8 +92,8 @@ pub fn get_display_info(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDm
|
||||
];
|
||||
if !queue.submit(mmio, &descs) { return None; }
|
||||
if dma.cmd.read::<u32>(RESPONSE) != 0x1101 { return None; }
|
||||
let w: u32 = dma.cmd.read(RESPONSE + 24 + 8);
|
||||
let h: u32 = dma.cmd.read(RESPONSE + 24 + 12);
|
||||
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 }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
use types::address::ByteOffset;
|
||||
|
||||
pub trait MmioAccess {
|
||||
fn read(&self, offset: usize) -> u32;
|
||||
fn write(&self, offset: usize, val: u32);
|
||||
fn read(&self, offset: ByteOffset) -> u32;
|
||||
fn write(&self, offset: ByteOffset, val: u32);
|
||||
}
|
||||
|
||||
pub const MAGIC: u32 = 0x74726976;
|
||||
|
||||
pub const REG_MAGIC: usize = 0x000;
|
||||
pub const REG_VERSION: usize = 0x004;
|
||||
pub const REG_DEVICE_ID: usize = 0x008;
|
||||
pub const REG_STATUS: usize = 0x070;
|
||||
pub const REG_GUEST_PAGE_SIZE: usize = 0x028;
|
||||
pub const REG_FEATURES_SEL: usize = 0x014;
|
||||
pub const REG_FEATURES: usize = 0x010;
|
||||
pub const REG_DRIVER_FEATURES_SEL: usize = 0x024;
|
||||
pub const REG_DRIVER_FEATURES: usize = 0x020;
|
||||
pub const REG_QUEUE_SEL: usize = 0x030;
|
||||
pub const REG_QUEUE_NUM_MAX: usize = 0x034;
|
||||
pub const REG_QUEUE_NUM: usize = 0x038;
|
||||
pub const REG_QUEUE_PFN: usize = 0x040;
|
||||
pub const REG_QUEUE_NOTIFY: usize = 0x050;
|
||||
pub const REG_INTERRUPT_STATUS: usize = 0x060;
|
||||
pub const REG_INTERRUPT_ACK: usize = 0x064;
|
||||
pub const REG_MAGIC: ByteOffset = ByteOffset::new(0x000);
|
||||
pub const REG_VERSION: ByteOffset = ByteOffset::new(0x004);
|
||||
pub const REG_DEVICE_ID: ByteOffset = ByteOffset::new(0x008);
|
||||
pub const REG_STATUS: ByteOffset = ByteOffset::new(0x070);
|
||||
pub const REG_GUEST_PAGE_SIZE: ByteOffset = ByteOffset::new(0x028);
|
||||
pub const REG_FEATURES_SEL: ByteOffset = ByteOffset::new(0x014);
|
||||
pub const REG_FEATURES: ByteOffset = ByteOffset::new(0x010);
|
||||
pub const REG_DRIVER_FEATURES_SEL: ByteOffset = ByteOffset::new(0x024);
|
||||
pub const REG_DRIVER_FEATURES: ByteOffset = ByteOffset::new(0x020);
|
||||
pub const REG_QUEUE_SEL: ByteOffset = ByteOffset::new(0x030);
|
||||
pub const REG_QUEUE_NUM_MAX: ByteOffset = ByteOffset::new(0x034);
|
||||
pub const REG_QUEUE_NUM: ByteOffset = ByteOffset::new(0x038);
|
||||
pub const REG_QUEUE_PFN: ByteOffset = ByteOffset::new(0x040);
|
||||
pub const REG_QUEUE_NOTIFY: ByteOffset = ByteOffset::new(0x050);
|
||||
pub const REG_INTERRUPT_STATUS: ByteOffset = ByteOffset::new(0x060);
|
||||
pub const REG_INTERRUPT_ACK: ByteOffset = ByteOffset::new(0x064);
|
||||
|
||||
pub const STATUS_ACK: u32 = 1;
|
||||
pub const STATUS_DRIVER: u32 = 2;
|
||||
@@ -42,11 +44,11 @@ impl Registers {
|
||||
}
|
||||
|
||||
impl MmioAccess for Registers {
|
||||
fn read(&self, offset: usize) -> u32 {
|
||||
fn read(&self, offset: ByteOffset) -> u32 {
|
||||
self.0.read(offset)
|
||||
}
|
||||
|
||||
fn write(&self, offset: usize, val: u32) {
|
||||
fn write(&self, offset: ByteOffset, val: u32) {
|
||||
self.0.write(offset, val)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use crate::mmio::{MmioAccess, REG_QUEUE_NOTIFY};
|
||||
use core::sync::atomic::{Ordering, fence};
|
||||
use libkos::Window;
|
||||
use types::address::ByteOffset;
|
||||
|
||||
pub const QUEUE_SIZE: usize = 8;
|
||||
const DESC_SIZE: usize = 16;
|
||||
const TIMEOUT: u32 = 10_000_000;
|
||||
/// Where the legacy layout puts the available and used rings.
|
||||
const AVAIL: usize = QUEUE_SIZE * DESC_SIZE;
|
||||
const USED: usize = 4096;
|
||||
const AVAIL: ByteOffset = ByteOffset::new(QUEUE_SIZE * DESC_SIZE);
|
||||
const USED: ByteOffset = ByteOffset::new(4096);
|
||||
|
||||
pub struct Descriptor {
|
||||
pub addr: u64,
|
||||
@@ -32,7 +33,7 @@ impl VirtioQueue {
|
||||
}
|
||||
let r = &self.rings;
|
||||
for (i, d) in descs.iter().enumerate() {
|
||||
let at = i * DESC_SIZE;
|
||||
let at = ByteOffset::new(i * DESC_SIZE);
|
||||
let last = i == descs.len() - 1;
|
||||
let flags: u16 = if d.writable { 2 } else { 0 } | if !last { 1 } else { 0 };
|
||||
r.write(at, d.addr);
|
||||
|
||||
Reference in New Issue
Block a user