virtio-gpu: remove the +1 workaround
Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
+46
-7
@@ -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
@@ -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
@@ -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
@@ -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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
|
||||
@@ -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<'_> {}
|
||||
|
||||
|
||||
@@ -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
@@ -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 { .. } => {
|
||||
|
||||
Reference in New Issue
Block a user