virtio_gpud: able to get orbital running :^)

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh
2023-07-04 13:21:41 +10:00
parent c0950d0686
commit caa435eae3
2 changed files with 136 additions and 74 deletions
+9 -11
View File
@@ -163,7 +163,6 @@ impl GpuRect {
}
}
#[derive(Debug)]
#[repr(C)]
pub struct DisplayInfo {
@@ -234,10 +233,10 @@ impl Default for ResourceCreate2d {
#[derive(Debug)]
#[repr(C)]
pub struct MemEntry {
pub address: u64,
pub length: u32,
pub padding: u32
pub struct MemEntry {
pub address: u64,
pub length: u32,
pub padding: u32,
}
#[derive(Debug)]
@@ -245,7 +244,7 @@ pub struct MemEntry {
pub struct AttachBacking {
pub header: ControlHeader,
pub resource_id: u32,
pub num_entries: u32
pub num_entries: u32,
}
impl AttachBacking {
@@ -256,7 +255,7 @@ impl AttachBacking {
..Default::default()
},
resource_id,
num_entries
num_entries,
}
}
}
@@ -267,7 +266,7 @@ pub struct ResourceFlush {
pub header: ControlHeader,
pub rect: GpuRect,
pub resource_id: u32,
pub padding: u32
pub padding: u32,
}
impl ResourceFlush {
@@ -277,10 +276,10 @@ impl ResourceFlush {
ty: VolatileCell::new(CommandTy::ResourceFlush),
..Default::default()
},
rect,
resource_id,
padding: 0
padding: 0,
}
}
}
@@ -309,7 +308,6 @@ impl SetScanout {
}
}
#[derive(Debug)]
#[repr(C)]
pub struct XferToHost2d {
+127 -63
View File
@@ -17,9 +17,7 @@ use virtio_core::{
use crate::*;
pub enum Handle {
Screen {
id: usize
},
Screen { id: usize },
}
pub struct Display<'a> {
@@ -29,6 +27,7 @@ pub struct Display<'a> {
display_id: usize,
handles: BTreeMap<usize, Handle>,
next_id: AtomicUsize,
mapped: Option<usize>,
}
impl<'a> Display<'a> {
@@ -40,6 +39,7 @@ impl<'a> Display<'a> {
display_id: 0,
handles: BTreeMap::new(),
next_id: AtomicUsize::new(0),
mapped: None,
}
}
@@ -76,7 +76,7 @@ impl<'a> Display<'a> {
let width = display_info.display_info[self.display_id].rect.width();
let height = display_info.display_info[self.display_id].rect.height();
let path = format!("display:0.0/{}/{}", width, height);
let path = format!("display:3.0/{}/{}", width, height);
// Copy the path into the target buffer.
buffer[..path.len()].copy_from_slice(path.as_bytes());
@@ -84,7 +84,7 @@ impl<'a> Display<'a> {
}
async fn send_request<T>(&mut self, request: Dma<T>) -> Result<Dma<ControlHeader>, Error> {
let header = Dma::new(ControlHeader::default())?;
let header = Dma::new(ControlHeader::default())?;
let command = ChainBuilder::new()
.chain(Buffer::new(&request))
.chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY))
@@ -95,16 +95,16 @@ impl<'a> Display<'a> {
}
async fn flush_resource(&mut self, flush: ResourceFlush) -> Result<(), Error> {
let header = self.send_request(Dma::new(flush)?).await?;
let header = self.send_request(Dma::new(flush)?).await?;
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
Ok(())
}
async fn map_screen(&mut self, offset: usize, size: usize) -> Result<usize, Error> {
async fn map_screen(&mut self, offset: usize) -> Result<usize, Error> {
// Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`.
let (width, height) = self.get_resolution().await?;
let mut request = Dma::new(ResourceCreate2d::default())?;
let mut request = Dma::new(ResourceCreate2d::default())?;
request.set_width(width);
request.set_height(height);
@@ -113,54 +113,63 @@ impl<'a> Display<'a> {
self.send_request(request).await?;
// Allocate a framebuffer from guest ram, and attach it as backing storage to the
// resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. Scatter
// lists are supported, so the framebuffer doesnt need to be contignous in guest
// physical memory.
// Allocate a framebuffer from guest ram, and attach it as backing storage to the
// resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. Scatter
// lists are supported, so the framebuffer doesnt need to be contignous in guest
// physical memory.
let bpp = 32;
let fb_size = (width as usize * height as usize * bpp / 8).next_multiple_of(syscall::PAGE_SIZE);
let mut entries = unsafe { Dma::zeroed_unsized(fb_size / syscall::PAGE_SIZE) }?;
let fb_size =
(width as usize * height as usize * bpp / 8).next_multiple_of(syscall::PAGE_SIZE);
let address = unsafe { syscall::physalloc(fb_size) }? as u64;
let mapped = unsafe {
syscall::physmap(
address as usize,
fb_size,
syscall::PhysmapFlags::PHYSMAP_WRITE,
)
}?;
for i in 0..fb_size / syscall::PAGE_SIZE {
let address = unsafe { syscall::physalloc(syscall::PAGE_SIZE) }? as u64;
let mapped = unsafe {syscall::physmap(address as usize, syscall::PAGE_SIZE, syscall::PhysmapFlags::PHYSMAP_WRITE)}?;
unsafe {
core::ptr::write_bytes(mapped as *mut u8, 69, syscall::PAGE_SIZE);
}
let entry = MemEntry {
address,
length: syscall::PAGE_SIZE as u32,
padding: 0,
};
entries[i]= entry;
unsafe {
core::ptr::write_bytes(mapped as *mut u8, 255, fb_size);
}
let attach_request = Dma::new(AttachBacking::new(1, entries.len() as u32))?;
let header = Dma::new(ControlHeader::default())?;
let entry = Dma::new(MemEntry {
address,
length: fb_size as u32,
padding: 0,
})?;
let attach_request = Dma::new(AttachBacking::new(1, 1))?;
let header = Dma::new(ControlHeader::default())?;
let command = ChainBuilder::new()
.chain(Buffer::new(&attach_request))
.chain(Buffer::new_unsized(&entries))
.chain(Buffer::new(&entry))
.chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY))
.build();
self.control_queue.send(command).await;
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
self.flush().await?;
self.mapped = Some(mapped);
Ok(mapped + offset)
}
let rect = GpuRect::new(0,0,width,height);
async fn flush(&mut self) -> Result<(), Error> {
let (width, height) = self.get_resolution().await?;
let rect = GpuRect::new(0, 0, width, height);
let scanout_request = Dma::new(SetScanout::new(0, 1, rect))?;
let header = self.send_request(scanout_request).await?;
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
let rect = GpuRect::new(0,0,width,height);
let rect = GpuRect::new(0, 0, width, height);
let req = Dma::new(XferToHost2d::new(1, rect))?;
let header = self.send_request(req).await?;
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
let rect = GpuRect::new(0,0,width,height);
let rect = GpuRect::new(0, 0, width, height);
self.flush_resource(ResourceFlush::new(1, rect)).await?;
todo!()
Ok(())
}
}
@@ -179,59 +188,114 @@ impl<'a> SchemeMut for Display<'a> {
let vt_index = screen.next().unwrap_or("").parse::<usize>().unwrap_or(1);
let id = screen.next().unwrap_or("").parse::<usize>().unwrap_or(0);
if id != self.display_id {
return Err(SysError::new(syscall::ENOENT));
}
dbg!(&vt_index, &id);
let fd = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.insert(fd, Handle::Screen { id });
Ok(fd)
}
}
fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> syscall::Result<usize> {
todo!()
}
fn fevent(
&mut self,
_id: usize,
_flags: syscall::EventFlags,
) -> syscall::Result<syscall::EventFlags> {
log::warn!("fevent is a stub!");
Ok(syscall::EventFlags::empty())
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
let bytes_copied = match handle {
Handle::Screen { .. } => {
futures::executor::block_on(self.get_fpath(buf))?
}
Handle::Screen { .. } => futures::executor::block_on(self.get_fpath(buf))?,
};
Ok(bytes_copied)
}
fn fmap_old(&mut self, id: usize, map: &syscall::OldMap) -> syscall::Result<usize> {
self.fmap(
id,
&syscall::Map {
offset: map.offset,
size: map.size,
flags: map.flags,
address: 0,
},
)
}
fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
if let Handle::Screen { .. } = handle {
futures::executor::block_on(self.map_screen(map.offset, map.size));
}
unreachable!()
}
fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
let path = match handle {
let a = match handle {
Handle::Screen { .. } => {
futures::executor::block_on(self.get_fpath(buf))?
if let Some(mapped) = self.mapped {
// already mapped
mapped + map.offset
} else {
// create the resource
futures::executor::block_on(self.map_screen(map.offset)).unwrap()
}
}
};
Ok(a)
}
fn fsync(&mut self, id: usize) -> syscall::Result<usize> {
let _handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
futures::executor::block_on(self.flush()).unwrap();
Ok(0)
}
fn read(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result<usize> {
// TODO: figure out how to get input lol
log::warn!("virtio_gpu::read is a stub!");
Ok(0)
}
fn write(&mut self, _id: usize, buf: &[u8]) -> syscall::Result<usize> {
// let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
// match handle {
// Handle::Screen { .. } => {
// let size = buf.len() / core::mem::size_of::<Event>();
// let events =
// unsafe { core::slice::from_raw_parts(buf.as_ptr().cast::<Event>(), size) };
// dbg!(events);
// todo!()
// }
// }
// SAFETY: lmao
unsafe {
core::ptr::copy_nonoverlapping(
buf.as_ptr(),
self.mapped.unwrap() as *mut u8,
buf.len(),
);
futures::executor::block_on(self.flush()).unwrap();
}
Ok(buf.len())
}
fn seek(&mut self, _id: usize, _pos: isize, _whence: usize) -> syscall::Result<isize> {
todo!()
}
fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
match handle {
Handle::Screen { .. } => {
let size = buf.len() / core::mem::size_of::<Event>();
let events =
unsafe { core::slice::from_raw_parts(buf.as_ptr().cast::<Event>(), size) };
dbg!(events);
todo!()
}
}
fn close(&mut self, _id: usize) -> syscall::Result<usize> {
Ok(0)
}
}