xhcid: Use redox-scheme

This commit is contained in:
bjorn3
2025-03-13 17:00:48 +01:00
parent f2d3d16455
commit 374e5fbfab
4 changed files with 92 additions and 131 deletions
Generated
+1
View File
@@ -1934,6 +1934,7 @@ dependencies = [
"pcid",
"plain",
"redox-daemon",
"redox-scheme 0.3.0",
"redox_event",
"redox_syscall",
"regex",
+1
View File
@@ -21,6 +21,7 @@ lazy_static = "1.4"
log = "0.4"
redox-daemon = "0.1"
redox_event = "0.4.1"
redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" }
redox_syscall = "0.5"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
+30 -29
View File
@@ -26,12 +26,9 @@
extern crate bitflags;
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::{FromRawFd, RawFd};
use std::ptr::NonNull;
use std::sync::{Arc, Mutex};
use libredox::flag;
#[cfg(target_arch = "x86_64")]
use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi;
use pcid_interface::irq_helpers::read_bsp_apic_id;
@@ -40,9 +37,8 @@ use pcid_interface::{
MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo,
};
use syscall::data::Packet;
use syscall::error::EWOULDBLOCK;
use syscall::scheme::Scheme;
use redox_scheme::{RequestKind, Response, SignalBehavior, Socket};
use syscall::EOPNOTSUPP;
use crate::xhci::{InterruptMethod, Xhci};
@@ -190,14 +186,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
println!(" + XHCI {}", pci_config.func.display());
let scheme_name = format!("usb.{}", name);
let socket_fd =
libredox::call::open(format!(":{}", scheme_name), flag::O_RDWR | flag::O_CREAT, 0)
.expect("xhcid: failed to create usb scheme");
let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) };
let socket = Socket::create(scheme_name.clone()).expect("xhcid: failed to create usb scheme");
daemon.ready().expect("xhcid: failed to notify parent");
let mut hci = Arc::new(
let hci = Arc::new(
Xhci::new(scheme_name, address, interrupt_method, pcid_handle)
.expect("xhcid: failed to allocate device"),
);
@@ -207,26 +200,34 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
hci.poll();
let mut todo = Vec::<Packet>::new();
loop {
let mut packet = Packet::default();
match socket.read(&mut packet) {
Ok(0) => break,
Ok(_) => (),
Err(err) => panic!("xhcid failed to read from socket: {err}"),
}
let Some(request) = socket
.next_request(SignalBehavior::Restart)
.expect("xhcid: failed to read scheme")
else {
// Scheme likely got unmounted
std::process::exit(0);
};
let a = packet.a;
hci.handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.push(packet);
} else {
socket
.write(&packet)
.expect("xhcid failed to write to socket");
match request.kind() {
RequestKind::Call(call_request) => {
let resp = call_request.handle_scheme(&mut &*hci);
socket
.write_response(resp, SignalBehavior::Restart)
.expect("xhcid: failed to write scheme");
}
RequestKind::SendFd(sendfd_request) => {
socket
.write_response(
Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))),
SignalBehavior::Restart,
)
.expect("xhcid: failed to write response");
}
RequestKind::Cancellation(_cancellation_request) => {}
RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => {
unreachable!()
}
}
}
std::process::exit(0);
}
+60 -102
View File
@@ -28,7 +28,8 @@ use log::{debug, error, info, trace, warn};
use smallvec::SmallVec;
use common::io::Io;
use syscall::scheme::Scheme;
use redox_scheme::{CallerCtx, OpenResult, Scheme};
use syscall::schemev2::NewFdFlags;
use syscall::{
Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EINVAL, EIO, EISDIR, ENOENT, ENOSYS,
ENOTDIR, EPROTO, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_DIRECTORY, O_RDWR, O_STAT, O_WRONLY,
@@ -97,7 +98,7 @@ pub enum EndpointHandleTy {
Ctl,
/// portX/endpoints/Y/
Root(usize, Vec<u8>), // offset, content
Root(Vec<u8>), // content
}
#[derive(Clone, Copy, Debug)]
@@ -122,13 +123,13 @@ pub enum PortReqState {
/// Contains some information about the data requested via the handle.
#[derive(Debug)]
pub enum Handle {
TopLevel(usize, Vec<u8>), // offset, contents (ports)
Port(usize, usize, Vec<u8>), // port, offset, contents
PortDesc(usize, usize, Vec<u8>), // port, offset, contents
PortState(usize, usize), // port, offset
TopLevel(Vec<u8>), // contents (ports)
Port(usize, Vec<u8>), // port, contents
PortDesc(usize, Vec<u8>), // port, contents
PortState(usize), // port
PortReq(usize, PortReqState), // port, state
Endpoints(usize, usize, Vec<u8>), // port, offset, contents
Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, offset, state
Endpoints(usize, Vec<u8>), // port, contents
Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, state
ConfigureEndpoints(usize), // port
}
@@ -181,20 +182,20 @@ impl Handle {
/// - A [String] containing the scheme path that the handle is associated with.
pub(crate) fn to_scheme(&self) -> String {
match self {
Handle::TopLevel(_, _) => String::from(""),
Handle::Port(port_num, _, _) => {
Handle::TopLevel(_) => String::from(""),
Handle::Port(port_num, _) => {
format!("port{}", port_num)
}
Handle::PortDesc(port_num, _, _) => {
Handle::PortDesc(port_num, _) => {
format!("port{}/descriptors", port_num)
}
Handle::PortState(port_num, _) => {
Handle::PortState(port_num) => {
format!("port{}/state", port_num)
}
Handle::PortReq(port_num, _) => {
format!("port{}/request", port_num)
}
Handle::Endpoints(port_num, _, _) => {
Handle::Endpoints(port_num, _) => {
format!("port{}/endpoints", port_num)
}
Handle::Endpoint(port_num, endpoint_num, handle_type) => match handle_type {
@@ -204,7 +205,7 @@ impl Handle {
EndpointHandleTy::Ctl => {
format!("port{}/endpoints/{}/ctl", port_num, endpoint_num)
}
EndpointHandleTy::Root(_, _) => {
EndpointHandleTy::Root(_) => {
format!("port{}/endpoints/{}", port_num, endpoint_num)
}
},
@@ -224,21 +225,21 @@ impl Handle {
/// - [HandleType] - The access mode associated with the handle.
pub(crate) fn get_handle_type(&self) -> HandleType {
match self {
&Handle::TopLevel(_, _) => HandleType::Directory,
&Handle::Port(_, _, _) => HandleType::Directory,
&Handle::Endpoints(_, _, _) => HandleType::Directory,
&Handle::PortDesc(_, _, _) => HandleType::File,
&Handle::TopLevel(_) => HandleType::Directory,
&Handle::Port(_, _) => HandleType::Directory,
&Handle::Endpoints(_, _) => HandleType::Directory,
&Handle::PortDesc(_, _) => HandleType::File,
&Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(_, _)) => HandleType::Character,
&Handle::PortReq(_, PortReqState::WaitingForHostBytes(_, _)) => HandleType::Character,
&Handle::PortReq(_, PortReqState::Tmp) => unreachable!(),
&Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(),
&Handle::PortState(_, _) => HandleType::Character,
&Handle::PortState(_) => HandleType::Character,
&Handle::PortReq(_, _) => HandleType::Character,
&Handle::ConfigureEndpoints(_) => HandleType::Character,
&Handle::Endpoint(_, _, ref st) => match st {
EndpointHandleTy::Data => HandleType::Character,
EndpointHandleTy::Ctl => HandleType::Character,
EndpointHandleTy::Root(_, _) => HandleType::Directory,
EndpointHandleTy::Root(_) => HandleType::Directory,
},
}
}
@@ -252,21 +253,21 @@ impl Handle {
/// Either the size of the buffer, or [Option::None] if the buffer does not exist.
pub(crate) fn get_buf_len(&self) -> Option<usize> {
match self {
&Handle::TopLevel(_, ref buf) => Some(buf.len()),
&Handle::Port(_, _, ref buf) => Some(buf.len()),
&Handle::Endpoints(_, _, ref buf) => Some(buf.len()),
&Handle::PortDesc(_, _, ref buf) => Some(buf.len()),
&Handle::TopLevel(ref buf) => Some(buf.len()),
&Handle::Port(_, ref buf) => Some(buf.len()),
&Handle::Endpoints(_, ref buf) => Some(buf.len()),
&Handle::PortDesc(_, ref buf) => Some(buf.len()),
&Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) => Some(buf.len()),
&Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => Some(buf.len()),
&Handle::PortReq(_, PortReqState::Tmp) => None,
&Handle::PortReq(_, PortReqState::TmpSetup(_)) => None,
&Handle::PortState(_, _) => None,
&Handle::PortState(_) => None,
&Handle::PortReq(_, _) => None,
&Handle::ConfigureEndpoints(_) => None,
&Handle::Endpoint(_, _, ref st) => match st {
EndpointHandleTy::Data => None,
EndpointHandleTy::Ctl => None,
EndpointHandleTy::Root(_, ref buf) => Some(buf.len()),
EndpointHandleTy::Root(ref buf) => Some(buf.len()),
},
}
}
@@ -1551,13 +1552,11 @@ impl Xhci {
.dev_desc;
serde_json::to_vec(dev_desc).or(Err(Error::new(EIO)))
}
fn write_dyn_string(string: &[u8], buf: &mut [u8], offset: &mut usize) -> usize {
fn write_dyn_string(string: &[u8], buf: &mut [u8], offset: usize) -> usize {
let max_bytes_to_read = cmp::min(string.len(), buf.len());
let bytes_to_read = cmp::max(*offset, max_bytes_to_read) - *offset;
let bytes_to_read = cmp::max(offset, max_bytes_to_read) - offset;
buf[..bytes_to_read].copy_from_slice(&string[..bytes_to_read]);
*offset += bytes_to_read;
bytes_to_read
}
async fn port_req_transfer(
@@ -1735,7 +1734,7 @@ impl Xhci {
write!(contents, "port{}\n", index).unwrap();
}
Ok(Handle::TopLevel(0, contents))
Ok(Handle::TopLevel(contents))
} else {
Err(Error::new(EISDIR))
}
@@ -1758,7 +1757,7 @@ impl Xhci {
}
let contents = self.port_desc_json(port_num)?;
Ok(Handle::PortDesc(port_num, 0, contents))
Ok(Handle::PortDesc(port_num, contents))
}
/// implements open() for /port<n>
@@ -1792,7 +1791,7 @@ impl Xhci {
write!(contents, "configure\n").unwrap();
}
Ok(Handle::Port(port_num, 0, contents))
Ok(Handle::Port(port_num, contents))
} else {
Err(Error::new(EISDIR))
}
@@ -1814,7 +1813,7 @@ impl Xhci {
return Err(Error::new(ENOTDIR));
}
Ok(Handle::PortState(port_num, 0))
Ok(Handle::PortState(port_num))
}
/// implements open() for /port<n>/endpoints
@@ -1843,7 +1842,7 @@ impl Xhci {
write!(contents, "{}\n", ep_num).unwrap();
}
Ok(Handle::Endpoints(port_num, 0, contents))
Ok(Handle::Endpoints(port_num, contents))
}
/// implements open() for /port<n>/endpoints/<n>
@@ -1886,7 +1885,7 @@ impl Xhci {
Ok(Handle::Endpoint(
port_num,
endpoint_num,
EndpointHandleTy::Root(0, contents),
EndpointHandleTy::Root(contents),
))
}
@@ -1983,9 +1982,9 @@ impl Xhci {
}
}
impl Scheme for Xhci {
fn open(&self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if uid != 0 {
impl Scheme for &Xhci {
fn xopen(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
if ctx.uid != 0 {
return Err(Error::new(EACCES));
}
@@ -2025,11 +2024,14 @@ impl Scheme for Xhci {
self.handles.insert(fd, handle);
Ok(fd)
Ok(OpenResult::ThisScheme {
number: fd,
flags: NewFdFlags::POSITIONED,
})
}
fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> {
let mut guard = self.handles.get(&id).ok_or(Error::new(EBADF))?;
fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result<usize> {
let guard = self.handles.get(&id).ok_or(Error::new(EBADF))?;
stat.st_mode = match (&*guard).get_handle_type() {
HandleType::Directory => MODE_DIR,
@@ -2043,14 +2045,14 @@ impl Scheme for Xhci {
};
//If we have a handle to the configure scheme, we need to mark it as write only.
if let &Handle::ConfigureEndpoints(_) = (&*guard) {
if let &Handle::ConfigureEndpoints(_) = &*guard {
stat.st_mode = stat.st_mode | 0o200;
}
Ok(0)
}
fn fpath(&self, fd: usize, buffer: &mut [u8]) -> Result<usize> {
fn fpath(&mut self, fd: usize, buffer: &mut [u8]) -> Result<usize> {
let mut cursor = io::Cursor::new(buffer);
let guard = self.handles.get(&fd).ok_or(Error::new(EBADF))?;
@@ -2068,51 +2070,8 @@ impl Scheme for Xhci {
Ok(src_len)
}
fn seek(&self, fd: usize, pos: isize, whence: usize) -> Result<isize> {
let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?;
trace!(
"SEEK fd={}, handle={:?}, pos {}, whence {}",
fd,
guard,
pos,
whence
);
match &mut *guard {
// Directories, or fixed files
Handle::TopLevel(ref mut offset, ref buf)
| Handle::Port(_, ref mut offset, ref buf)
| Handle::PortDesc(_, ref mut offset, ref buf)
| Handle::Endpoints(_, ref mut offset, ref buf)
| Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref buf)) => {
let max = buf.len() as isize;
*offset = match whence {
SEEK_SET => cmp::max(0, cmp::min(pos, max)),
SEEK_CUR => cmp::max(0, cmp::min(*offset as isize + pos, max)),
SEEK_END => cmp::max(0, cmp::min(max + pos, max)),
_ => return Err(Error::new(EINVAL)),
} as usize;
Ok(*offset as isize)
}
Handle::PortState(_, ref mut offset) => {
match whence {
//TODO: checks for invalid pos
SEEK_SET => *offset = pos as usize,
SEEK_CUR => *offset = pos as usize,
SEEK_END => *offset = pos as usize,
_ => return Err(Error::new(EINVAL)),
};
Ok(*offset as isize)
}
// Write-once configure or transfer
Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) | Handle::PortReq(_, _) => {
Err(Error::new(ESPIPE))
}
}
}
fn read(&self, fd: usize, buf: &mut [u8]) -> Result<usize> {
fn read(&mut self, fd: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result<usize> {
let offset = offset as usize;
let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?;
trace!(
"READ fd={}, handle={:?}, buf=(addr {:p}, length {})",
@@ -2122,16 +2081,15 @@ impl Scheme for Xhci {
buf.len()
);
match &mut *guard {
Handle::TopLevel(ref mut offset, ref src_buf)
| Handle::Port(_, ref mut offset, ref src_buf)
| Handle::PortDesc(_, ref mut offset, ref src_buf)
| Handle::Endpoints(_, ref mut offset, ref src_buf)
| Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref src_buf)) => {
Handle::TopLevel(ref src_buf)
| Handle::Port(_, ref src_buf)
| Handle::PortDesc(_, ref src_buf)
| Handle::Endpoints(_, ref src_buf)
| Handle::Endpoint(_, _, EndpointHandleTy::Root(ref src_buf)) => {
let max_bytes_to_read = cmp::min(src_buf.len(), buf.len());
let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset;
let bytes_to_read = cmp::max(max_bytes_to_read, offset) - offset;
buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]);
*offset += bytes_to_read;
Ok(bytes_to_read)
}
@@ -2140,9 +2098,9 @@ impl Scheme for Xhci {
&mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st {
EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf),
EndpointHandleTy::Data => block_on(self.on_read_endp_data(port_num, endp_num, buf)),
EndpointHandleTy::Root(_, _) => Err(Error::new(EBADF)),
EndpointHandleTy::Root(_) => Err(Error::new(EBADF)),
},
&mut Handle::PortState(port_num, ref mut offset) => {
&mut Handle::PortState(port_num) => {
let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?;
let state = self
.dev_ctx
@@ -2164,7 +2122,7 @@ impl Scheme for Xhci {
.unwrap_or("unknown")
.as_bytes();
Ok(Self::write_dyn_string(string, buf, offset))
Ok(Xhci::write_dyn_string(string, buf, offset))
}
&mut Handle::PortReq(port_num, ref mut st) => {
let state = std::mem::replace(st, PortReqState::Tmp);
@@ -2173,7 +2131,7 @@ impl Scheme for Xhci {
}
}
}
fn write(&self, fd: usize, buf: &[u8]) -> Result<usize> {
fn write(&mut self, fd: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result<usize> {
let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?;
trace!(
"WRITE fd={}, handle={:?}, buf=(addr {:p}, length {})",
@@ -2193,7 +2151,7 @@ impl Scheme for Xhci {
EndpointHandleTy::Data => {
block_on(self.on_write_endp_data(port_num, endp_num, buf))
}
EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)),
EndpointHandleTy::Root(_) => return Err(Error::new(EBADF)),
},
&mut Handle::PortReq(port_num, ref mut st) => {
let state = std::mem::replace(st, PortReqState::Tmp);
@@ -2205,7 +2163,7 @@ impl Scheme for Xhci {
_ => Err(Error::new(EBADF)),
}
}
fn close(&self, fd: usize) -> Result<usize> {
fn close(&mut self, fd: usize) -> Result<usize> {
if self.handles.remove(&fd).is_none() {
return Err(Error::new(EBADF));
}