diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index 1527925b04..15fd0509ea 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -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 { diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index decd2b40f5..0dbec3326f 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -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, next_id: AtomicUsize, + mapped: Option, } 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(&mut self, request: Dma) -> Result, 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 { + async fn map_screen(&mut self, offset: usize) -> Result { // 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::().unwrap_or(1); let id = screen.next().unwrap_or("").parse::().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 { + todo!() + } + + fn fevent( + &mut self, + _id: usize, + _flags: syscall::EventFlags, + ) -> syscall::Result { + log::warn!("fevent is a stub!"); + Ok(syscall::EventFlags::empty()) + } + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { 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 { + 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 { 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 { - 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 { + 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 { + // 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 { + // let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + + // match handle { + // Handle::Screen { .. } => { + // let size = buf.len() / core::mem::size_of::(); + // let events = + // unsafe { core::slice::from_raw_parts(buf.as_ptr().cast::(), 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 { todo!() } - fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { - let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - - match handle { - Handle::Screen { .. } => { - let size = buf.len() / core::mem::size_of::(); - let events = - unsafe { core::slice::from_raw_parts(buf.as_ptr().cast::(), size) }; - - dbg!(events); - todo!() - } - } + fn close(&mut self, _id: usize) -> syscall::Result { + Ok(0) } }