From a153c8bc1c15d76d05a70eec8f6499d041a910c0 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Thu, 20 Jul 2023 19:20:56 +1000 Subject: [PATCH] inputd: correctly pass on resize events Signed-off-by: Anhad Singh --- bgad/src/main.rs | 4 +- inputd/src/lib.rs | 107 +++++++++++++++++++++++++++++------ inputd/src/main.rs | 36 +++++++----- vboxd/src/main.rs | 2 +- vesad/src/scheme.rs | 26 ++++----- virtio-core/src/lib.rs | 2 +- virtio-core/src/probe.rs | 15 +++-- virtio-core/src/transport.rs | 22 ++++--- virtio-gpud/src/main.rs | 2 +- virtio-gpud/src/scheme.rs | 42 ++++++++------ 10 files changed, 178 insertions(+), 80 deletions(-) diff --git a/bgad/src/main.rs b/bgad/src/main.rs index 781e68ae8f..cc7570efab 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -37,8 +37,8 @@ fn main() { print!("{}", format!(" - BGA {}x{}\n", bga.width(), bga.height())); let mut scheme = BgaScheme { - bga: bga, - display: File::open("display/vesa:input").ok() + bga, + display: File::open("input:producer").ok() }; scheme.update_size(); diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index bd9cb6655d..3c2eb329d4 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -1,6 +1,7 @@ +#![feature(iter_next_chunk)] + use std::fs::File; use std::io::{Error, Read}; -use std::mem; pub struct Handle(File); @@ -19,33 +20,103 @@ impl Handle { #[derive(Debug, Copy, Clone, PartialEq)] #[repr(u8)] -pub enum CommandTy { +enum CmdTy { Unknown = 0, Activate, Deactivate, + Resize, } -#[repr(C)] -pub struct Command { - pub ty: CommandTy, - pub value: usize, +impl From for CmdTy { + fn from(value: u8) -> Self { + match value { + 1 => CmdTy::Activate, + 2 => CmdTy::Deactivate, + 3 => CmdTy::Resize, + _ => CmdTy::Unknown, + } + } } -impl Command { - pub fn new(ty: CommandTy, value: usize) -> Self { - Self { ty, value } - } +pub enum Cmd { + // TODO(andypython): #VT should really need to be a `u8`. + Activate(usize /* #VT */), + Deactivate(usize /* #VT */), + Resize { + // TODO(andypython): do we really need to pass the VT here? + vt: usize, - /// ## Panics - /// This function panics if the buffer is not `sizeof::()` bytes wide. - pub fn parse<'a>(buffer: &'a [u8]) -> &'a Command { - assert_eq!(buffer.len(), core::mem::size_of::()); - unsafe { &*(buffer.as_ptr() as *const Command) } - } + width: u32, + height: u32, + stride: u32, + }, +} - pub fn into_bytes(self) -> [u8; mem::size_of::()] { - unsafe { core::mem::transmute(self) } +impl Cmd { + fn ty(&self) -> CmdTy { + match self { + Cmd::Activate(_) => CmdTy::Activate, + Cmd::Deactivate(_) => CmdTy::Deactivate, + Cmd::Resize { .. } => CmdTy::Resize, + } + } +} + +pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), syscall::Error> { + use std::os::fd::AsRawFd; + + let mut result = vec![]; + result.push(command.ty() as u8); + + match command { + Cmd::Activate(vt) | Cmd::Deactivate(vt) => result.extend_from_slice(&vt.to_le_bytes()), + Cmd::Resize { + vt, + width, + height, + stride, + } => { + result.extend_from_slice(&vt.to_le_bytes()); + result.extend(width.to_le_bytes()); + result.extend(height.to_le_bytes()); + result.extend(stride.to_le_bytes()); + } + }; + + let written = syscall::write(file.as_raw_fd() as usize, &result)?; + + // XXX: Ensure all of the data is written. + assert_eq!(written, result.len()); + Ok(()) +} + +pub fn parse_command(buffer: &[u8]) -> Option { + const U32_SIZE: usize = core::mem::size_of::(); + const USIZE_SIZE: usize = core::mem::size_of::(); + + let mut parser = buffer.iter().cloned(); + + let command = CmdTy::from(parser.next()?); + let vt = usize::from_le_bytes(parser.next_chunk::().ok()?); + + match command { + CmdTy::Activate => Some(Cmd::Activate(vt)), + CmdTy::Deactivate => Some(Cmd::Deactivate(vt)), + CmdTy::Resize => { + let width = parser.next_chunk::().ok()?; + let height = parser.next_chunk::().ok()?; + let stride = parser.next_chunk::().ok()?; + + Some(Cmd::Resize { + vt, + width: u32::from_le_bytes(width), + height: u32::from_le_bytes(height), + stride: u32::from_le_bytes(stride), + }) + } + + CmdTy::Unknown => None, } } diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 0609cb1491..da9efd6619 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -13,11 +13,12 @@ use std::collections::BTreeMap; use std::fs::File; -use std::io::{self, Read, Write}; +use std::io::{Read, Write}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use inputd::{Command, CommandTy}; +use inputd::Cmd; + use orbclient::{Event, EventOption}; use syscall::{Error as SysError, EventFlags, Packet, SchemeMut, EINVAL}; @@ -166,15 +167,25 @@ impl SchemeMut for InputScheme { _ => (), }, + EventOption::Resize(resize_event) => { + if let Some((_, file, current)) = self.active_vt.as_mut() { + inputd::send_comand( + file, + Cmd::Resize { + vt: current.clone(), + width: resize_event.width, + height: resize_event.height, + + // TODO(andypython): Figure out how to get the stride. + stride: resize_event.width, + }, + )?; + } + } + _ => continue, } - let deactivate = |file: &mut File, id: usize| -> io::Result<()> { - let command = Command::new(CommandTy::Deactivate, id).into_bytes(); - file.write(&command)?; - Ok(()) - }; - if let Some(new_active) = new_active_opt { if let Some(vt) = self.vts.get(&new_active).cloned() { if let Some((_, file, current)) = self.active_vt.as_mut() { @@ -183,20 +194,19 @@ impl SchemeMut for InputScheme { continue; } - deactivate(file, *current).unwrap(); + inputd::send_comand(file, Cmd::Deactivate(*current))?; } else { let id = self.next_vt_id.load(Ordering::SeqCst) - 1; let mut vt = File::open(self.vts.get_mut(&id).unwrap().as_ref()).unwrap(); - deactivate(&mut vt, id).unwrap(); + inputd::send_comand(&mut vt, Cmd::Deactivate(id))?; } log::info!("inputd: switching to VT #{new_active} (`{vt}`)"); let mut file = File::open(vt.as_ref()).unwrap(); - file.write(&Command::new(CommandTy::Activate, new_active).into_bytes()) - .unwrap(); + inputd::send_comand(&mut file, Cmd::Activate(new_active))?; self.active_vt = Some((vt.clone(), file, new_active)); } else { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); @@ -294,7 +304,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { last_allocated == *vt }; - // The activate VT is not the same as the VT that the consumer is listening to + // The activate VT is not the same as the VT that the consumer is listening to // for events. if !should_notify { continue; diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index cb3bba6035..845464d5e4 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -208,7 +208,7 @@ fn main() { let mut width = 0; let mut height = 0; - let mut display_opt = File::open("display/vesa:input").ok(); + let mut display_opt = File::open("inputd:producer").ok(); if let Some(ref display) = display_opt { let mut buf: [u8; 4096] = [0; 4096]; if let Ok(count) = syscall::fpath(display.as_raw_fd() as usize, &mut buf) { diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index d334c79a89..86f29b7c9e 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,8 +1,7 @@ use std::collections::BTreeMap; use std::{mem, ptr, slice, str}; -use orbclient::{Event, EventOption}; -use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE}; +use syscall::{Error, EventFlags, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE}; use crate::{ display::Display, @@ -37,7 +36,6 @@ pub struct DisplayScheme { pub vts: BTreeMap>>, next_id: usize, pub handles: BTreeMap, - super_key: bool, inputd_handle: inputd::Handle, } @@ -74,7 +72,6 @@ impl DisplayScheme { vts, next_id: 0, handles: BTreeMap::new(), - super_key: false, inputd_handle } } @@ -306,11 +303,13 @@ impl SchemeMut for DisplayScheme { match handle.kind { HandleKind::Input => { - let command = inputd::Command::parse(buf); + use inputd::Cmd as DisplayCommand; + + let command = inputd::parse_command(buf).unwrap(); - match command.ty { - inputd::CommandTy::Activate => { - let vt_i = VtIndex(command.value); + match command { + DisplayCommand::Activate(vt) => { + let vt_i = VtIndex(vt); if let Some(screens) = self.vts.get_mut(&vt_i) { for (screen_i, screen) in screens.iter_mut() { @@ -323,12 +322,13 @@ impl SchemeMut for DisplayScheme { self.active = vt_i; }, - - inputd::CommandTy::Deactivate => { - // Nothing :) - }, - _ => unreachable!() + DisplayCommand::Resize { width, height, stride, .. } => { + self.resize(width as usize, height as usize, stride as usize); + } + + // Nothing to do for deactivate :) + DisplayCommand::Deactivate(_) => {}, } Ok(buf.len()) diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs index 54554679a1..87b737f124 100644 --- a/virtio-core/src/lib.rs +++ b/virtio-core/src/lib.rs @@ -6,4 +6,4 @@ pub mod utils; mod probe; -pub use probe::{probe_device, Device, MSIX_PRIMARY_VECTOR, reinit}; +pub use probe::{probe_device, reinit, Device, MSIX_PRIMARY_VECTOR}; diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index cdb029a60c..f97ae30f5a 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -11,7 +11,7 @@ use pcid_interface::*; use syscall::Io; use crate::spec::*; -use crate::transport::{Error, StandardTransport, Queue}; +use crate::transport::{Error, Queue, StandardTransport}; use crate::utils::{align_down, VolatileCell}; pub struct Device<'a> { @@ -190,7 +190,12 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result let size = offset + capability.length as usize; - let addr = common::physmap(aligned_addr, size, common::Prot::RW, common::MemoryType::Uncacheable)? as usize; + let addr = common::physmap( + aligned_addr, + size, + common::Prot::RW, + common::MemoryType::Uncacheable, + )? as usize; addr + offset }; @@ -262,12 +267,12 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result }; device.transport.reset(); - reinit(& device)?; + reinit(&device)?; Ok(device) } -pub fn reinit<'a>(device: & Device<'a>) -> Result<(), Error> { +pub fn reinit<'a>(device: &Device<'a>) -> Result<(), Error> { // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits // in `device_status` is required to be done in two steps. let mut common = device.transport.common.lock().unwrap(); @@ -280,7 +285,5 @@ pub fn reinit<'a>(device: & Device<'a>) -> Result<(), Error> { let old = common.device_status.get(); common.device_status.set(old | DeviceStatusFlags::DRIVER); - - Ok(()) } diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 7118adbf9d..9d72b4fab0 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -161,7 +161,7 @@ impl<'a> Queue<'a> { descriptor_stack, used_head: AtomicU16::new(0), sref: sref.clone(), - vector + vector, }) } @@ -171,7 +171,7 @@ impl<'a> Queue<'a> { // Drain all of the available descriptors. while let Some(_) = self.descriptor_stack.pop() {} - + // Refill the descriptor stack. (0..self.descriptor.len() as u16).for_each(|i| self.descriptor_stack.push(i)); } @@ -244,9 +244,9 @@ impl<'a> Available<'a> { let size = size.next_multiple_of(syscall::PAGE_SIZE); // align to page size let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; - let virt = unsafe { - common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) - }.map_err(Error::SyscallError)?; + let virt = + unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) } + .map_err(Error::SyscallError)?; let ring = unsafe { &mut *(virt as *mut AvailableRing) }; @@ -312,7 +312,8 @@ impl<'a> Used<'a> { let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; let virt = - unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) }.map_err(Error::SyscallError)?; + unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) } + .map_err(Error::SyscallError)?; let ring = unsafe { &mut *(virt as *mut UsedRing) }; @@ -493,7 +494,14 @@ impl<'a> StandardTransport<'a> { log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); - let queue = Queue::new(descriptor, avail, used, notification_bell, queue_index, vector); + let queue = Queue::new( + descriptor, + avail, + used, + notification_bell, + queue_index, + vector, + ); let queue_copy = queue.clone(); let irq_fd = irq_handle.as_raw_fd(); diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index f22ed521da..3fdc3eb347 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -30,7 +30,7 @@ use std::sync::Arc; use pcid_interface::PcidServerHandle; use syscall::{Packet, SchemeMut}; -use virtio_core::transport::{Queue, self}; +use virtio_core::transport::{self, Queue}; use virtio_core::utils::VolatileCell; use virtio_core::MSIX_PRIMARY_VECTOR; diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index a07b54a8a5..a42a81c51e 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use inputd::Damage; use common::dma::Dma; -use syscall::{Error as SysError, SchemeMut, EINVAL, EAGAIN}; +use syscall::{Error as SysError, SchemeMut, EAGAIN, EINVAL}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, StandardTransport}; @@ -117,8 +117,8 @@ impl<'a> Display<'a> { .next_multiple_of(syscall::PAGE_SIZE); let mapped = *self.mapped.get().unwrap(); - let address = unsafe {syscall::virttophys(mapped)}?; - + let address = unsafe { syscall::virttophys(mapped) }?; + self.map_screen_with(0, address, fb_size, mapped).await } @@ -130,7 +130,7 @@ impl<'a> Display<'a> { let bpp = 32; let fb_size = (self.width as usize * self.height as usize * bpp / 8) .next_multiple_of(syscall::PAGE_SIZE); - let address = unsafe { syscall::physalloc(fb_size) }? ; + let address = unsafe { syscall::physalloc(fb_size) }?; let mapped = unsafe { common::physmap( address as usize, @@ -147,7 +147,13 @@ impl<'a> Display<'a> { self.map_screen_with(offset, address, fb_size, mapped).await } - async fn map_screen_with(&self, offset: usize, address: usize, size: usize, mapped: usize) -> Result { + async fn map_screen_with( + &self, + offset: usize, + address: usize, + size: usize, + mapped: usize, + ) -> Result { // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. let mut request = Dma::new(ResourceCreate2d::default())?; @@ -158,10 +164,10 @@ impl<'a> Display<'a> { self.send_request(request).await?; - // Use the allocated framebuffer from tthe guest ram, and attach it as backing - // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. + // Use the allocated framebuffer from tthe guest ram, and attach it as backing + // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. // - // TODO(andypython): Scatter lists are supported, so the framebuffer doesn’t need to be + // TODO(andypython): Scatter lists are supported, so the framebuffer doesn’t need to be // contignous in guest physical memory. let entry = Dma::new(MemEntry { address: address as u64, @@ -421,7 +427,7 @@ impl<'a> SchemeMut for Scheme<'a> { Handle::Vt(id) => { let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?; - // The VT is not active and the device is reseted. Ask them to try + // The VT is not active and the device is reseted. Ask them to try // again later. if handle.is_reseted.load(Ordering::SeqCst) { return Err(SysError::new(EAGAIN)); @@ -442,24 +448,24 @@ impl<'a> SchemeMut for Scheme<'a> { } Handle::Input => { - let command = inputd::Command::parse(buf); + use inputd::Cmd as DisplayCommand; - match command.ty { - inputd::CommandTy::Activate => { - let vt = command.value; + let command = inputd::parse_command(buf).unwrap(); + match command { + DisplayCommand::Activate(vt) => { let display = self.vts.get(&vt).unwrap(); futures::executor::block_on(display.init()).unwrap(); - }, - - inputd::CommandTy::Deactivate => { - let vt = command.value; + } + DisplayCommand::Deactivate(vt) => { let display = self.vts.get(&vt).ok_or(SysError::new(EINVAL))?; futures::executor::block_on(display.detach()).unwrap(); } - _ => unreachable!(), + DisplayCommand::Resize { .. } => { + log::warn!("virtio-gpu: resize is not implemented yet") + } } Ok(buf.len())