inputd: correctly pass on resize events

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh
2023-07-20 19:20:56 +10:00
parent e457f03935
commit a153c8bc1c
10 changed files with 178 additions and 80 deletions
+2 -2
View File
@@ -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();
+89 -18
View File
@@ -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<u8> 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::<Command>()` bytes wide.
pub fn parse<'a>(buffer: &'a [u8]) -> &'a Command {
assert_eq!(buffer.len(), core::mem::size_of::<Command>());
unsafe { &*(buffer.as_ptr() as *const Command) }
}
width: u32,
height: u32,
stride: u32,
},
}
pub fn into_bytes(self) -> [u8; mem::size_of::<Command>()] {
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<Cmd> {
const U32_SIZE: usize = core::mem::size_of::<u32>();
const USIZE_SIZE: usize = core::mem::size_of::<usize>();
let mut parser = buffer.iter().cloned();
let command = CmdTy::from(parser.next()?);
let vt = usize::from_le_bytes(parser.next_chunk::<USIZE_SIZE>().ok()?);
match command {
CmdTy::Activate => Some(Cmd::Activate(vt)),
CmdTy::Deactivate => Some(Cmd::Deactivate(vt)),
CmdTy::Resize => {
let width = parser.next_chunk::<U32_SIZE>().ok()?;
let height = parser.next_chunk::<U32_SIZE>().ok()?;
let stride = parser.next_chunk::<U32_SIZE>().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,
}
}
+23 -13
View File
@@ -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;
+1 -1
View File
@@ -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) {
+13 -13
View File
@@ -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<VtIndex, BTreeMap<ScreenIndex, Box<dyn Screen>>>,
next_id: usize,
pub handles: BTreeMap<usize, Handle>,
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())
+1 -1
View File
@@ -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};
+9 -6
View File
@@ -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<Device<'a>
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<'a>
};
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(())
}
+15 -7
View File
@@ -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();
+1 -1
View File
@@ -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;
+24 -18
View File
@@ -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<usize, Error> {
async fn map_screen_with(
&self,
offset: usize,
address: usize,
size: usize,
mapped: usize,
) -> Result<usize, Error> {
// 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 doesnt need to be
// TODO(andypython): Scatter lists are supported, so the framebuffer doesnt 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())