virtio-gpu: remove the +1 workaround

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh
2023-07-25 16:34:25 +10:00
parent 440d6381f9
commit 820b8370ae
8 changed files with 197 additions and 83 deletions
+46 -7
View File
@@ -3,6 +3,25 @@
use std::fs::File;
use std::io::{Error, Read, Write};
unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
::core::slice::from_raw_parts((p as *const T) as *const u8, ::core::mem::size_of::<T>())
}
#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(usize)]
pub enum VtMode {
Text = 0,
Graphic = 1,
Default = 2,
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct VtActivate {
pub vt: usize,
pub mode: VtMode,
}
pub struct Handle(File);
impl Handle {
@@ -14,11 +33,12 @@ impl Handle {
// The return value is the display identifier. It will be used to uniquely
// identify the display on activation events.
pub fn register(&mut self) -> Result<usize, Error> {
Ok(dbg!(self.0.read(&mut [])?))
Ok(self.0.read(&mut [])?)
}
pub fn activate(&mut self, vt: usize) -> Result<usize, Error> {
Ok(dbg!(self.0.write(&vt.to_le_bytes())?))
pub fn activate(&mut self, vt: usize, mode: VtMode) -> Result<usize, Error> {
let cmd = VtActivate { vt, mode };
Ok(self.0.write(unsafe { any_as_u8_slice(&cmd) })?)
}
}
@@ -43,9 +63,14 @@ impl From<u8> for CmdTy {
}
}
#[derive(Debug)]
pub enum Cmd {
// TODO(andypython): #VT should really need to be a `u8`.
Activate(usize /* #VT */),
Activate {
vt: usize,
mode: VtMode,
},
Deactivate(usize /* #VT */),
Resize {
// TODO(andypython): do we really need to pass the VT here?
@@ -60,7 +85,7 @@ pub enum Cmd {
impl Cmd {
fn ty(&self) -> CmdTy {
match self {
Cmd::Activate(_) => CmdTy::Activate,
Cmd::Activate { .. } => CmdTy::Activate,
Cmd::Deactivate(_) => CmdTy::Deactivate,
Cmd::Resize { .. } => CmdTy::Resize,
}
@@ -74,7 +99,14 @@ pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), syscall::Error>
result.push(command.ty() as u8);
match command {
Cmd::Activate(vt) | Cmd::Deactivate(vt) => result.extend_from_slice(&vt.to_le_bytes()),
Cmd::Activate { vt, mode } => {
let cmd = VtActivate { vt, mode };
let bytes = unsafe { any_as_u8_slice(&cmd) };
result.extend_from_slice(bytes);
}
Cmd::Deactivate(vt) => result.extend_from_slice(&vt.to_le_bytes()),
Cmd::Resize {
vt,
width,
@@ -105,7 +137,14 @@ pub fn parse_command(buffer: &[u8]) -> Option<Cmd> {
let vt = usize::from_le_bytes(parser.next_chunk::<USIZE_SIZE>().ok()?);
match command {
CmdTy::Activate => Some(Cmd::Activate(vt)),
CmdTy::Activate => {
let cmd = unsafe { &*buffer.as_ptr().offset(1).cast::<VtActivate>() };
Some(Cmd::Activate {
vt: cmd.vt,
mode: VtMode::from(cmd.mode),
})
}
CmdTy::Deactivate => Some(Cmd::Deactivate(vt)),
CmdTy::Resize => {
let width = parser.next_chunk::<U32_SIZE>().ok()?;
+81 -22
View File
@@ -17,7 +17,7 @@ use std::io::{Read, Write};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use inputd::Cmd;
use inputd::{Cmd, VtActivate, VtMode};
use spin::Mutex;
@@ -49,6 +49,7 @@ impl Handle {
/// requires the system call to return first. Otherwise, it will block indefinitely.
struct VtInner {
handle_file: File,
mode: VtMode,
}
struct Vt {
@@ -72,8 +73,10 @@ impl Vt {
pub fn inner(&self) -> &Mutex<VtInner> {
self.inner.call_once(|| {
let handle_file = File::open(format!("{}:handle", self.display)).unwrap();
Mutex::new(VtInner { handle_file })
Mutex::new(VtInner {
handle_file,
mode: VtMode::Default,
})
})
}
}
@@ -88,7 +91,7 @@ struct InputScheme {
super_key: bool,
active_vt: Option<Arc<Vt>>,
todo: Vec<usize>,
todo: Vec<VtActivate>,
}
impl InputScheme {
@@ -186,19 +189,19 @@ impl SchemeMut for InputScheme {
let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
match handle {
Handle::Device { .. } | Handle::Consumer { .. } => {
if buf.len() == core::mem::size_of::<usize>() {
// The device is requesting to activate a VT.
let vt =
usize::from_le_bytes(buf.try_into().map_err(|_| SysError::new(EINVAL))?);
Handle::Device { device } => {
assert!(buf.len() == core::mem::size_of::<VtActivate>());
self.todo.push(vt);
return Ok(buf.len());
} else {
unreachable!()
}
// SAFETY: We have verified the size of the buffer above.
let cmd = unsafe { &*buf.as_ptr().cast::<VtActivate>() };
self.vts.insert(cmd.vt, Vt::new(device.clone(), cmd.vt));
self.todo.push(cmd.clone());
return Ok(buf.len());
}
Handle::Consumer { .. } => unreachable!(),
_ => {}
}
@@ -276,7 +279,10 @@ impl SchemeMut for InputScheme {
inputd::send_comand(
&mut vt_inner.handle_file,
Cmd::Activate(new_active.index),
Cmd::Activate {
vt: new_active.index,
mode: VtMode::Default,
},
)?;
self.active_vt = Some(new_active.clone());
} else {
@@ -287,7 +293,7 @@ impl SchemeMut for InputScheme {
assert!(handle.is_producer());
let active_vt = self.active_vt.as_ref().unwrap();
let active_vt = self.active_vt.as_ref().unwrap();
for handle in self.handles.values_mut() {
match handle {
Handle::Consumer {
@@ -357,17 +363,22 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
scheme.handle(&mut packet);
socket_file.write(&packet)?;
while let Some(vt) = scheme.todo.pop() {
let vt = scheme.vts.get_mut(&vt).unwrap();
while let Some(cmd) = scheme.todo.pop() {
let vt = scheme.vts.get_mut(&cmd.vt).unwrap();
let mut vt_inner = vt.inner().lock();
// Failing to activate a VT is not a fatal error.
if let Err(err) =
inputd::send_comand(&mut vt_inner.handle_file, Cmd::Activate(vt.index))
{
if let Err(err) = inputd::send_comand(
&mut vt_inner.handle_file,
Cmd::Activate {
vt: vt.index,
mode: VtMode::from(cmd.mode),
},
) {
log::error!("inputd: failed to activate VT #{}: {err}", vt.index)
}
vt_inner.mode = cmd.mode;
scheme.active_vt = Some(vt.clone());
}
@@ -454,5 +465,53 @@ pub fn setup_logging(level: log::LevelFilter, name: &str) {
pub fn main() {
#[cfg(target_os = "redox")]
setup_logging(log::LevelFilter::Trace, "inputd");
redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize");
let mut args = std::env::args().skip(1);
if let Some(val) = args.next() {
if val != "-G" {
panic!("inputd: invalid argument: {}", val);
}
let vt = args.next().unwrap().parse::<usize>().unwrap();
// On startup, the VESA display driver is started which basically makes use of the framebuffer
// provided by the firmware. The GPU device are latter started by `pcid` (such as `virtio-gpu`).
let mut devices = vec![];
let schemes = std::fs::read_dir(":").unwrap();
for entry in schemes {
let path = entry.unwrap().path();
let path_str = path
.into_os_string()
.into_string()
.expect("inputd: failed to convert path to string");
if path_str.contains("display") {
println!("inputd: found display scheme {}", path_str);
devices.push(path_str);
}
}
let device = devices
.iter()
.filter(|d| !d.contains("vesa"))
.collect::<Vec<_>>();
let device = if device.is_empty() {
"vesa"
} else {
// TODO: What should we do when there are multiple display devices?
device[0].split("/").nth(2).unwrap()
};
dbg!(&device);
let mut handle =
inputd::Handle::new(device).expect("inputd: failed to open display handle");
handle
.activate(vt, VtMode::Graphic)
.expect("inputd: failed to activate VT in graphic mode");
} else {
redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize");
}
}
+1 -1
View File
@@ -98,7 +98,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec<FrameBuffer>, spec: &[b
daemon.ready().expect("failed to notify parent");
scheme.inputd_handle.activate(1).unwrap();
scheme.inputd_handle.activate(1, inputd::VtMode::Default).unwrap();
let mut blocked = Vec::new();
loop {
+21 -7
View File
@@ -37,6 +37,7 @@ pub struct DisplayScheme {
next_id: usize,
pub handles: BTreeMap<usize, Handle>,
pub inputd_handle: inputd::Handle,
}
impl DisplayScheme {
@@ -72,7 +73,7 @@ impl DisplayScheme {
vts,
next_id: 0,
handles: BTreeMap::new(),
inputd_handle
inputd_handle,
}
}
@@ -303,20 +304,33 @@ impl SchemeMut for DisplayScheme {
match handle.kind {
HandleKind::Input => {
use inputd::Cmd as DisplayCommand;
use inputd::{Cmd as DisplayCommand, VtMode};
let command = inputd::parse_command(buf).unwrap();
dbg!(&command);
match command {
DisplayCommand::Activate(vt) => {
DisplayCommand::Activate { vt, mode } => {
let vt_i = VtIndex(vt);
if let Some(screens) = self.vts.get_mut(&vt_i) {
for (screen_i, screen) in screens.iter_mut() {
screen.redraw(
self.onscreens[screen_i.0],
self.framebuffers[screen_i.0].stride
);
match mode {
VtMode::Graphic => {
dbg!("yes");
*screen = Box::new(GraphicScreen::new(Display::new(screen.width(), screen.height())));
}
VtMode::Default => {
dbg!("x", &mode);
screen.redraw(
self.onscreens[screen_i.0],
self.framebuffers[screen_i.0].stride
);
}
VtMode::Text => todo!()
}
}
}
+1 -1
View File
@@ -27,7 +27,7 @@ pub struct GraphicScreen {
impl GraphicScreen {
pub fn new(display: Display) -> GraphicScreen {
GraphicScreen {
display: display,
display,
input: VecDeque::new(),
sync_rects: Vec::new(),
}
+3 -1
View File
@@ -11,7 +11,7 @@ use pcid_interface::*;
use syscall::Io;
use crate::spec::*;
use crate::transport::{Error, Queue, StandardTransport};
use crate::transport::{Error, StandardTransport};
use crate::utils::{align_down, VolatileCell};
pub struct Device<'a> {
@@ -21,6 +21,8 @@ pub struct Device<'a> {
pub isr: &'a VolatileCell<u32>,
}
// FIXME(andypython): `device_space` should not be `Send` nor `Sync`. Take
// it out of `Device`.
unsafe impl Send for Device<'_> {}
unsafe impl Sync for Device<'_> {}
+1 -1
View File
@@ -446,7 +446,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
device.transport.clone(),
))?;
scheme.inputd_handle.activate(scheme.main_vt)?;
// scheme.inputd_handle.activate(scheme.main_vt)?;
loop {
let mut packet = Packet::default();
+43 -43
View File
@@ -249,20 +249,16 @@ impl<'a> Display<'a> {
}
}
enum Handle {
Vt(usize /* VT index */),
enum Handle<'a> {
Vt { display: Arc<Display<'a>>, vt: usize },
Input,
}
pub struct Scheme<'a> {
vts: BTreeMap<usize /* VT index */, Arc<Display<'a>>>,
handles: BTreeMap<usize /* file descriptor */, Handle>,
handles: BTreeMap<usize /* file descriptor */, Handle<'a>>,
/// Counter used for file descriptor allocation.
next_id: AtomicUsize,
displays: Vec<Arc<Display<'a>>>,
pub(crate) inputd_handle: inputd::Handle,
pub(crate) main_vt: usize,
}
impl<'a> Scheme<'a> {
@@ -280,19 +276,10 @@ impl<'a> Scheme<'a> {
)
.await?;
let mut inputd_handle = inputd::Handle::new("virtio-gpu").unwrap();
let mut vts = BTreeMap::new();
let main_vt = inputd_handle.register().unwrap();
vts.insert(main_vt, displays[0].clone());
Ok(Self {
vts,
handles: BTreeMap::new(),
next_id: AtomicUsize::new(0),
inputd_handle,
displays,
main_vt,
})
}
@@ -363,22 +350,17 @@ impl<'a> SchemeMut for Scheme<'a> {
dbg!(vt, id);
if self.displays.get(id).is_none() {
return Err(SysError::new(EINVAL));
}
let display = self.displays.get(id).ok_or(SysError::new(EINVAL))?;
let fd = self.next_id.fetch_add(1, Ordering::SeqCst);
// FIXME: The +1 is a hack. vesad smh
self.handles.insert(fd, Handle::Vt(vt + 1));
self.handles.insert(fd, Handle::Vt {display: display.clone(), vt });
Ok(fd)
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result<usize> {
match self.handles.get(&id).unwrap() {
Handle::Vt(id) => {
let handle = self.vts.get_mut(&(id - 1)).ok_or(SysError::new(EINVAL))?;
let bytes_copied = futures::executor::block_on(handle.get_fpath(buf)).unwrap();
Handle::Vt { display, .. } => {
let bytes_copied = futures::executor::block_on(display.get_fpath(buf)).unwrap();
Ok(bytes_copied)
}
@@ -400,9 +382,8 @@ impl<'a> SchemeMut for Scheme<'a> {
fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result<usize> {
match self.handles.get(&id).ok_or(SysError::new(EINVAL))? {
Handle::Vt(id) => {
let handle = self.vts.get_mut(&(id - 1)).ok_or(SysError::new(EINVAL))?;
Ok(futures::executor::block_on(handle.map_screen(map.offset)).unwrap())
Handle::Vt { display, .. } => {
Ok(futures::executor::block_on(display.map_screen(map.offset)).unwrap())
}
_ => unreachable!(),
}
@@ -410,9 +391,8 @@ impl<'a> SchemeMut for Scheme<'a> {
fn fsync(&mut self, id: usize) -> syscall::Result<usize> {
match self.handles.get(&id).ok_or(SysError::new(EINVAL))? {
Handle::Vt(id) => {
let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?;
futures::executor::block_on(handle.flush(None)).unwrap();
Handle::Vt { display, .. } => {
futures::executor::block_on(display.flush(None)).unwrap();
Ok(0)
}
@@ -428,12 +408,10 @@ impl<'a> SchemeMut for Scheme<'a> {
fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result<usize> {
match self.handles.get(&id).ok_or(SysError::new(EINVAL))? {
Handle::Vt(id) => {
let handle = self.vts.get_mut(&(id - 1)).ok_or(SysError::new(EINVAL))?;
Handle::Vt { display, .. } => {
// The VT is not active and the device is reseted. Ask them to try
// again later.
if handle.is_reseted.load(Ordering::SeqCst) {
if display.is_reseted.load(Ordering::SeqCst) {
return Err(SysError::new(EAGAIN));
}
@@ -445,26 +423,48 @@ impl<'a> SchemeMut for Scheme<'a> {
};
for damage in damages {
futures::executor::block_on(handle.flush(Some(damage))).unwrap();
futures::executor::block_on(display.flush(Some(damage))).unwrap();
}
Ok(buf.len())
}
Handle::Input => {
use inputd::Cmd as DisplayCommand;
use inputd::{Cmd as DisplayCommand, VtMode};
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();
DisplayCommand::Activate { mode, vt } => {
assert!(mode == VtMode::Graphic || mode == VtMode::Default);
let target_vt = vt;
for handle in self.handles.values() {
if let Handle::Vt { display , vt } = handle {
if *vt != target_vt {
continue;
}
futures::executor::block_on(display.init()).unwrap();
}
}
}
DisplayCommand::Deactivate(vt) => {
let display = self.vts.get(&vt).ok_or(SysError::new(EINVAL))?;
futures::executor::block_on(display.detach()).unwrap();
DisplayCommand::Deactivate(target_vt) => {
for handle in self.handles.values() {
if let Handle::Vt { display , vt } = handle {
if *vt != target_vt {
continue;
}
futures::executor::block_on(display.detach()).unwrap();
break;
}
}
// for display in self.displays.iter() {
// futures::executor::block_on(display.detach()).unwrap();
// }
}
DisplayCommand::Resize { .. } => {