virtio_gpud: able to get orbital running :^)
Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
+9
-11
@@ -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
@@ -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 doesn’t 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 doesn’t 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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user