From 7536048ceb5115c5fe883bb6824e9aa48a070b7f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 14 Mar 2020 12:13:47 +0100 Subject: [PATCH 01/22] Parse some of the PCI capabilities, and setup IPC. --- Cargo.lock | 16 +- initfs.toml | 4 +- pcid/.gitignore | 1 + pcid/Cargo.toml | 18 +- pcid/src/config.rs | 7 +- pcid/src/driver_interface.rs | 132 ++++++++++++++ pcid/src/lib.rs | 7 + pcid/src/main.rs | 84 +++++++-- pcid/src/pci/bar.rs | 4 +- pcid/src/pci/bus.rs | 3 + pcid/src/pci/cap.rs | 344 +++++++++++++++++++++++++++++++++++ pcid/src/pci/dev.rs | 3 + pcid/src/pci/func.rs | 21 ++- pcid/src/pci/header.rs | 5 +- pcid/src/pci/mod.rs | 1 + xhcid/Cargo.toml | 1 + xhcid/src/main.rs | 9 + 17 files changed, 626 insertions(+), 34 deletions(-) create mode 100644 pcid/.gitignore create mode 100644 pcid/src/driver_interface.rs create mode 100644 pcid/src/lib.rs create mode 100644 pcid/src/pci/cap.rs diff --git a/Cargo.lock b/Cargo.lock index c41a1e0178..aa3a88a748 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -686,10 +686,12 @@ version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1303,14 +1305,6 @@ dependencies = [ "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] -[[package]] -name = "toml" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "toml" version = "0.5.6" @@ -1524,6 +1518,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pcid 0.1.0", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", @@ -1671,7 +1666,6 @@ dependencies = [ "checksum tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" diff --git a/initfs.toml b/initfs.toml index b604eec197..6861491750 100644 --- a/initfs.toml +++ b/initfs.toml @@ -22,7 +22,7 @@ vendor = 33006 device = 48879 command = ["bgad", "$NAME", "$BAR0"] -#nvmed +# nvmed [[drivers]] name = "NVME storage" class = 1 @@ -37,9 +37,11 @@ vendor = 33006 device = 51966 command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] +# xhcid [[drivers]] name = "XHCI" class = 12 subclass = 3 interface = 48 command = ["xhcid", "$NAME", "$BAR0", "$IRQ"] +channel_name = "pcid-xhcid" diff --git a/pcid/.gitignore b/pcid/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/pcid/.gitignore @@ -0,0 +1 @@ +/target diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index e35303f094..a899c78fa4 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -3,10 +3,20 @@ name = "pcid" version = "0.1.0" edition = "2018" +[[bin]] +name = "pcid" +path = "src/main.rs" + +[lib] +name = "pcid_interface" +path = "src/lib.rs" + [dependencies] -bitflags = "1.0" +bitflags = "1" byteorder = "1.2" +libc = "0.2" redox_syscall = "0.1" -serde = "1.0" -serde_derive = "1.0" -toml = "0.4" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +thiserror = "1" +toml = "0.5" diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 74ba8b4eaa..b57ef14dd3 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -1,9 +1,11 @@ use std::collections::BTreeMap; use std::ops::Range; +use serde::Deserialize; + #[derive(Debug, Default, Deserialize)] pub struct Config { - pub drivers: Vec + pub drivers: Vec, } #[derive(Debug, Default, Deserialize)] @@ -16,5 +18,6 @@ pub struct DriverConfig { pub vendor: Option, pub device: Option, pub device_id_range: Option>, - pub command: Option> + pub command: Option>, + pub channel_name: Option, } diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs new file mode 100644 index 0000000000..7a514b8426 --- /dev/null +++ b/pcid/src/driver_interface.rs @@ -0,0 +1,132 @@ +use std::fs::{File, OpenOptions}; +use std::io::prelude::*; +use std::{env, io}; + +use std::os::unix::io::{FromRawFd, RawFd}; + +use serde::{Serialize, Deserialize, de::DeserializeOwned}; +use thiserror::Error; + +use crate::pci; + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct PciFunction { + /// Number of PCI bus + pub bus_num: u8, + /// Number of PCI device + pub dev_num: u8, + /// Number of PCI function + pub func_num: u8, + /// PCI Base Address Registers + pub bars: [pci::PciBar; 6], + /// BAR sizes + pub bar_sizes: [u32; 6], + /// Legacy IRQ line + // TODO: Stop using legacy IRQ lines, and physical pins, but MSI/MSI-X instead. + pub legacy_interrupt_line: u8, + /// Vendor ID + pub venid: u16, + /// Device ID + pub devid: u16, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct SubdriverArguments { + pub func: PciFunction, + pub capabilities: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum PciCapabilitiy { + Msi, + MsiX, +} + +#[derive(Debug, Error)] +pub enum PcidClientHandleError { + #[error("i/o error: {0}")] + IoError(#[from] io::Error), + + #[error("JSON ser/de error: {0}")] + SerializationError(#[from] serde_json::Error), + + #[error("environment variable error: {0}")] + EnvError(#[from] env::VarError), + + #[error("malformed fd: {0}")] + EnvValidityError(std::num::ParseIntError), + + #[error("invalid response: {0:?}")] + InvalidResponse(PcidClientResponse), +} +pub type Result = std::result::Result; + +#[derive(Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum PcidClientRequest { + RequestConfig, +} + +#[derive(Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum PcidClientResponse { + Config(SubdriverArguments), +} + +// TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over +// a channel, the communication could potentially be done via mmap, using a channel +// very similar to crossbeam-channel or libstd's mpsc (except the cycle, enqueue and dequeue fields +// are stored in the same buffer). +/// A handle from a `pcid` client (e.g. `ahcid`) to `pcid`. +pub struct PcidServerHandle { + pcid_to_client: File, + pcid_from_client: File, +} + +pub(crate) fn send(w: &mut W, message: &T) -> Result<()> { + // TODO: Use bincode. + let data = serde_json::to_vec(message)?; + let length_bytes = u64::to_le_bytes(data.len() as u64); + w.write_all(&length_bytes)?; + w.write_all(&data)?; + Ok(()) +} +pub(crate) fn recv(r: &mut R) -> Result { + let mut length_bytes = [0u8; 8]; + r.read_exact(&mut length_bytes)?; + let length = u64::from_le_bytes(length_bytes); + if length > 0x100_000 { + panic!("pcid_interface: Too large buffer"); + } + let mut data = vec! [0u8; length as usize]; + r.read_exact(&mut data)?; + + Ok(serde_json::from_slice(&data)?) +} + +impl PcidServerHandle { + pub fn connect(pcid_to_client: RawFd, pcid_from_client: RawFd) -> Result { + Ok(Self { + pcid_to_client: unsafe { File::from_raw_fd(pcid_to_client) }, + pcid_from_client: unsafe { File::from_raw_fd(pcid_from_client) }, + }) + } + pub fn connect_default() -> Result { + let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; + let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; + + Self::connect(pcid_to_client_fd, pcid_from_client_fd) + } + pub(crate) fn send(&mut self, req: &PcidClientRequest) -> Result<()> { + send(&mut self.pcid_from_client, req) + } + pub(crate) fn recv(&mut self) -> Result { + recv(&mut self.pcid_to_client) + } + pub fn fetch_config(&mut self) -> Result { + self.send(&PcidClientRequest::RequestConfig)?; + match self.recv()? { + PcidClientResponse::Config(a) => Ok(a), + } + } +} diff --git a/pcid/src/lib.rs b/pcid/src/lib.rs new file mode 100644 index 0000000000..e03e5bfccf --- /dev/null +++ b/pcid/src/lib.rs @@ -0,0 +1,7 @@ +//! Interface to `pcid`. + +#![feature(asm)] + +mod driver_interface; +mod pci; +pub use driver_interface::*; diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 88d85e07c0..34e4876973 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,21 +1,24 @@ #![feature(asm)] -#[macro_use] extern crate bitflags; +extern crate bitflags; extern crate byteorder; -#[macro_use] extern crate serde_derive; extern crate syscall; extern crate toml; -use std::{env, i64}; +use std::{env, io, i64}; use std::fs::{File, metadata, read_dir}; -use std::io::Read; +use std::io::prelude::*; +use std::os::unix::io::{FromRawFd, RawFd}; use std::process::Command; use syscall::iopl; +use std::os::unix::process::CommandExt; + use crate::config::Config; use crate::pci::{Pci, PciBar, PciClass, PciHeader, PciHeaderError, PciHeaderType}; mod config; +mod driver_interface; mod pci; fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, @@ -24,14 +27,16 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", bus_num, dev_num, func_num, header.vendor_id(), header.device_id(), raw_class, header.subclass(), header.interface(), header.revision(), header.class()); - match header.class() { + PciClass::Legacy if header.subclass() == 1 => string.push_str(" VGA CTL"), PciClass::Storage => match header.subclass() { 0x01 => { string.push_str(" IDE"); }, - 0x06 => { - string.push_str(" SATA"); + 0x06 => if header.interface() == 0 { + string.push_str(" SATA VND"); + } else if header.interface() == 1 { + string.push_str(" SATA AHCI"); }, _ => () }, @@ -166,6 +171,23 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, } } + let func = driver_interface::PciFunction { + bars, + bar_sizes, + bus_num, + dev_num, + func_num, + devid: header.device_id(), + legacy_interrupt_line: irq, + venid: header.vendor_id(), + }; + let capabilities = Vec::new(); + + let subdriver_args = driver_interface::SubdriverArguments { + capabilities, + func, + }; + // TODO: find a better way to pass the header data down to the // device driver, making passing the capabilities list etc // posible. @@ -199,16 +221,54 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, } println!("PCID SPAWN {:?}", command); - match command.spawn() { - Ok(mut child) => match child.wait() { - Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()), - Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err) - }, + + let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.channel_name.is_some() { + let mut fds1 = [0usize; 2]; + let mut fds2 = [0usize; 2]; + + syscall::pipe2(&mut fds1, 0).expect("pcid: failed to create pcid->client pipe"); + syscall::pipe2(&mut fds2, 0).expect("pcid: failed to create client->pcid pipe"); + + let [pcid_to_client_read, pcid_to_client_write] = fds1; + let [pcid_from_client_read, pcid_from_client_write] = fds2; + + (Some(pcid_to_client_write), Some(pcid_from_client_read), vec! [("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write))]) + } else { + (None, None, vec! []) + }; + + match command.envs(envs).spawn() { + Ok(mut child) => { + handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); + match child.wait() { + Ok(_status) => (), + Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err), + } + } Err(err) => println!("pcid: failed to execute {:?}: {}", command, err) } } } } + fn handle_spawn(pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { + use driver_interface::*; + + // TODO: Instead of relying on the subdriver to correctly close the pipe, there should be a + // dedicated thread responsible for this. Or alternatively, a thread pool with Futures. + + if let (Some(pcid_to_client_fd), Some(pcid_from_client_fd)) = (pcid_to_client_write, pcid_from_client_read) { + let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd as RawFd) }; + let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd as RawFd) }; + + if let Ok(msg) = recv(&mut pcid_from_client) { + match msg { + PcidClientRequest::RequestConfig => { + send(&mut pcid_to_client, &PcidClientResponse::Config(args.clone())).unwrap(); + } + } + } + } + } } fn main() { diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index b1efde2e38..1ff92f9739 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -1,6 +1,8 @@ use std::fmt; -#[derive(Clone, Copy, Debug, PartialEq)] +use serde::{Serialize, Deserialize}; + +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum PciBar { None, Memory(u32), diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs index 120fa458f9..388e796e61 100644 --- a/pcid/src/pci/bus.rs +++ b/pcid/src/pci/bus.rs @@ -13,6 +13,9 @@ impl<'pci> PciBus<'pci> { pub unsafe fn read(&self, dev: u8, func: u8, offset: u8) -> u32 { self.pci.read(self.num, dev, func, offset) } + pub unsafe fn write(&self, dev: u8, func: u8, offset: u8, value: u32) { + self.pci.write(self.num, dev, func, offset, value) + } } pub struct PciBusIter<'pci> { diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs new file mode 100644 index 0000000000..7ac6c3a07a --- /dev/null +++ b/pcid/src/pci/cap.rs @@ -0,0 +1,344 @@ +use super::func::{ConfigReader, ConfigWriter}; + +pub struct CapabilityOffsetsIter<'a, R> { + offset: u8, + reader: &'a R, +} +impl<'a, R> CapabilityOffsetsIter<'a, R> { + pub fn new(offset: u8, reader: &'a R) -> Self { + Self { + offset, + reader, + } + } +} +impl<'a, R> Iterator for CapabilityOffsetsIter<'a, R> +where + R: ConfigReader +{ + type Item = u8; + + fn next(&mut self) -> Option { + unsafe { + assert_eq!(self.offset & 0xF8, self.offset, "capability must be dword aligned"); + + if self.offset == 0 { return None }; + + let first_dword = dbg!(self.reader.read_u32(dbg!(self.offset))); + let next = ((first_dword >> 8) & 0xFF) as u8; + + let offset = self.offset; + self.offset = next; + + Some(offset) + } + } +} + +#[repr(u8)] +pub enum CapabilityId { + Msi = 0x05, + MsiX = 0x11, + Pcie = 0x10, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum MsiCapability { + _32BitAddress { + message_control: u32, + message_address: u32, + message_data: u32, + }, + _64BitAddress { + message_control: u32, + message_address_lo: u32, + message_address_hi: u32, + message_data: u32, + }, + _32BitAddressWithPvm { + message_control: u32, + message_address: u32, + message_data: u32, + mask_bits: u32, + pending_bits: u32, + }, + _64BitAddressWithPvm { + message_control: u32, + message_address_lo: u32, + message_address_hi: u32, + message_data: u32, + mask_bits: u32, + pending_bits: u32, + }, +} + +impl MsiCapability { + pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; + pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; + + pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E; + pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1; + + pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070; + pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4; + + pub const MC_MSI_ENABLED_BIT: u16 = 1; + + pub unsafe fn parse(reader: &R, offset: u8) -> Self { + let dword = reader.read_u32(offset); + + let message_control = (dword >> 16) as u16; + + if message_control & Self::MC_PVT_CAPABLE_BIT != 0 { + if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { + Self::_64BitAddressWithPvm { + message_control: dword, + message_address_lo: reader.read_u32(offset + 4), + message_address_hi: reader.read_u32(offset + 8), + message_data: reader.read_u32(offset + 12), + mask_bits: reader.read_u32(offset + 16), + pending_bits: reader.read_u32(offset + 20), + } + } else { + Self::_32BitAddressWithPvm { + message_control: dword, + message_address: reader.read_u32(offset + 4), + message_data: reader.read_u32(offset + 8), + mask_bits: reader.read_u32(offset + 12), + pending_bits: reader.read_u32(offset + 16), + } + } + } else { + if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { + Self::_64BitAddress { + message_control: dword, + message_address_lo: reader.read_u32(offset + 4), + message_address_hi: reader.read_u32(offset + 8), + message_data: reader.read_u32(offset + 12), + } + } else { + Self::_32BitAddress { + message_control: dword, + message_address: reader.read_u32(offset + 4), + message_data: reader.read_u32(offset + 8), + } + } + } + } + + fn message_control_raw(&self) -> u32 { + match self { + Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control, + } + } + pub fn message_control(&self) -> u16 { + self.message_control_raw() as u16 + } + pub unsafe fn set_message_control(&mut self, writer: &mut W, offset: u8, value: u16) { + let mut new_message_control = self.message_control_raw(); + new_message_control &= 0x0000_FFFF; + new_message_control |= u32::from(value) << 16; + writer.write_u32(offset, new_message_control); + + match self { + Self::_32BitAddress { ref mut message_control, .. } + | Self::_64BitAddress { ref mut message_control, .. } + | Self::_32BitAddressWithPvm { ref mut message_control, .. } + | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, + } + } + pub fn is_pvt_capable(&self) -> bool { + self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 + } + pub fn has_64_bit_addr(&self) -> bool { + self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0 + } + pub fn enabled(&self) -> bool { + self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 + } + pub unsafe fn set_enabled(&mut self, writer: &mut W, offset: u8, enabled: bool) { + let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); + new_message_control |= u16::from(enabled); + self.set_message_control(writer, offset, new_message_control) + } + pub fn multi_message_capable(&self) -> u8 { + ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 + } + pub fn multi_message_enabled(&self) -> u8 { + ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_MASK) as u8 + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct PcieCapability { +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct MsixCapability { + pub a: u32, + pub b: u32, + pub c: u32, +} + +impl MsixCapability { + pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; + pub const MC_MSIX_ENABLED_SHIFT: u8 = 15; + pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; + pub const MC_FUNCTION_MASK_SHIFT: u8 = 14; + pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF; + + /// The Message Control field, containing the enabled and function mask bits, as well as the + /// table size. + pub const fn message_control(&self) -> u16 { + (self.a >> 16) as u16 + } + pub fn set_message_control(&mut self, message_control: u16) { + self.a &= 0x0000_FFFF; + self.a |= u32::from(message_control) << 16; + } + /// Returns the MSI-X table size, subtracted by one. + pub const fn table_size_raw(&self) -> u16 { + self.message_control() & Self::MC_TABLE_SIZE_MASK + } + /// Returns the MSI-X table size. + pub const fn table_size(&self) -> u16 { + self.table_size_raw() + 1 + } + /// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the + /// MSI capability structure. + pub const fn msix_enabled(&self) -> bool { + self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0 + } + /// The MSI-X function mask, which overrides each of the vectors' mask bit, when set. + pub const fn function_mask(&self) -> bool { + self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0 + } + + pub fn set_msix_enabled(&mut self, enabled: bool) { + let mut new_message_control = self.message_control(); + new_message_control &= !(Self::MC_MSIX_ENABLED_BIT); + new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT; + self.set_message_control(new_message_control); + } + + pub fn set_function_mask(&mut self, function_mask: bool) { + let mut new_message_control = self.message_control(); + new_message_control &= !(Self::MC_FUNCTION_MASK_BIT); + new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT; + self.set_message_control(new_message_control); + } + pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8; + pub const TABLE_BIR_MASK: u32 = 0x0000_0007; + + /// The table offset is guaranteed to be QWORD aligned (8 bytes). + pub const fn table_offset(&self) -> u32 { + self.b & Self::TABLE_OFFSET_MASK + } + /// The table BIR, which is used to map the offset to a memory location. + pub const fn table_bir(&self) -> u8 { + (self.b & Self::TABLE_BIR_MASK) as u8 + } + + pub fn set_table_offset(&mut self, offset: u32) { + assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned"); + self.b &= !Self::TABLE_OFFSET_MASK; + self.b |= offset; + } + pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8; + pub const PBA_BIR_MASK: u32 = 0x0000_0007; + + /// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes). + pub const fn pba_offset(&self) -> u32 { + self.b & Self::PBA_OFFSET_MASK + } + /// The Pending Bit Array BIR, which is used to map the offset to a memory location. + pub const fn pba_bir(&self) -> u8 { + (self.b & Self::PBA_BIR_MASK) as u8 + } + + pub fn set_pba_offset(&mut self, offset: u32) { + assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned"); + self.c &= !Self::PBA_OFFSET_MASK; + self.c |= offset; + } + + /// Write the first DWORD into configuration space (containing the partially modifiable Message + /// Control field). + pub unsafe fn write_a(&self, writer: &W, offset: u8) { + writer.write_u32(offset, self.a) + } + /// Write the second DWORD into configuration space (containing the modifiable table + /// offset and the readonly table BIR). + pub unsafe fn write_b(&self, writer: &W, offset: u8) { + writer.write_u32(offset + 4, self.a) + } + /// Write the third DWORD into configuration space (containing the modifiable pending bit array + /// offset, and the readonly PBA BIR). + pub unsafe fn write_c(&self, writer: &W, offset: u8) { + writer.write_u32(offset + 8, self.a) + } + /// Write this capability structure back to configuration space. + pub unsafe fn write_all(&self, writer: &W, offset: u8) { + self.write_a(writer, offset); + self.write_b(writer, offset); + self.write_c(writer, offset); + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum Capability { + Msi(MsiCapability), + MsiX(MsixCapability), + Pcie(PcieCapability), + Other(u8), +} + +impl Capability { + unsafe fn parse_msi(reader: &R, offset: u8) -> Self { + Self::Msi(MsiCapability::parse(reader, offset)) + } + unsafe fn parse_msix(reader: &R, offset: u8) -> Self { + Self::MsiX(MsixCapability { + a: reader.read_u32(offset), + b: reader.read_u32(offset + 4), + c: reader.read_u32(offset + 8), + }) + } + unsafe fn parse_pcie(reader: &R, offset: u8) -> Self { + // TODO + Self::Pcie(PcieCapability {}) + } + unsafe fn parse(reader: &R, offset: u8) -> Self { + assert_eq!(offset & 0xF8, offset, "capability must be dword aligned"); + + let dword = reader.read_u32(offset); + let capability_id = (dword & 0xFF) as u8; + + if capability_id == CapabilityId::Msi as u8 { + Self::parse_msi(reader, offset) + } else if capability_id == CapabilityId::MsiX as u8 { + Self::parse_msix(reader, offset) + } else if capability_id == CapabilityId::Pcie as u8 { + Self::parse_pcie(reader, offset) + } else { + Self::Other(capability_id) + //panic!("unimplemented or malformed capability id: {}", capability_id) + } + } +} + +pub struct CapabilitiesIter<'a, R> { + pub inner: CapabilityOffsetsIter<'a, R>, +} + +impl<'a, R> Iterator for CapabilitiesIter<'a, R> +where + R: ConfigReader +{ + type Item = Capability; + + fn next(&mut self) -> Option { + let offset = self.inner.next()?; + Some(unsafe { Capability::parse(self.inner.reader, offset) }) + } +} diff --git a/pcid/src/pci/dev.rs b/pcid/src/pci/dev.rs index 05088886e8..6d021994e5 100644 --- a/pcid/src/pci/dev.rs +++ b/pcid/src/pci/dev.rs @@ -13,6 +13,9 @@ impl<'pci> PciDev<'pci> { pub unsafe fn read(&self, func: u8, offset: u8) -> u32 { self.bus.read(self.num, func, offset) } + pub unsafe fn write(&self, func: u8, offset: u8, value: u32) { + self.bus.write(self.num, func, offset, value); + } } pub struct PciDevIter<'pci> { diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index 5c206f3607..0a3be3c874 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -2,6 +2,9 @@ use byteorder::{LittleEndian, ByteOrder}; use super::PciDev; +// TODO: PCI Express Configuration Space, which uses a flat memory buffer, rather than IN/OUT +// instructions. + pub trait ConfigReader { unsafe fn read_range(&self, offset: u8, len: u8) -> Vec { assert!(len > 3 && len % 4 == 0); @@ -17,11 +20,22 @@ pub trait ConfigReader { } unsafe fn read_u32(&self, offset: u8) -> u32; + + unsafe fn read_u8(&self, offset: u8) -> u8 { + let dword_offset = (offset / 4) * 4; + let dword = self.read_u32(dword_offset); + + let shift = (offset % 4) * 8; + ((dword >> shift) & 0xFF) as u8 + } +} +pub trait ConfigWriter { + unsafe fn write_u32(&self, offset: u8, value: u32); } pub struct PciFunc<'pci> { pub dev: &'pci PciDev<'pci>, - pub num: u8 + pub num: u8, } impl<'pci> ConfigReader for PciFunc<'pci> { @@ -29,3 +43,8 @@ impl<'pci> ConfigReader for PciFunc<'pci> { self.dev.read(self.num, offset) } } +impl<'pci> ConfigWriter for PciFunc<'pci> { + unsafe fn write_u32(&self, offset: u8, value: u32) { + self.dev.write(self.num, offset, value); + } +} diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 272d917b1f..e4197436a9 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -3,6 +3,7 @@ use byteorder::{LittleEndian, ByteOrder}; use super::func::ConfigReader; use super::class::PciClass; use super::bar::PciBar; +use bitflags::bitflags; #[derive(Debug, PartialEq)] pub enum PciHeaderError { @@ -123,8 +124,9 @@ impl PciHeader { let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]); let subsystem_id = LittleEndian::read_u16(&bytes[30..32]); let expansion_rom_bar = LittleEndian::read_u32(&bytes[32..36]); - // TODO: Parse out the capabilities list. let cap_pointer = bytes[36]; + println!("PCI DEVICE CAPABILITIES: {:?}", crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(cap_pointer, &reader) }.collect::>()); + let interrupt_line = bytes[44]; let interrupt_pin = bytes[45]; let min_grant = bytes[46]; @@ -158,7 +160,6 @@ impl PciHeader { let prefetch_limit_upper = LittleEndian::read_u32(&bytes[28..32]); let io_base_upper = LittleEndian::read_u16(&bytes[32..34]); let io_limit_upper = LittleEndian::read_u16(&bytes[34..36]); - // TODO: Parse out the capabilities list. let cap_pointer = bytes[36]; let expansion_rom = LittleEndian::read_u32(&bytes[40..44]); let interrupt_line = bytes[44]; diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index e70048fd84..8209e09a45 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -7,6 +7,7 @@ pub use self::header::{PciHeader, PciHeaderError, PciHeaderType}; mod bar; mod bus; +pub mod cap; mod class; mod dev; mod func; diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index b67f291149..0ef92d5fd7 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -23,3 +23,4 @@ serde_json = "1" smallvec = { version = "1", features = ["serde"] } thiserror = "1" toml = "0.5" +pcid = { path = "../pcid" } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 2cc823886d..0de08d86e9 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -23,6 +23,15 @@ mod usb; mod xhci; fn main() { + println!("xhcid started"); + let mut pcid_handle = pcid_interface::PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); + dbg!(); + println!("XHCI from PCI config: {:?}", pcid_handle.fetch_config().expect("xhcid: failed to fetch config")); + + // Close the pipe, allowing pcid to continue. + drop(pcid_handle); + + let mut args = env::args().skip(1); let mut name = args.next().expect("xhcid: no name provided"); From 735c55f65621b4a47cc79c0c37164b899ce341b1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 14 Mar 2020 14:19:58 +0100 Subject: [PATCH 02/22] Rebase. --- Cargo.lock | 11 +++ pcid/Cargo.toml | 1 + pcid/src/config.rs | 4 +- pcid/src/driver_interface.rs | 47 +++++++-- pcid/src/main.rs | 182 +++++++++++++++++++++++++++++------ pcid/src/pci/cap.rs | 45 ++++++++- pcid/src/pci/header.rs | 9 +- pcid/src/pci/mod.rs | 25 ++++- 8 files changed, 273 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa3a88a748..e0a97cc6da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,6 +84,15 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bincode" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.7.0" @@ -684,6 +693,7 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ + "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1539,6 +1549,7 @@ dependencies = [ "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index a899c78fa4..189aed0338 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -12,6 +12,7 @@ name = "pcid_interface" path = "src/lib.rs" [dependencies] +bincode = "1.2" bitflags = "1" byteorder = "1.2" libc = "0.2" diff --git a/pcid/src/config.rs b/pcid/src/config.rs index b57ef14dd3..3c79746816 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -3,12 +3,12 @@ use std::ops::Range; use serde::Deserialize; -#[derive(Debug, Default, Deserialize)] +#[derive(Clone, Debug, Default, Deserialize)] pub struct Config { pub drivers: Vec, } -#[derive(Debug, Default, Deserialize)] +#[derive(Clone, Debug, Default, Deserialize)] pub struct DriverConfig { pub name: Option, pub class: Option, diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs index 7a514b8426..cf5e24336d 100644 --- a/pcid/src/driver_interface.rs +++ b/pcid/src/driver_interface.rs @@ -33,11 +33,26 @@ pub struct PciFunction { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SubdriverArguments { pub func: PciFunction, - pub capabilities: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum PciCapabilitiy { +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub enum FeatureStatus { + Enabled, + Disabled, +} + +impl FeatureStatus { + pub fn enabled(enabled: bool) -> Self { + if enabled { + Self::Enabled + } else { + Self::Disabled + } + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub enum PciFeature { Msi, MsiX, } @@ -48,7 +63,7 @@ pub enum PcidClientHandleError { IoError(#[from] io::Error), #[error("JSON ser/de error: {0}")] - SerializationError(#[from] serde_json::Error), + SerializationError(#[from] bincode::Error), #[error("environment variable error: {0}")] EnvError(#[from] env::VarError), @@ -65,18 +80,31 @@ pub type Result = std::result::Result; #[non_exhaustive] pub enum PcidClientRequest { RequestConfig, + RequestFeatures, + EnableFeature(PciFeature), + FeatureStatus(PciFeature), +} + +#[derive(Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum PcidServerResponseError { + NonexistentFeature(PciFeature), } #[derive(Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum PcidClientResponse { Config(SubdriverArguments), + AllFeatures(Vec<(PciFeature, FeatureStatus)>), + FeatureEnabled(PciFeature), + FeatureStatus(PciFeature, FeatureStatus), + Error(PcidServerResponseError), } // TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over // a channel, the communication could potentially be done via mmap, using a channel // very similar to crossbeam-channel or libstd's mpsc (except the cycle, enqueue and dequeue fields -// are stored in the same buffer). +// are stored in the same buffer as the actual data). /// A handle from a `pcid` client (e.g. `ahcid`) to `pcid`. pub struct PcidServerHandle { pcid_to_client: File, @@ -84,8 +112,8 @@ pub struct PcidServerHandle { } pub(crate) fn send(w: &mut W, message: &T) -> Result<()> { - // TODO: Use bincode. - let data = serde_json::to_vec(message)?; + let mut data = Vec::new(); + bincode::serialize_into(&mut data, message)?; let length_bytes = u64::to_le_bytes(data.len() as u64); w.write_all(&length_bytes)?; w.write_all(&data)?; @@ -96,12 +124,12 @@ pub(crate) fn recv(r: &mut R) -> Result { r.read_exact(&mut length_bytes)?; let length = u64::from_le_bytes(length_bytes); if length > 0x100_000 { - panic!("pcid_interface: Too large buffer"); + panic!("pcid_interface: buffer too large"); } let mut data = vec! [0u8; length as usize]; r.read_exact(&mut data)?; - Ok(serde_json::from_slice(&data)?) + Ok(bincode::deserialize_from(&data[..])?) } impl PcidServerHandle { @@ -127,6 +155,7 @@ impl PcidServerHandle { self.send(&PcidClientRequest::RequestConfig)?; match self.recv()? { PcidClientResponse::Config(a) => Ok(a), + other => Err(PcidClientHandleError::InvalidResponse(other)), } } } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 34e4876973..78416db8c3 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -5,24 +5,132 @@ extern crate byteorder; extern crate syscall; extern crate toml; -use std::{env, io, i64}; use std::fs::{File, metadata, read_dir}; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; use std::process::Command; +use std::sync::{Arc, Mutex}; +use std::{env, io, i64, thread}; + use syscall::iopl; -use std::os::unix::process::CommandExt; - use crate::config::Config; -use crate::pci::{Pci, PciBar, PciClass, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{Pci, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::cap::Capability as PciCapability; mod config; mod driver_interface; mod pci; -fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, +pub struct DriverHandler { + config: config::DriverConfig, + bus_num: u8, + dev_num: u8, + func_num: u8, + header: PciHeader, + capabilities: Vec<(u8, PciCapability)>, + + state: Arc, +} +fn with_pci_func_raw T>(pci: &Pci, bus_num: u8, dev_num: u8, func_num: u8, function: F) -> T { + let bus = PciBus { + pci, + num: bus_num, + }; + let dev = PciDev { + bus: &bus, + num: dev_num, + }; + let func = PciFunc { + dev: &dev, + num: func_num, + }; + function(&func) +} +impl DriverHandler { + fn with_pci_func_raw T>(&self, function: F) -> T { + with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, function) + } + fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse { + use driver_interface::*; + use crate::pci::cap::{MsiCapability, MsixCapability}; + + match request { + PcidClientRequest::RequestConfig => { + PcidClientResponse::Config(args.clone()) + } + PcidClientRequest::RequestFeatures => { + PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability { + PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))), + // TODO: For MSI-X to actually be enabled, MSI also has to be enabled. + // How should this be reported to the subdrivers? + PciCapability::MsiX(msix) => Some((PciFeature::MsiX, FeatureStatus::enabled(msix.msix_enabled()))), + _ => None, + }).collect()) + } + PcidClientRequest::EnableFeature(feature) => match feature { + PciFeature::Msi => { + let (offset, capability): (u8, &mut MsiCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msi_mut().map(|cap| (offset, cap))) { + Some(tuple) => tuple, + None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), + }; + unsafe { + with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| capability.set_enabled(func, offset, true)); + } + PcidClientResponse::FeatureEnabled(feature) + } + PciFeature::MsiX => { + let (offset, capability): (u8, &mut MsixCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msix_mut().map(|cap| (offset, cap))) { + Some(tuple) => tuple, + None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), + }; + unsafe { + with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| { + capability.set_msix_enabled(true); + capability.write_a(func, offset); + }); + } + PcidClientResponse::FeatureEnabled(feature) + } + } + PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus(feature, match feature { + PciFeature::Msi => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::Msi(msi) = capability { + Some(FeatureStatus::enabled(msi.enabled())) + } else { + None + }).unwrap_or(FeatureStatus::Disabled), + PciFeature::MsiX => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::MsiX(msix) = capability { + Some(FeatureStatus::enabled(msix.msix_enabled())) + } else { + None + }).unwrap_or(FeatureStatus::Disabled), + }), + } + } + fn handle_spawn(mut self, pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { + use driver_interface::*; + + if let (Some(pcid_to_client_fd), Some(pcid_from_client_fd)) = (pcid_to_client_write, pcid_from_client_read) { + let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd as RawFd) }; + let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd as RawFd) }; + + while let Ok(msg) = recv(&mut pcid_from_client) { + let response = self.respond(msg, &args); + send(&mut pcid_to_client, &response); + } + } + } +} + +pub struct State { + threads: Mutex>>, + pci: Pci, +} + +fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, dev_num: u8, func_num: u8, header: PciHeader) { + let pci = &state.pci; + let raw_class: u8 = header.class().into(); let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", bus_num, dev_num, func_num, header.vendor_id(), header.device_id(), raw_class, @@ -171,6 +279,22 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, } } + let capabilities = { + let bus = PciBus { + pci, + num: bus_num, + }; + let dev = PciDev { + bus: &bus, + num: dev_num + }; + let func = PciFunc { + dev: &dev, + num: func_num, + }; + crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() + }; + let func = driver_interface::PciFunction { bars, bar_sizes, @@ -181,10 +305,8 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, legacy_interrupt_line: irq, venid: header.vendor_id(), }; - let capabilities = Vec::new(); let subdriver_args = driver_interface::SubdriverArguments { - capabilities, func, }; @@ -239,7 +361,18 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, match command.envs(envs).spawn() { Ok(mut child) => { - handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); + let driver_handler = DriverHandler { + bus_num, + dev_num, + func_num, + config: driver.clone(), + header, + state: Arc::clone(&state), + capabilities, + }; + let thread = thread::spawn(move || { + driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); + }); match child.wait() { Ok(_status) => (), Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err), @@ -250,25 +383,6 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, } } } - fn handle_spawn(pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { - use driver_interface::*; - - // TODO: Instead of relying on the subdriver to correctly close the pipe, there should be a - // dedicated thread responsible for this. Or alternatively, a thread pool with Futures. - - if let (Some(pcid_to_client_fd), Some(pcid_from_client_fd)) = (pcid_to_client_write, pcid_from_client_read) { - let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd as RawFd) }; - let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd as RawFd) }; - - if let Ok(msg) = recv(&mut pcid_from_client) { - match msg { - PcidClientRequest::RequestConfig => { - send(&mut pcid_to_client, &PcidClientResponse::Config(args.clone())).unwrap(); - } - } - } - } - } } fn main() { @@ -301,18 +415,24 @@ fn main() { } } + let state = Arc::new(State { + pci: Pci::new(), + threads: Mutex::new(Vec::new()), + }); + + let pci = &state.pci; + unsafe { iopl(3).unwrap() }; print!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV\n"); - let pci = Pci::new(); 'bus: for bus in pci.buses() { 'dev: for dev in bus.devs() { for func in dev.funcs() { let func_num = func.num; match PciHeader::from_reader(func) { Ok(header) => { - handle_parsed_header(&config, &pci, bus.num, dev.num, func_num, header); + handle_parsed_header(Arc::clone(&state), &config, bus.num, dev.num, func_num, header); } Err(PciHeaderError::NoDevice) => { if func_num == 0 { @@ -332,4 +452,8 @@ fn main() { } } } + + for thread in state.threads.lock().unwrap().drain(..) { + thread.join().unwrap(); + } } diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 7ac6c3a07a..c458174536 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -134,7 +134,7 @@ impl MsiCapability { pub fn message_control(&self) -> u16 { self.message_control_raw() as u16 } - pub unsafe fn set_message_control(&mut self, writer: &mut W, offset: u8, value: u16) { + pub unsafe fn set_message_control(&mut self, writer: &W, offset: u8, value: u16) { let mut new_message_control = self.message_control_raw(); new_message_control &= 0x0000_FFFF; new_message_control |= u32::from(value) << 16; @@ -156,7 +156,7 @@ impl MsiCapability { pub fn enabled(&self) -> bool { self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 } - pub unsafe fn set_enabled(&mut self, writer: &mut W, offset: u8, enabled: bool) { + pub unsafe fn set_enabled(&mut self, writer: &W, offset: u8, enabled: bool) { let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); new_message_control |= u16::from(enabled); self.set_message_control(writer, offset, new_message_control) @@ -192,6 +192,7 @@ impl MsixCapability { pub const fn message_control(&self) -> u16 { (self.a >> 16) as u16 } + pub fn set_message_control(&mut self, message_control: u16) { self.a &= 0x0000_FFFF; self.a |= u32::from(message_control) << 16; @@ -294,6 +295,42 @@ pub enum Capability { } impl Capability { + pub fn as_msi(&self) -> Option<&MsiCapability> { + match self { + &Self::Msi(ref msi) => Some(msi), + _ => None, + } + } + pub fn as_msix(&self) -> Option<&MsixCapability> { + match self { + &Self::MsiX(ref msix) => Some(msix), + _ => None, + } + } + pub fn as_msi_mut(&mut self) -> Option<&mut MsiCapability> { + match self { + &mut Self::Msi(ref mut msi) => Some(msi), + _ => None, + } + } + pub fn as_msix_mut(&mut self) -> Option<&mut MsixCapability> { + match self { + &mut Self::MsiX(ref mut msix) => Some(msix), + _ => None, + } + } + pub fn into_msi(self) -> Option { + match self { + Self::Msi(msi) => Some(msi), + _ => None, + } + } + pub fn into_msix(self) -> Option { + match self { + Self::MsiX(msix) => Some(msix), + _ => None, + } + } unsafe fn parse_msi(reader: &R, offset: u8) -> Self { Self::Msi(MsiCapability::parse(reader, offset)) } @@ -335,10 +372,10 @@ impl<'a, R> Iterator for CapabilitiesIter<'a, R> where R: ConfigReader { - type Item = Capability; + type Item = (u8, Capability); fn next(&mut self) -> Option { let offset = self.inner.next()?; - Some(unsafe { Capability::parse(self.inner.reader, offset) }) + Some((offset, unsafe { Capability::parse(self.inner.reader, offset) })) } } diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index e4197436a9..0d8513bb82 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -27,7 +27,7 @@ bitflags! { } } -#[derive(Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum PciHeader { General { vendor_id: u16, @@ -125,8 +125,6 @@ impl PciHeader { let subsystem_id = LittleEndian::read_u16(&bytes[30..32]); let expansion_rom_bar = LittleEndian::read_u32(&bytes[32..36]); let cap_pointer = bytes[36]; - println!("PCI DEVICE CAPABILITIES: {:?}", crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(cap_pointer, &reader) }.collect::>()); - let interrupt_line = bytes[44]; let interrupt_pin = bytes[45]; let min_grant = bytes[46]; @@ -266,6 +264,11 @@ impl PciHeader { } } + pub fn cap_pointer(&self) -> u8 { + match self { + &PciHeader::General { cap_pointer, .. } | &PciHeader::PciToPci { cap_pointer, .. } => cap_pointer, + } + } } #[cfg(test)] diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 8209e09a45..6e763a89e4 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,3 +1,5 @@ +use std::sync::Mutex; + pub use self::bar::PciBar; pub use self::bus::{PciBus, PciBusIter}; pub use self::class::PciClass; @@ -13,11 +15,15 @@ mod dev; mod func; pub mod header; -pub struct Pci; +pub struct Pci { + lock: Mutex<()>, +} impl Pci { pub fn new() -> Self { - Pci + Self { + lock: Mutex::new(()), + } } pub fn buses<'pci>(&'pci self) -> PciIter<'pci> { @@ -25,7 +31,7 @@ impl Pci { } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { + pub unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); let value: u32; asm!("mov dx, 0xCF8 @@ -37,7 +43,13 @@ impl Pci { } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { + pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { + let _guard = self.lock.lock().unwrap(); + self.read_nolock(bus, dev, func, offset) + } + + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); asm!("mov dx, 0xCF8 out dx, eax" @@ -46,6 +58,11 @@ impl Pci { out dx, eax" : : "{eax}"(value) : "dx" : "intel", "volatile"); } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { + let _guard = self.lock.lock().unwrap(); + self.write_nolock(bus, dev, func, offset, value) + } } pub struct PciIter<'pci> { From fa594155c9c8aedadd5e63be2b06e79ad1352bd9 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 15 Mar 2020 14:05:19 +0100 Subject: [PATCH 03/22] Allow subdrivers to get the capability structs. --- bgad/src/scheme.rs | 1 - pcid/src/driver_interface.rs | 51 +++++- pcid/src/main.rs | 15 +- pcid/src/pci/cap.rs | 209 +------------------------ pcid/src/pci/mod.rs | 1 + pcid/src/pci/msi.rs | 296 +++++++++++++++++++++++++++++++++++ xhcid/src/main.rs | 253 ++++++++++++++++++------------ xhcid/src/xhci/mod.rs | 4 +- xhcid/src/xhci/scheme.rs | 2 +- xhcid/src/xhci/trb.rs | 9 ++ 10 files changed, 533 insertions(+), 308 deletions(-) create mode 100644 pcid/src/pci/msi.rs diff --git a/bgad/src/scheme.rs b/bgad/src/scheme.rs index bad949c717..635d581017 100644 --- a/bgad/src/scheme.rs +++ b/bgad/src/scheme.rs @@ -1,4 +1,3 @@ -use orbclient; use std::fs::File; use std::io::Write; use std::str; diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs index cf5e24336d..47b8e108a2 100644 --- a/pcid/src/driver_interface.rs +++ b/pcid/src/driver_interface.rs @@ -7,7 +7,8 @@ use std::os::unix::io::{FromRawFd, RawFd}; use serde::{Serialize, Deserialize, de::DeserializeOwned}; use thiserror::Error; -use crate::pci; +pub use crate::pci::PciBar; +pub use crate::pci::msi::{MsiCapability, MsixCapability, MsixTableEntry}; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct PciFunction { @@ -18,7 +19,7 @@ pub struct PciFunction { /// Number of PCI function pub func_num: u8, /// PCI Base Address Registers - pub bars: [pci::PciBar; 6], + pub bars: [PciBar; 6], /// BAR sizes pub bar_sizes: [u32; 6], /// Legacy IRQ line @@ -49,6 +50,9 @@ impl FeatureStatus { Self::Disabled } } + pub fn is_enabled(&self) -> bool { + if let &Self::Enabled = self { true } else { false } + } } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] @@ -56,6 +60,19 @@ pub enum PciFeature { Msi, MsiX, } +impl PciFeature { + pub fn is_msi(&self) -> bool { + if let &Self::Msi = self { true } else { false } + } + pub fn is_msix(&self) -> bool { + if let &Self::MsiX = self { true } else { false } + } +} +#[derive(Debug, Serialize, Deserialize)] +pub enum PciFeatureInfo { + Msi(MsiCapability), + MsiX(MsixCapability), +} #[derive(Debug, Error)] pub enum PcidClientHandleError { @@ -83,6 +100,7 @@ pub enum PcidClientRequest { RequestFeatures, EnableFeature(PciFeature), FeatureStatus(PciFeature), + FeatureInfo(PciFeature), } #[derive(Debug, Serialize, Deserialize)] @@ -99,6 +117,7 @@ pub enum PcidClientResponse { FeatureEnabled(PciFeature), FeatureStatus(PciFeature, FeatureStatus), Error(PcidServerResponseError), + FeatureInfo(PciFeature, PciFeatureInfo), } // TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over @@ -158,4 +177,32 @@ impl PcidServerHandle { other => Err(PcidClientHandleError::InvalidResponse(other)), } } + pub fn fetch_all_features(&mut self) -> Result> { + self.send(&PcidClientRequest::RequestFeatures)?; + match self.recv()? { + PcidClientResponse::AllFeatures(a) => Ok(a), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } + pub fn feature_status(&mut self, feature: PciFeature) -> Result { + self.send(&PcidClientRequest::FeatureStatus(feature))?; + match self.recv()? { + PcidClientResponse::FeatureStatus(feat, status) if feat == feature => Ok(status), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } + pub fn enable_feature(&mut self, feature: PciFeature) -> Result<()> { + self.send(&PcidClientRequest::EnableFeature(feature))?; + match self.recv()? { + PcidClientResponse::FeatureEnabled(feat) if feat == feature => Ok(()), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } + pub fn feature_info(&mut self, feature: PciFeature) -> Result { + self.send(&PcidClientRequest::FeatureInfo(feature))?; + match self.recv()? { + PcidClientResponse::FeatureInfo(feat, info) if feat == feature => Ok(info), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 78416db8c3..42f28f29bf 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -105,6 +105,18 @@ impl DriverHandler { None }).unwrap_or(FeatureStatus::Disabled), }), + PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo(feature, match feature { + PciFeature::Msi => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msi()) { + PciFeatureInfo::Msi(*info) + } else { + return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)); + } + PciFeature::MsiX => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msix()) { + PciFeatureInfo::MsiX(*info) + } else { + return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)); + } + }), } } fn handle_spawn(mut self, pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { @@ -116,7 +128,7 @@ impl DriverHandler { while let Ok(msg) = recv(&mut pcid_from_client) { let response = self.respond(msg, &args); - send(&mut pcid_to_client, &response); + send(&mut pcid_to_client, &response).unwrap(); } } } @@ -294,6 +306,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, }; crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() }; + println!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); let func = driver_interface::PciFunction { bars, diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index c458174536..6159dc0f6a 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -1,4 +1,5 @@ -use super::func::{ConfigReader, ConfigWriter}; +use super::func::ConfigReader; +use serde::{Serialize, Deserialize}; pub struct CapabilityOffsetsIter<'a, R> { offset: u8, @@ -42,7 +43,7 @@ pub enum CapabilityId { Pcie = 0x10, } -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum MsiCapability { _32BitAddress { message_control: u32, @@ -72,220 +73,18 @@ pub enum MsiCapability { }, } -impl MsiCapability { - pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; - pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; - - pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E; - pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1; - - pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070; - pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4; - - pub const MC_MSI_ENABLED_BIT: u16 = 1; - - pub unsafe fn parse(reader: &R, offset: u8) -> Self { - let dword = reader.read_u32(offset); - - let message_control = (dword >> 16) as u16; - - if message_control & Self::MC_PVT_CAPABLE_BIT != 0 { - if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { - Self::_64BitAddressWithPvm { - message_control: dword, - message_address_lo: reader.read_u32(offset + 4), - message_address_hi: reader.read_u32(offset + 8), - message_data: reader.read_u32(offset + 12), - mask_bits: reader.read_u32(offset + 16), - pending_bits: reader.read_u32(offset + 20), - } - } else { - Self::_32BitAddressWithPvm { - message_control: dword, - message_address: reader.read_u32(offset + 4), - message_data: reader.read_u32(offset + 8), - mask_bits: reader.read_u32(offset + 12), - pending_bits: reader.read_u32(offset + 16), - } - } - } else { - if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { - Self::_64BitAddress { - message_control: dword, - message_address_lo: reader.read_u32(offset + 4), - message_address_hi: reader.read_u32(offset + 8), - message_data: reader.read_u32(offset + 12), - } - } else { - Self::_32BitAddress { - message_control: dword, - message_address: reader.read_u32(offset + 4), - message_data: reader.read_u32(offset + 8), - } - } - } - } - - fn message_control_raw(&self) -> u32 { - match self { - Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control, - } - } - pub fn message_control(&self) -> u16 { - self.message_control_raw() as u16 - } - pub unsafe fn set_message_control(&mut self, writer: &W, offset: u8, value: u16) { - let mut new_message_control = self.message_control_raw(); - new_message_control &= 0x0000_FFFF; - new_message_control |= u32::from(value) << 16; - writer.write_u32(offset, new_message_control); - - match self { - Self::_32BitAddress { ref mut message_control, .. } - | Self::_64BitAddress { ref mut message_control, .. } - | Self::_32BitAddressWithPvm { ref mut message_control, .. } - | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, - } - } - pub fn is_pvt_capable(&self) -> bool { - self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 - } - pub fn has_64_bit_addr(&self) -> bool { - self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0 - } - pub fn enabled(&self) -> bool { - self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 - } - pub unsafe fn set_enabled(&mut self, writer: &W, offset: u8, enabled: bool) { - let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); - new_message_control |= u16::from(enabled); - self.set_message_control(writer, offset, new_message_control) - } - pub fn multi_message_capable(&self) -> u8 { - ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 - } - pub fn multi_message_enabled(&self) -> u8 { - ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_MASK) as u8 - } -} #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct PcieCapability { } -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct MsixCapability { pub a: u32, pub b: u32, pub c: u32, } -impl MsixCapability { - pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; - pub const MC_MSIX_ENABLED_SHIFT: u8 = 15; - pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; - pub const MC_FUNCTION_MASK_SHIFT: u8 = 14; - pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF; - - /// The Message Control field, containing the enabled and function mask bits, as well as the - /// table size. - pub const fn message_control(&self) -> u16 { - (self.a >> 16) as u16 - } - - pub fn set_message_control(&mut self, message_control: u16) { - self.a &= 0x0000_FFFF; - self.a |= u32::from(message_control) << 16; - } - /// Returns the MSI-X table size, subtracted by one. - pub const fn table_size_raw(&self) -> u16 { - self.message_control() & Self::MC_TABLE_SIZE_MASK - } - /// Returns the MSI-X table size. - pub const fn table_size(&self) -> u16 { - self.table_size_raw() + 1 - } - /// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the - /// MSI capability structure. - pub const fn msix_enabled(&self) -> bool { - self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0 - } - /// The MSI-X function mask, which overrides each of the vectors' mask bit, when set. - pub const fn function_mask(&self) -> bool { - self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0 - } - - pub fn set_msix_enabled(&mut self, enabled: bool) { - let mut new_message_control = self.message_control(); - new_message_control &= !(Self::MC_MSIX_ENABLED_BIT); - new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT; - self.set_message_control(new_message_control); - } - - pub fn set_function_mask(&mut self, function_mask: bool) { - let mut new_message_control = self.message_control(); - new_message_control &= !(Self::MC_FUNCTION_MASK_BIT); - new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT; - self.set_message_control(new_message_control); - } - pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8; - pub const TABLE_BIR_MASK: u32 = 0x0000_0007; - - /// The table offset is guaranteed to be QWORD aligned (8 bytes). - pub const fn table_offset(&self) -> u32 { - self.b & Self::TABLE_OFFSET_MASK - } - /// The table BIR, which is used to map the offset to a memory location. - pub const fn table_bir(&self) -> u8 { - (self.b & Self::TABLE_BIR_MASK) as u8 - } - - pub fn set_table_offset(&mut self, offset: u32) { - assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned"); - self.b &= !Self::TABLE_OFFSET_MASK; - self.b |= offset; - } - pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8; - pub const PBA_BIR_MASK: u32 = 0x0000_0007; - - /// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes). - pub const fn pba_offset(&self) -> u32 { - self.b & Self::PBA_OFFSET_MASK - } - /// The Pending Bit Array BIR, which is used to map the offset to a memory location. - pub const fn pba_bir(&self) -> u8 { - (self.b & Self::PBA_BIR_MASK) as u8 - } - - pub fn set_pba_offset(&mut self, offset: u32) { - assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned"); - self.c &= !Self::PBA_OFFSET_MASK; - self.c |= offset; - } - - /// Write the first DWORD into configuration space (containing the partially modifiable Message - /// Control field). - pub unsafe fn write_a(&self, writer: &W, offset: u8) { - writer.write_u32(offset, self.a) - } - /// Write the second DWORD into configuration space (containing the modifiable table - /// offset and the readonly table BIR). - pub unsafe fn write_b(&self, writer: &W, offset: u8) { - writer.write_u32(offset + 4, self.a) - } - /// Write the third DWORD into configuration space (containing the modifiable pending bit array - /// offset, and the readonly PBA BIR). - pub unsafe fn write_c(&self, writer: &W, offset: u8) { - writer.write_u32(offset + 8, self.a) - } - /// Write this capability structure back to configuration space. - pub unsafe fn write_all(&self, writer: &W, offset: u8) { - self.write_a(writer, offset); - self.write_b(writer, offset); - self.write_c(writer, offset); - } -} - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum Capability { Msi(MsiCapability), diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 6e763a89e4..b3395517eb 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -14,6 +14,7 @@ mod class; mod dev; mod func; pub mod header; +pub mod msi; pub struct Pci { lock: Mutex<()>, diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs new file mode 100644 index 0000000000..2a662f6737 --- /dev/null +++ b/pcid/src/pci/msi.rs @@ -0,0 +1,296 @@ +use std::fmt; + +use super::bar::PciBar; +pub use super::cap::{MsiCapability, MsixCapability}; +use super::func::{ConfigReader, ConfigWriter}; + +use syscall::{Io, Mmio}; + +impl MsiCapability { + pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; + pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; + + pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E; + pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1; + + pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070; + pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4; + + pub const MC_MSI_ENABLED_BIT: u16 = 1; + + pub unsafe fn parse(reader: &R, offset: u8) -> Self { + let dword = reader.read_u32(offset); + + let message_control = (dword >> 16) as u16; + + if message_control & Self::MC_PVT_CAPABLE_BIT != 0 { + if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { + Self::_64BitAddressWithPvm { + message_control: dword, + message_address_lo: reader.read_u32(offset + 4), + message_address_hi: reader.read_u32(offset + 8), + message_data: reader.read_u32(offset + 12), + mask_bits: reader.read_u32(offset + 16), + pending_bits: reader.read_u32(offset + 20), + } + } else { + Self::_32BitAddressWithPvm { + message_control: dword, + message_address: reader.read_u32(offset + 4), + message_data: reader.read_u32(offset + 8), + mask_bits: reader.read_u32(offset + 12), + pending_bits: reader.read_u32(offset + 16), + } + } + } else { + if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { + Self::_64BitAddress { + message_control: dword, + message_address_lo: reader.read_u32(offset + 4), + message_address_hi: reader.read_u32(offset + 8), + message_data: reader.read_u32(offset + 12), + } + } else { + Self::_32BitAddress { + message_control: dword, + message_address: reader.read_u32(offset + 4), + message_data: reader.read_u32(offset + 8), + } + } + } + } + + fn message_control_raw(&self) -> u32 { + match self { + Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control, + } + } + pub fn message_control(&self) -> u16 { + (self.message_control_raw() >> 16) as u16 + } + pub unsafe fn set_message_control(&mut self, writer: &W, offset: u8, value: u16) { + let mut new_message_control = self.message_control_raw(); + new_message_control &= 0x0000_FFFF; + new_message_control |= u32::from(value) << 16; + writer.write_u32(offset, new_message_control); + + match self { + Self::_32BitAddress { ref mut message_control, .. } + | Self::_64BitAddress { ref mut message_control, .. } + | Self::_32BitAddressWithPvm { ref mut message_control, .. } + | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, + } + } + pub fn is_pvt_capable(&self) -> bool { + self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 + } + pub fn has_64_bit_addr(&self) -> bool { + self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0 + } + pub fn enabled(&self) -> bool { + self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 + } + pub unsafe fn set_enabled(&mut self, writer: &W, offset: u8, enabled: bool) { + let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); + new_message_control |= u16::from(enabled); + self.set_message_control(writer, offset, new_message_control) + } + pub fn multi_message_capable(&self) -> u8 { + ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 + } + pub fn multi_message_enabled(&self) -> u8 { + ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8 + } +} + +impl MsixCapability { + pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; + pub const MC_MSIX_ENABLED_SHIFT: u8 = 15; + pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; + pub const MC_FUNCTION_MASK_SHIFT: u8 = 14; + pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF; + + /// The Message Control field, containing the enabled and function mask bits, as well as the + /// table size. + pub const fn message_control(&self) -> u16 { + (self.a >> 16) as u16 + } + + pub fn set_message_control(&mut self, message_control: u16) { + self.a &= 0x0000_FFFF; + self.a |= u32::from(message_control) << 16; + } + /// Returns the MSI-X table size, subtracted by one. + pub const fn table_size_raw(&self) -> u16 { + self.message_control() & Self::MC_TABLE_SIZE_MASK + } + /// Returns the MSI-X table size. + pub const fn table_size(&self) -> u16 { + self.table_size_raw() + 1 + } + /// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the + /// MSI capability structure. + pub const fn msix_enabled(&self) -> bool { + self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0 + } + /// The MSI-X function mask, which overrides each of the vectors' mask bit, when set. + pub const fn function_mask(&self) -> bool { + self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0 + } + + pub fn set_msix_enabled(&mut self, enabled: bool) { + let mut new_message_control = self.message_control(); + new_message_control &= !(Self::MC_MSIX_ENABLED_BIT); + new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT; + self.set_message_control(new_message_control); + } + + pub fn set_function_mask(&mut self, function_mask: bool) { + let mut new_message_control = self.message_control(); + new_message_control &= !(Self::MC_FUNCTION_MASK_BIT); + new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT; + self.set_message_control(new_message_control); + } + pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8; + pub const TABLE_BIR_MASK: u32 = 0x0000_0007; + + /// The table offset is guaranteed to be QWORD aligned (8 bytes). + pub const fn table_offset(&self) -> u32 { + self.b & Self::TABLE_OFFSET_MASK + } + /// The table BIR, which is used to map the offset to a memory location. + pub const fn table_bir(&self) -> u8 { + (self.b & Self::TABLE_BIR_MASK) as u8 + } + + pub fn set_table_offset(&mut self, offset: u32) { + assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned"); + self.b &= !Self::TABLE_OFFSET_MASK; + self.b |= offset; + } + pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8; + pub const PBA_BIR_MASK: u32 = 0x0000_0007; + + /// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes). + pub const fn pba_offset(&self) -> u32 { + self.c & Self::PBA_OFFSET_MASK + } + /// The Pending Bit Array BIR, which is used to map the offset to a memory location. + pub const fn pba_bir(&self) -> u8 { + (self.c & Self::PBA_BIR_MASK) as u8 + } + + pub fn set_pba_offset(&mut self, offset: u32) { + assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned"); + self.c &= !Self::PBA_OFFSET_MASK; + self.c |= offset; + } + + pub fn table_base_pointer(&self, bars: [PciBar; 6]) -> usize { + if self.table_bir() > 5 { + panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir()); + } + let base = bars[usize::from(self.table_bir())]; + + if let PciBar::Memory(ptr) = base { + ptr as usize + self.table_offset() as usize + } else { + panic!("MSI-X Table BIR referenced a non-memory BAR: {:?}", base); + } + } + pub fn table_pointer(&self, bars: [PciBar; 6], k: u16) -> usize { + self.table_base_pointer(bars) + k as usize * 16 + } + + pub fn pba_base_pointer(&self, bars: [PciBar; 6]) -> usize { + if self.pba_bir() > 5 { + panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir()); + } + let base = bars[usize::from(self.pba_bir())]; + + if let PciBar::Memory(ptr) = base { + ptr as usize + self.pba_offset() as usize + } else { + panic!("MSI-X PBA BIR referenced a non-memory BAR: {:?}", base); + } + } + pub fn pba_pointer_dword(&self, bars: [PciBar; 6], k: u16) -> usize { + self.pba_base_pointer(bars) + (k as usize / 32) * 4 + } + pub const fn pba_bit_dword(&self, k: u16) -> u8 { + (k % 32) as u8 + } + + pub fn pba_pointer_qword(&self, bars: [PciBar; 6], k: u16) -> usize { + self.pba_base_pointer(bars) + (k as usize / 64) * 8 + } + pub const fn pba_bit_qword(&self, k: u16) -> u8 { + (k % 64) as u8 + } + + /// Write the first DWORD into configuration space (containing the partially modifiable Message + /// Control field). + pub unsafe fn write_a(&self, writer: &W, offset: u8) { + writer.write_u32(offset, self.a) + } + /// Write the second DWORD into configuration space (containing the modifiable table + /// offset and the readonly table BIR). + pub unsafe fn write_b(&self, writer: &W, offset: u8) { + writer.write_u32(offset + 4, self.a) + } + /// Write the third DWORD into configuration space (containing the modifiable pending bit array + /// offset, and the readonly PBA BIR). + pub unsafe fn write_c(&self, writer: &W, offset: u8) { + writer.write_u32(offset + 8, self.a) + } + /// Write this capability structure back to configuration space. + pub unsafe fn write_all(&self, writer: &W, offset: u8) { + self.write_a(writer, offset); + self.write_b(writer, offset); + self.write_c(writer, offset); + } +} + +#[repr(packed)] +pub struct MsixTableEntry { + pub addr_lo: Mmio, + pub addr_hi: Mmio, + pub msg_data: Mmio, + pub vec_ctl: Mmio, +} + +impl MsixTableEntry { + pub fn addr_lo(&self) -> u32 { + self.addr_lo.read() + } + pub fn addr_hi(&self) -> u32 { + self.addr_hi.read() + } + pub fn msg_data(&self) -> u32 { + self.msg_data.read() + } + pub fn vec_ctl(&self) -> u32 { + self.vec_ctl.read() + } + pub fn addr(&self) -> u64 { + u64::from(self.addr_lo()) | (u64::from(self.addr_hi()) << 32) + } + pub const VEC_CTL_MASK_BIT: u32 = 1; + + pub fn mask(&mut self) { + self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, true) + } + pub fn unmask(&mut self) { + self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, false) + } +} + +impl fmt::Debug for MsixTableEntry { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("MsixTableEntry") + .field("addr", &self.addr()) + .field("msg_data", &self.msg_data()) + .field("vec_ctl", &self.vec_ctl()) + .finish() + } +} diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 0de08d86e9..87a09d7d36 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -4,6 +4,9 @@ extern crate event; extern crate plain; extern crate syscall; +use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; +use pcid_interface::MsixTableEntry; + use event::{Event, EventQueue}; use std::cell::RefCell; use std::fs::File; @@ -23,127 +26,185 @@ mod usb; mod xhci; fn main() { - println!("xhcid started"); - let mut pcid_handle = pcid_interface::PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); - dbg!(); - println!("XHCI from PCI config: {:?}", pcid_handle.fetch_config().expect("xhcid: failed to fetch config")); + let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); + let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); + println!("XHCI PCI CONFIG: {:?}", pci_config); - // Close the pipe, allowing pcid to continue. - drop(pcid_handle); + let bar = pci_config.func.bars[0]; + let irq = pci_config.func.legacy_interrupt_line; + let bar_ptr = match bar { + pcid_interface::PciBar::Memory(ptr) => ptr, + other => panic!("Expected memory bar, found {}", other), + }; + + let address = unsafe { + syscall::physmap(bar_ptr as usize, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("xhcid: failed to map address") + }; + + let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); + println!("XHCI PCI FEATURES: {:?}", all_pci_features); + + let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + + dbg!(has_msi, msi_enabled); + dbg!(has_msix, msix_enabled); + + if has_msi && !msi_enabled { + pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); + msi_enabled = true; + println!("Enabled MSI"); + } + if has_msi && msi_enabled && has_msix && !msix_enabled { + pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); + msix_enabled = true; + println!("Enabled MSI-X"); + } + + if msi_enabled && !msix_enabled { + todo!("only msi-x is currently implemented") + } + if msix_enabled { + let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { + PciFeatureInfo::Msi(_) => panic!(), + PciFeatureInfo::MsiX(s) => s, + }; + let table_size = capability.table_size(); + let table_base = capability.table_base_pointer(pci_config.func.bars); + let table_min_length = table_size * 16; + let pba_min_length = crate::xhci::scheme::div_round_up(table_size, 8); + + let pba_base = capability.pba_base_pointer(pci_config.func.bars); + dbg!(table_size, table_base, table_min_length, pba_base); + + if !(bar_ptr..bar_ptr + 65536).contains(&(table_base as u32 + table_min_length as u32)) { + todo!() + } + if !(bar_ptr..bar_ptr + 65536).contains(&(pba_base as u32 + pba_min_length as u32)) { + todo!() + } + + let virt_table_base = ((table_base - bar_ptr as usize) + address) as *const MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *const u64; + + for k in 0..table_size { + assert_eq!(std::mem::size_of::(), 16); + let table_entry_pointer = unsafe { virt_table_base.offset(k as isize).as_ref().unwrap() }; + let pba_pointer = unsafe { virt_pba_base.offset(k as isize / 64).as_ref().unwrap() }; + let pba_bit = k % 64; + + dbg!(table_entry_pointer, (*pba_pointer >> pba_bit) & 1); + } + } + + std::thread::sleep(std::time::Duration::from_millis(300)); + + // Daemonize + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { + return; + } let mut args = env::args().skip(1); let mut name = args.next().expect("xhcid: no name provided"); name.push_str("_xhci"); - let bar_str = args.next().expect("xhcid: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("xhcid: failed to parse address"); - - let irq_str = args.next().expect("xhcid: no IRQ provided"); - let irq = irq_str.parse::().expect("xhcid: failed to parse irq"); - print!( "{}", - format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq) + format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq) ); - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { - let socket_fd = syscall::open( - format!(":usb/{}", name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("xhcid: failed to create usb scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); + let socket_fd = syscall::open( + format!(":usb/{}", name), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + ) + .expect("xhcid: failed to create usb scheme"); + let socket = Arc::new(RefCell::new(unsafe { + File::from_raw_fd(socket_fd as RawFd) + })); - let mut irq_file = - File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); + let mut irq_file = + File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); - let address = unsafe { - syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("xhcid: failed to map address") - }; - { - let hci = Arc::new(RefCell::new( - Xhci::new(name, address).expect("xhcid: failed to allocate device"), - )); + { + let hci = Arc::new(RefCell::new( + Xhci::new(name, address).expect("xhcid: failed to allocate device"), + )); - hci.borrow_mut().probe().expect("xhcid: failed to probe"); + hci.borrow_mut().probe().expect("xhcid: failed to probe"); - let mut event_queue = - EventQueue::<()>::new().expect("xhcid: failed to create event queue"); + let mut event_queue = + EventQueue::<()>::new().expect("xhcid: failed to create event queue"); - syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); + syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + let todo = Arc::new(RefCell::new(Vec::::new())); - let hci_irq = hci.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add(irq_file.as_raw_fd(), move |_| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + let hci_irq = hci.clone(); + let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + event_queue + .add(irq_file.as_raw_fd(), move |_| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; - if hci_irq.borrow_mut().trigger_irq() { - irq_file.write(&mut irq)?; + if hci_irq.borrow_mut().trigger_irq() { + irq_file.write(&mut irq)?; - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - hci_irq.borrow_mut().handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket_irq.borrow_mut().write(&mut todo[i])?; - todo.remove(i); - } - } - } - - Ok(None) - }) - .expect("xhcid: failed to catch events on IRQ file"); - - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd, move |_| -> Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => break, - Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, - Ok(_) => (), - Err(err) => return Err(err), - } - - let a = packet.a; - hci.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + hci_irq.borrow_mut().handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; } else { - socket_packet.borrow_mut().write(&mut packet)?; + socket_irq.borrow_mut().write(&mut todo[i])?; + todo.remove(i); } } - Ok(None) - }) - .expect("xhcid: failed to catch events on scheme file"); + } - event_queue - .trigger_all(Event { fd: 0, flags: 0 }) - .expect("xhcid: failed to trigger events"); + Ok(None) + }) + .expect("xhcid: failed to catch events on IRQ file"); - event_queue.run().expect("xhcid: failed to handle events"); - } - unsafe { - let _ = syscall::physunmap(address); - } + let socket_fd = socket.borrow().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue + .add(socket_fd, move |_| -> Result> { + loop { + let mut packet = Packet::default(); + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => break, + Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, + Ok(_) => (), + Err(err) => return Err(err), + } + + let a = packet.a; + hci.borrow_mut().handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket_packet.borrow_mut().write(&mut packet)?; + } + } + Ok(None) + }) + .expect("xhcid: failed to catch events on scheme file"); + + event_queue + .trigger_all(Event { fd: 0, flags: 0 }) + .expect("xhcid: failed to trigger events"); + + event_queue.run().expect("xhcid: failed to handle events"); + } + unsafe { + let _ = syscall::physunmap(address); } } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index ed4a0e29e8..530bb30fad 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -21,7 +21,7 @@ mod operational; mod port; mod ring; mod runtime; -mod scheme; +pub mod scheme; mod trb; use self::capability::CapabilityRegs; @@ -306,7 +306,7 @@ impl Xhci { Ok(cloned_event_trb.event_slot()) } pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> { - self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?; + self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.disable_slot(0, cycle))?; Ok(()) } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index e26b032810..20d8e81c9c 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -2003,7 +2003,7 @@ impl Xhci { } } use std::ops::{Add, Div, Rem}; -fn div_round_up(a: T, b: T) -> T +pub fn div_round_up(a: T, b: T) -> T where T: Add + Div + Rem + PartialEq + From + Copy, { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index d6d4cb30e0..4ad02bee37 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -203,6 +203,15 @@ impl Trb { | (cycle as u32), ); } + pub fn disable_slot(&mut self, slot: u8, cycle: bool) { + self.set( + 0, + 0, + (u32::from(slot) << 24) + | ((TrbType::DisableSlot as u32) << 10) + | u32::from(cycle) + ); + } pub fn address_device(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) { assert_eq!( From cb5a72fbc100cca943f7995b96311f835f019b6f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 20 Mar 2020 18:50:39 +0100 Subject: [PATCH 04/22] Successfully recognize (only one) MSI-X IRQ. Somehow it only happens once though. --- Cargo.lock | 2 +- pcid/Cargo.toml | 2 +- pcid/src/driver_interface.rs | 6 +- pcid/src/pci/msi.rs | 48 +++++++++++++ xhcid/src/main.rs | 126 +++++++++++++++++++++++++++-------- xhcid/src/xhci/command.rs | 3 +- xhcid/src/xhci/executor.rs | 1 + xhcid/src/xhci/mod.rs | 76 +++++++++++++++++---- 8 files changed, 218 insertions(+), 46 deletions(-) create mode 100644 xhcid/src/xhci/executor.rs diff --git a/Cargo.lock b/Cargo.lock index e0a97cc6da..43d3e114a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -697,7 +697,7 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 189aed0338..966d0ebff2 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -16,7 +16,7 @@ bincode = "1.2" bitflags = "1" byteorder = "1.2" libc = "0.2" -redox_syscall = "0.1" +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "1" diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs index 47b8e108a2..e2f5b68d8c 100644 --- a/pcid/src/driver_interface.rs +++ b/pcid/src/driver_interface.rs @@ -8,7 +8,7 @@ use serde::{Serialize, Deserialize, de::DeserializeOwned}; use thiserror::Error; pub use crate::pci::PciBar; -pub use crate::pci::msi::{MsiCapability, MsixCapability, MsixTableEntry}; +pub use crate::pci::msi; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct PciFunction { @@ -70,8 +70,8 @@ impl PciFeature { } #[derive(Debug, Serialize, Deserialize)] pub enum PciFeatureInfo { - Msi(MsiCapability), - MsiX(MsixCapability), + Msi(msi::MsiCapability), + MsiX(msi::MsixCapability), } #[derive(Debug, Error)] diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 2a662f6737..da993840ec 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -259,6 +259,54 @@ pub struct MsixTableEntry { pub vec_ctl: Mmio, } +#[cfg(target_arch = "x86_64")] +pub mod x86_64 { + #[repr(u8)] + pub enum TriggerMode { + Level = 0, + Edge = 1, + } + + #[repr(u8)] + pub enum LevelTriggerMode { + Deassert = 0, + Assert = 1, + } + + #[repr(u8)] + pub enum DeliveryMode { + Fixed = 0b000, + LowestPriority = 0b001, + Smi = 0b010, + // 0b011 is reserved + Nmi = 0b100, + Init = 0b101, + // 0b110 is reserved + ExtInit = 0b111, + } + + // TODO: should the reserved field be preserved? + pub const fn message_address(destination_id: u8, rh: bool, dm: bool, xx: u8) -> u32 { + 0xFEE0_0000u32 + | ((destination_id as u32) << 12) + | ((rh as u32) << 3) + | ((dm as u32) << 2) + | xx as u32 + } + pub const fn message_data(trigger_mode: TriggerMode, level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 { + ((trigger_mode as u32) << 15) + | ((level_trigger_mode as u32) << 14) + | ((delivery_mode as u32) << 8) + | vector as u32 + } + pub const fn message_data_level_triggered(level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 { + message_data(TriggerMode::Level, level_trigger_mode, delivery_mode, vector) + } + pub const fn message_data_edge_triggered(delivery_mode: DeliveryMode, vector: u8) -> u32 { + message_data(TriggerMode::Edge, LevelTriggerMode::Deassert, delivery_mode, vector) + } +} + impl MsixTableEntry { pub fn addr_lo(&self) -> u32 { self.addr_lo.read() diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 87a09d7d36..e8c29b2848 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -5,19 +5,22 @@ extern crate plain; extern crate syscall; use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; -use pcid_interface::MsixTableEntry; +use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; use event::{Event, EventQueue}; use std::cell::RefCell; -use std::fs::File; -use std::io::{Read, Result, Write}; +use std::convert::TryInto; +use std::fs::{self, File}; +use std::io::{self, Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::ptr::NonNull; use std::sync::Arc; -use std::{env, io}; +use std::env; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::scheme::SchemeMut; +use syscall::io::Io; use crate::xhci::Xhci; @@ -25,7 +28,55 @@ mod driver_interface; mod usb; mod xhci; +/// Read the local APIC id of the bootstrap processor. +fn read_bsp_apic_id() -> io::Result { + let mut buffer = [0u8; 8]; + + let mut file = File::open("irq:bsp")?; + let bytes_read = file.read(&mut buffer)?; + + Ok(if bytes_read == 8 { + u64::from_le_bytes(buffer) as u32 + } else if bytes_read == 4 { + u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]) + } else { + panic!("`irq:` scheme responded with {} bytes, expected {}", bytes_read, std::mem::size_of::()); + }) +} +/// Allocate an interrupt vector, located at the BSP's IDT. +fn allocate_interrupt_vector() -> io::Result> { + let available_irqs = fs::read_dir("irq:")?; + + for entry in available_irqs { + let entry = entry?; + let path = entry.path(); + + let file_name = match path.file_name() { + Some(f) => f, + None => continue, + }; + + let path_str = match file_name.to_str() { + Some(s) => s, + None => continue, + }; + + if let Ok(irq_number) = path_str.parse::() { + // if found, reserve the irq + let irq_handle = File::create(format!("irq:{}", irq_number))?; + let interrupt_vector = irq_number + 32; + return Ok(Some((interrupt_vector, irq_handle))); + } + } + Ok(None) +} + fn main() { + // Daemonize + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { + return; + } + let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); println!("XHCI PCI CONFIG: {:?}", pci_config); @@ -63,10 +114,9 @@ fn main() { println!("Enabled MSI-X"); } - if msi_enabled && !msix_enabled { + let (mut irq_file, msix_info) = if msi_enabled && !msix_enabled { todo!("only msi-x is currently implemented") - } - if msix_enabled { + } else if msix_enabled { let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, @@ -86,26 +136,49 @@ fn main() { todo!() } - let virt_table_base = ((table_base - bar_ptr as usize) + address) as *const MsixTableEntry; - let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *const u64; + let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; + + let mut info = xhci::MsixInfo { + virt_table_base: NonNull::new(virt_table_base).unwrap(), + virt_pba_base: NonNull::new(virt_pba_base).unwrap(), + capability, + }; + + // Allocate one msi vector. + + { + use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; + + // primary interrupter + let k = 0; - for k in 0..table_size { assert_eq!(std::mem::size_of::(), 16); - let table_entry_pointer = unsafe { virt_table_base.offset(k as isize).as_ref().unwrap() }; - let pba_pointer = unsafe { virt_pba_base.offset(k as isize / 64).as_ref().unwrap() }; - let pba_bit = k % 64; + let table_entry_pointer = info.table_entry_pointer(k); - dbg!(table_entry_pointer, (*pba_pointer >> pba_bit) & 1); + let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); + let rh = false; + let dm = false; + let addr = x86_64_msix::message_address(destination_id.try_into().expect("xhcid: BSP apic id couldn't fit u8"), rh, dm, 0b00); + + let (vector, interrupt_handle) = allocate_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + dbg!(vector, destination_id); + + table_entry_pointer.addr_lo.write(addr); + table_entry_pointer.addr_hi.write(0); + table_entry_pointer.msg_data.write(msg_data); + table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + + (interrupt_handle, Some(info)) } - } + } else { + (File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file"), None) + }; std::thread::sleep(std::time::Duration::from_millis(300)); - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { - return; - } - let mut args = env::args().skip(1); let mut name = args.next().expect("xhcid: no name provided"); @@ -125,12 +198,9 @@ fn main() { File::from_raw_fd(socket_fd as RawFd) })); - let mut irq_file = - File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); - { let hci = Arc::new(RefCell::new( - Xhci::new(name, address).expect("xhcid: failed to allocate device"), + Xhci::new(name, address, msi_enabled, msix_enabled, msix_info).expect("xhcid: failed to allocate device"), )); hci.borrow_mut().probe().expect("xhcid: failed to probe"); @@ -146,11 +216,13 @@ fn main() { let socket_irq = socket.clone(); let todo_irq = todo.clone(); event_queue - .add(irq_file.as_raw_fd(), move |_| -> Result> { + .add(irq_file.as_raw_fd(), move |_| -> io::Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; - if hci_irq.borrow_mut().trigger_irq() { + if hci_irq.borrow_mut().received_irq() { + hci_irq.borrow_mut().on_irq(); + irq_file.write(&mut irq)?; let mut todo = todo_irq.borrow_mut(); @@ -175,7 +247,7 @@ fn main() { let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); event_queue - .add(socket_fd, move |_| -> Result> { + .add(socket_fd, move |_| -> io::Result> { loop { let mut packet = Packet::default(); match socket_packet.borrow_mut().read(&mut packet) { diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs index ca78d592fe..c82dc4311e 100644 --- a/xhcid/src/xhci/command.rs +++ b/xhcid/src/xhci/command.rs @@ -22,7 +22,8 @@ impl CommandRing { } pub fn erdp(&self) -> u64 { - self.events.ring.register() + let address = self.events.ring.register(); + address & 0xFFFF_FFFF_FFFF_FFF0 } pub fn erstba(&self) -> u64 { diff --git a/xhcid/src/xhci/executor.rs b/xhcid/src/xhci/executor.rs new file mode 100644 index 0000000000..01fe6603d8 --- /dev/null +++ b/xhcid/src/xhci/executor.rs @@ -0,0 +1 @@ +use super::Xhci; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 530bb30fad..47df7db0a8 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -11,11 +11,14 @@ use syscall::io::{Dma, Io}; use crate::usb; +use pcid_interface::msi::{MsixTableEntry, MsixCapability}; + mod capability; mod command; mod context; mod doorbell; mod event; +pub mod executor; mod extended; mod operational; mod port; @@ -39,6 +42,33 @@ use self::scheme::EndpIfState; use crate::driver_interface::*; +pub struct MsixInfo { + pub virt_table_base: NonNull, + pub virt_pba_base: NonNull, + pub capability: MsixCapability, +} +impl MsixInfo { + pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { + &mut *self.virt_table_base.as_ptr().offset(k as isize) + } + pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { + assert!(k < self.capability.table_size() as usize); + unsafe { self.table_entry_pointer_unchecked(k) } + } + pub unsafe fn pba_pointer_unchecked(&mut self, k: usize) -> &mut u64 { + &mut *self.virt_pba_base.as_ptr().offset(k as isize) + } + pub fn pba_pointer(&mut self, k: usize) -> &mut u64 { + assert!(k < self.capability.table_size() as usize); + unsafe { self.pba_pointer_unchecked(k) } + } + pub fn pba(&mut self, k: usize) -> bool { + let byte = k / 64; + let bit = k % 64; + *self.pba_pointer(byte) & (1 << bit) != 0 + } +} + struct Device<'a> { ring: &'a mut Ring, cmd: &'a mut CommandRing, @@ -139,6 +169,10 @@ pub struct Xhci { drivers: BTreeMap, scheme_name: String, + + msi: bool, + msix: bool, + msix_info: Option, } struct PortState { @@ -167,7 +201,7 @@ impl EndpointState { } impl Xhci { - pub fn new(scheme_name: String, address: usize) -> Result { + pub fn new(scheme_name: String, address: usize, msi: bool, msix: bool, msix_info: Option) -> Result { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); @@ -239,6 +273,9 @@ impl Xhci { }), drivers: BTreeMap::new(), scheme_name, + msi, + msix, + msix_info, }; xhci.init(max_slots); @@ -277,7 +314,11 @@ impl Xhci { println!(" - Write ERSTBA: {:X}", erstba); self.run.ints[0].erstba.write(erstba as u64); + println!(" - Write IMODC and IMODI: {} and {}", 0, 0); + self.run.ints[0].imod.write(0); + println!(" - Enable interrupts"); + self.run.ints[0].iman.writef(1, true); // clear interrupt pending if set earlier by the BIOS self.run.ints[0].iman.writef(1 << 1, true); } @@ -506,25 +547,34 @@ impl Xhci { } - pub fn trigger_irq(&mut self) -> bool { - // Read the Interrupter Pending bit. - if self.run.ints[0].iman.readf(1) { - //println!("XHCI Interrupt"); - - // If set, set it back to zero, so that new interrupts can be triggered. - // FIXME: MSI and MSI-X systems + /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always + /// true when using MSI/MSI-X. + pub fn received_irq(&mut self) -> bool { + if self.msi || self.msix { + // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit + // doesn't have to be touched. + println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", self.run.ints[0].iman.readf(1), self.run.ints[0].erdp.readf(3)); + println!("MSI-X PB={}", self.msix_info.as_ref().unwrap().pba(0)); + true + } else if self.run.ints[0].iman.readf(1) { + // If MSI and/or MSI-X are not used, the interrupt has to be shared, and thus there is + // a special register to specify whether the IRQ actually came from the xHC. self.run.ints[0].iman.writef(1, true); - // Wake all futures awaiting the IRQ. - for waker in self.irq_state.wakers.lock().unwrap().drain(..) { - waker.wake(); - } - + // The interrupt came from the xHC. true } else { + // The interrupt came from a different device. false } } + /// Handle an IRQ event. + pub fn on_irq(&mut self) { + // Wake all futures awaiting the IRQ. + for waker in self.irq_state.wakers.lock().unwrap().drain(..) { + waker.wake(); + } + } pub(crate) fn irq(&self) -> IrqFuture { IrqFuture { state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)), From cfc4d65d4882be57b745e430299bbdf19c578990 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 22 Mar 2020 15:34:14 +0100 Subject: [PATCH 05/22] THE INTERRUPTS ARE GETTING GENERATED! --- pcid/src/pci/msi.rs | 4 ++-- xhcid/src/main.rs | 8 ++------ xhcid/src/xhci/mod.rs | 41 +++++++++++++++++++++++++++++++++------- xhcid/src/xhci/scheme.rs | 16 ++++++++++------ 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index da993840ec..8b420501aa 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -263,8 +263,8 @@ pub struct MsixTableEntry { pub mod x86_64 { #[repr(u8)] pub enum TriggerMode { - Level = 0, - Edge = 1, + Edge = 0, + Level = 1, } #[repr(u8)] diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index e8c29b2848..a415b5cc24 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -104,14 +104,10 @@ fn main() { dbg!(has_msix, msix_enabled); if has_msi && !msi_enabled { - pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); msi_enabled = true; - println!("Enabled MSI"); } - if has_msi && msi_enabled && has_msix && !msix_enabled { - pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); + if has_msix && !msix_enabled { msix_enabled = true; - println!("Enabled MSI-X"); } let (mut irq_file, msix_info) = if msi_enabled && !msix_enabled { @@ -200,7 +196,7 @@ fn main() { { let hci = Arc::new(RefCell::new( - Xhci::new(name, address, msi_enabled, msix_enabled, msix_info).expect("xhcid: failed to allocate device"), + Xhci::new(name, address, msi_enabled, msix_enabled, msix_info, pcid_handle).expect("xhcid: failed to allocate device"), )); hci.borrow_mut().probe().expect("xhcid: failed to probe"); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 47df7db0a8..813ec2728b 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -12,6 +12,7 @@ use syscall::io::{Dma, Io}; use crate::usb; use pcid_interface::msi::{MsixTableEntry, MsixCapability}; +use pcid_interface::{PcidServerHandle, PciFeature}; mod capability; mod command; @@ -108,7 +109,7 @@ impl<'a> Device<'a> { } } - self.int.erdp.write(self.cmd.erdp()); + self.int.erdp.write(self.cmd.erdp() | (1 << 3)); } fn get_device(&mut self) -> Result { @@ -173,6 +174,8 @@ pub struct Xhci { msi: bool, msix: bool, msix_info: Option, + + pcid_handle: PcidServerHandle, } struct PortState { @@ -201,7 +204,7 @@ impl EndpointState { } impl Xhci { - pub fn new(scheme_name: String, address: usize, msi: bool, msix: bool, msix_info: Option) -> Result { + pub fn new(scheme_name: String, address: usize, msi: bool, msix: bool, msix_info: Option, handle: PcidServerHandle) -> Result { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); @@ -276,6 +279,7 @@ impl Xhci { msi, msix, msix_info, + pcid_handle: handle, }; xhci.init(max_slots); @@ -302,13 +306,29 @@ impl Xhci { // Set event ring segment table registers println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); { + self.run.ints[0].iman.writef(1, true); // clear interrupt pending if set earlier by the BIOS + + println!("IP={}", self.run.ints[0].iman.readf(1)); + + /*if self.msi { + self.pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); + println!("Enabled MSI"); + }*/ + if self.msix { + self.pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); + println!("Enabled MSI-X"); + } + + dbg!(self.pcid_handle.feature_info(PciFeature::MsiX).unwrap()); + dbg!(self.pcid_handle.feature_info(PciFeature::Msi).unwrap()); + let erstz = 1; println!(" - Write ERSTZ: {}", erstz); self.run.ints[0].erstsz.write(erstz); let erdp = self.cmd.erdp(); println!(" - Write ERDP: {:X}", erdp); - self.run.ints[0].erdp.write(erdp as u64); + self.run.ints[0].erdp.write(erdp as u64 | (1 << 3)); let erstba = self.cmd.erstba(); println!(" - Write ERSTBA: {:X}", erstba); @@ -318,13 +338,14 @@ impl Xhci { self.run.ints[0].imod.write(0); println!(" - Enable interrupts"); - self.run.ints[0].iman.writef(1, true); // clear interrupt pending if set earlier by the BIOS self.run.ints[0].iman.writef(1 << 1, true); + } + self.op.usb_cmd.writef(1 << 2, true); // Set run/stop to 1 println!(" - Start"); - self.op.usb_cmd.writef(1 | 1 << 2, true); + self.op.usb_cmd.writef(1, true); // Wait until controller is running println!(" - Wait for running"); @@ -332,6 +353,8 @@ impl Xhci { println!(" - Waiting for XHCI running"); } + println!("IP={}", self.run.ints[0].iman.readf(1)); + // Ring command doorbell println!(" - Ring doorbell"); self.dbs[0].write(0); @@ -356,6 +379,7 @@ impl Xhci { } pub fn probe(&mut self) -> Result<()> { + println!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); for i in 0..self.ports.len() { let (data, state, speed, flags) = { let port = &self.ports[i]; @@ -554,10 +578,12 @@ impl Xhci { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", self.run.ints[0].iman.readf(1), self.run.ints[0].erdp.readf(3)); - println!("MSI-X PB={}", self.msix_info.as_ref().unwrap().pba(0)); + println!("MSI-X PB={}", self.msix_info.as_mut().unwrap().pba(0)); + let entry = self.msix_info.as_mut().unwrap().table_entry_pointer(0); + println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); true } else if self.run.ints[0].iman.readf(1) { - // If MSI and/or MSI-X are not used, the interrupt has to be shared, and thus there is + // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is // a special register to specify whether the IRQ actually came from the xHC. self.run.ints[0].iman.writef(1, true); @@ -567,6 +593,7 @@ impl Xhci { // The interrupt came from a different device. false } + } /// Handle an IRQ event. pub fn on_irq(&mut self) { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 20d8e81c9c..1abfc8b056 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -216,16 +216,20 @@ impl Xhci { cmd_name: &str, f: F, ) -> Result { - self.run.ints[0].erdp.write(self.cmd.erdp()); + self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); let (cmd, cycle, event) = self.cmd.next(); f(cmd, cycle); + println!("INTE={}", self.op.usb_cmd.readf(1 << 2)); + println!("IP={}", self.run.ints[0].iman.readf(1)); self.dbs[0].write(0); + println!("IP={}", self.run.ints[0].iman.readf(1)); - while event.data.read() == 0 { + while event.data.read() == 0/* || self.run.ints[0].iman.readf(1)*/ { println!(" - {} Waiting for event", cmd_name); } + println!("IP={}", self.run.ints[0].iman.readf(1)); if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::CommandCompletion as u8 @@ -239,7 +243,7 @@ impl Xhci { cmd.reserved(false); event.reserved(false); - self.run.ints[0].erdp.write(self.cmd.erdp()); + self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); Ok(ret) } pub fn execute_control_transfer( @@ -299,7 +303,7 @@ impl Xhci { event.clone() }; - self.run.ints[0].erdp.write(self.cmd.erdp()); + self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); Ok(cloned_trb) } @@ -385,7 +389,7 @@ impl Xhci { cloned_trb }; - self.run.ints[0].erdp.write(self.cmd.erdp()); + self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); Ok(cloned_trb) } @@ -995,7 +999,7 @@ impl Xhci { // TODO: Should the descriptors be stored in PortState? - run.ints[0].erdp.write(cmd.erdp()); + run.ints[0].erdp.write(cmd.erdp() | (1 << 3)); let mut dev = Device { ring, From 443b160b6d67dd67d8fd36c9c34fc5d12a3631e8 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 26 Mar 2020 18:18:00 +0100 Subject: [PATCH 06/22] Add internal locking to the Xhci struct. --- Cargo.lock | 172 +++++++++++++++ pcid/src/driver_interface.rs | 23 +- pcid/src/main.rs | 23 +- pcid/src/pci/msi.rs | 15 +- xhcid/Cargo.toml | 3 + xhcid/src/main.rs | 141 +++++++----- xhcid/src/xhci/capability.rs | 20 ++ xhcid/src/xhci/command.rs | 46 ---- xhcid/src/xhci/context.rs | 44 +++- xhcid/src/xhci/event.rs | 7 + xhcid/src/xhci/executor.rs | 1 - xhcid/src/xhci/irq_reactor.rs | 395 ++++++++++++++++++++++++++++++++++ xhcid/src/xhci/mod.rs | 279 ++++++++++++------------ xhcid/src/xhci/ring.rs | 53 ++++- xhcid/src/xhci/scheme.rs | 383 ++++++++++++++++---------------- xhcid/src/xhci/trb.rs | 71 +++++- 16 files changed, 1221 insertions(+), 455 deletions(-) delete mode 100644 xhcid/src/xhci/command.rs delete mode 100644 xhcid/src/xhci/executor.rs create mode 100644 xhcid/src/xhci/irq_reactor.rs diff --git a/Cargo.lock b/Cargo.lock index 43d3e114a3..2eeb19c3db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,6 +141,15 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chashmap" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "clap" version = "2.33.0" @@ -259,6 +268,88 @@ name = "futures" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "futures" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-channel" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-executor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-io" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-sink" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-task" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-util" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gpt" version = "0.6.3" @@ -419,6 +510,11 @@ name = "maybe-uninit" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memoffset" version = "0.5.3" @@ -627,6 +723,14 @@ dependencies = [ "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "owning_ref" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "owning_ref" version = "0.4.0" @@ -635,6 +739,15 @@ dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot" version = "0.7.1" @@ -644,6 +757,17 @@ dependencies = [ "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot_core" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot_core" version = "0.4.0" @@ -716,11 +840,26 @@ name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "plain" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro-hack" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro-nested" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proc-macro2" version = "1.0.8" @@ -747,6 +886,18 @@ dependencies = [ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.6.5" @@ -1527,6 +1678,9 @@ name = "xhcid" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "pcid 0.1.0", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1558,6 +1712,7 @@ dependencies = [ "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff41a3c2c1e39921b9003de14bf0439c7b63a9039637c291e1a64925d8ddfa45" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" @@ -1571,6 +1726,15 @@ dependencies = [ "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" +"checksum futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" +"checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" +"checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" +"checksum futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" +"checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" +"checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" +"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" +"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" +"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" "checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" "checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" @@ -1589,6 +1753,7 @@ dependencies = [ "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" @@ -1607,16 +1772,23 @@ dependencies = [ "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" +"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" +"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" "checksum pbr 1.0.2 (git+https://github.com/a8m/pb)" = "" "checksum pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4403eb718d70c03ee279e51737782902c68cca01e870a33b6a2f9dfb50b9cd83" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +"checksum proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420" +"checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" "checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs index e2f5b68d8c..28c06ef02a 100644 --- a/pcid/src/driver_interface.rs +++ b/pcid/src/driver_interface.rs @@ -10,21 +10,42 @@ use thiserror::Error; pub use crate::pci::PciBar; pub use crate::pci::msi; +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[repr(u8)] +pub enum LegacyInterruptPin { + /// INTa# + IntA = 1, + /// INTb# + IntB = 2, + /// INTc# + IntC = 3, + /// INTd# + IntD = 4, +} + #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct PciFunction { /// Number of PCI bus pub bus_num: u8, + /// Number of PCI device pub dev_num: u8, + /// Number of PCI function pub func_num: u8, + /// PCI Base Address Registers pub bars: [PciBar; 6], + /// BAR sizes pub bar_sizes: [u32; 6], + /// Legacy IRQ line - // TODO: Stop using legacy IRQ lines, and physical pins, but MSI/MSI-X instead. pub legacy_interrupt_line: u8, + + /// Legacy interrupt pin (INTx#), none if INTx# interrupts aren't supported at all. + pub legacy_interrupt_pin: Option, + /// Vendor ID pub venid: u16, /// Device ID diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 42f28f29bf..63637cb50b 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -75,7 +75,10 @@ impl DriverHandler { None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), }; unsafe { - with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| capability.set_enabled(func, offset, true)); + with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| { + capability.set_enabled(true); + capability.write_message_control(func, offset); + }); } PcidClientResponse::FeatureEnabled(feature) } @@ -255,6 +258,8 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, pci.write(bus_num, dev_num, func_num, 0x3C, data); } + let interrupt_pin = unsafe { pci.read(bus_num, dev_num, func_num, 0x3B) }; + // Find BAR sizes let mut bars = [PciBar::None; 6]; let mut bar_sizes = [0; 6]; @@ -308,6 +313,21 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, }; println!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); + use driver_interface::LegacyInterruptPin; + + let legacy_interrupt_pin = match interrupt_pin { + 0 => None, + 1 => Some(LegacyInterruptPin::IntA), + 2 => Some(LegacyInterruptPin::IntB), + 3 => Some(LegacyInterruptPin::IntC), + 4 => Some(LegacyInterruptPin::IntD), + + other => { + println!("pcid: invalid interrupt pin: {}", other); + None + } + }; + let func = driver_interface::PciFunction { bars, bar_sizes, @@ -316,6 +336,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, func_num, devid: header.device_id(), legacy_interrupt_line: irq, + legacy_interrupt_pin, venid: header.vendor_id(), }; diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 8b420501aa..d4400257f4 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -68,11 +68,10 @@ impl MsiCapability { pub fn message_control(&self) -> u16 { (self.message_control_raw() >> 16) as u16 } - pub unsafe fn set_message_control(&mut self, writer: &W, offset: u8, value: u16) { + pub fn set_message_control(&mut self, value: u16) { let mut new_message_control = self.message_control_raw(); new_message_control &= 0x0000_FFFF; new_message_control |= u32::from(value) << 16; - writer.write_u32(offset, new_message_control); match self { Self::_32BitAddress { ref mut message_control, .. } @@ -81,6 +80,9 @@ impl MsiCapability { | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, } } + pub unsafe fn write_message_control(&mut self, writer: &W, offset: u8) { + writer.write_u32(offset, self.message_control_raw()); + } pub fn is_pvt_capable(&self) -> bool { self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 } @@ -90,10 +92,10 @@ impl MsiCapability { pub fn enabled(&self) -> bool { self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 } - pub unsafe fn set_enabled(&mut self, writer: &W, offset: u8, enabled: bool) { + pub fn set_enabled(&mut self, enabled: bool) { let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); new_message_control |= u16::from(enabled); - self.set_message_control(writer, offset, new_message_control) + self.set_message_control(new_message_control); } pub fn multi_message_capable(&self) -> u8 { ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 @@ -101,6 +103,11 @@ impl MsiCapability { pub fn multi_message_enabled(&self) -> u8 { ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8 } + pub fn set_multi_message_enabled(&mut self, log_mme: u8) { + let mut new_message_control = self.message_control() & (!Self::MC_MULTI_MESSAGE_ENABLE_MASK); + new_message_control |= (u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT); + self.set_message_control(new_message_control); + } } impl MsixCapability { diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 0ef92d5fd7..e46a79a13b 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -13,6 +13,9 @@ path = "src/lib.rs" [dependencies] bitflags = "1" +chashmap = "2.2.2" +crossbeam-channel = "0.4" +futures = "0.3" plain = "0.2" lazy_static = "1.4" spin = "0.4" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index a415b5cc24..1a3e35e03b 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -8,13 +8,14 @@ use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; use event::{Event, EventQueue}; -use std::cell::RefCell; use std::convert::TryInto; use std::fs::{self, File}; +use std::future::Future; use std::io::{self, Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::pin::Pin; use std::ptr::NonNull; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::env; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; @@ -22,7 +23,7 @@ use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::scheme::SchemeMut; use syscall::io::Io; -use crate::xhci::Xhci; +use crate::xhci::{InterruptMethod, Xhci}; mod driver_interface; mod usb; @@ -71,6 +72,10 @@ fn allocate_interrupt_vector() -> io::Result> { Ok(None) } +async fn handle_packet(hci: Arc, packet: Packet) -> Packet { + todo!() +} + fn main() { // Daemonize if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { @@ -103,15 +108,26 @@ fn main() { dbg!(has_msi, msi_enabled); dbg!(has_msix, msix_enabled); - if has_msi && !msi_enabled { + if has_msi && !msi_enabled && !has_msix { + pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); + println!("Enabled MSI"); msi_enabled = true; } if has_msix && !msix_enabled { + pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); + println!("Enabled MSI-X"); msix_enabled = true; } - let (mut irq_file, msix_info) = if msi_enabled && !msix_enabled { - todo!("only msi-x is currently implemented") + let (mut irq_file, interrupt_method) = if msi_enabled && !msix_enabled { + let mut capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI capability structure from pcid") { + PciFeatureInfo::Msi(s) => s, + PciFeatureInfo::MsiX(_) => panic!(), + }; + // use one vector + capability.set_multi_message_enabled(0); + + todo!("msi (msix is implemented though)") } else if msix_enabled { let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), @@ -160,17 +176,19 @@ fn main() { let (vector, interrupt_handle) = allocate_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); - dbg!(vector, destination_id); - table_entry_pointer.addr_lo.write(addr); table_entry_pointer.addr_hi.write(0); table_entry_pointer.msg_data.write(msg_data); table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - (interrupt_handle, Some(info)) + (Some(interrupt_handle), InterruptMethod::MsiX(info)) } + } else if pci_config.func.legacy_interrupt_pin.is_some() { + // legacy INTx# interrupt pins. + (Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx) } else { - (File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file"), None) + // no interrupts at all + (None, InterruptMethod::Polling) }; std::thread::sleep(std::time::Duration::from_millis(300)); @@ -187,27 +205,25 @@ fn main() { let socket_fd = syscall::open( format!(":usb/{}", name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + syscall::O_RDWR | syscall::O_CREAT, ) .expect("xhcid: failed to create usb scheme"); - let socket = Arc::new(RefCell::new(unsafe { + let socket = Arc::new(Mutex::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); - { - let hci = Arc::new(RefCell::new( - Xhci::new(name, address, msi_enabled, msix_enabled, msix_info, pcid_handle).expect("xhcid: failed to allocate device"), - )); + let hci = Arc::new(Xhci::new(name, address, interrupt_method, irq_file.as_mut(), pcid_handle).expect("xhcid: failed to allocate device")); + hci.probe().expect("xhcid: failed to probe"); - hci.borrow_mut().probe().expect("xhcid: failed to probe"); + let mut event_queue = + EventQueue::<()>::new().expect("xhcid: failed to create event queue"); - let mut event_queue = - EventQueue::<()>::new().expect("xhcid: failed to create event queue"); + syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); - syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); - - let todo = Arc::new(RefCell::new(Vec::::new())); + let todo = Arc::new(Mutex::new(Vec::::new())); + let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); + if let Some(irq_file) = irq_file { let hci_irq = hci.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); @@ -216,21 +232,24 @@ fn main() { let mut irq = [0; 8]; irq_file.read(&mut irq)?; - if hci_irq.borrow_mut().received_irq() { - hci_irq.borrow_mut().on_irq(); + let hci = hci_irq.lock().unwrap(); + let socket = socket_irq.lock().unwrap(); + let todo = todo_irq.lock().unwrap(); + + if hci.received_irq() { + hci.on_irq(); irq_file.write(&mut irq)?; - let mut todo = todo_irq.borrow_mut(); let mut i = 0; while i < todo.len() { let a = todo[i].a; - hci_irq.borrow_mut().handle(&mut todo[i]); + hci.handle(&mut todo[i]); if todo[i].a == (-EWOULDBLOCK) as usize { todo[i].a = a; i += 1; } else { - socket_irq.borrow_mut().write(&mut todo[i])?; + socket.write(&todo[i])?; todo.remove(i); } } @@ -239,39 +258,43 @@ fn main() { Ok(None) }) .expect("xhcid: failed to catch events on IRQ file"); - - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd, move |_| -> io::Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => break, - Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, - Ok(_) => (), - Err(err) => return Err(err), - } - - let a = packet.a; - hci.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket_packet.borrow_mut().write(&mut packet)?; - } - } - Ok(None) - }) - .expect("xhcid: failed to catch events on scheme file"); - - event_queue - .trigger_all(Event { fd: 0, flags: 0 }) - .expect("xhcid: failed to trigger events"); - - event_queue.run().expect("xhcid: failed to handle events"); } + + let socket_fd = socket.lock().unwrap().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue + .add(socket_fd, move |_| -> io::Result> { + let mut socket = socket_packet.lock().unwrap(); + let mut hci = hci.lock().unwrap(); + let mut todo = todo.lock().unwrap(); + + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => break, + Ok(_) => (), + Err(err) => return Err(err), + } + + let a = packet.a; + hci.handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.push(packet); + } else { + socket.write(&packet)?; + } + } + Ok(None) + }) + .expect("xhcid: failed to catch events on scheme file"); + + event_queue + .trigger_all(Event { fd: 0, flags: 0 }) + .expect("xhcid: failed to trigger events"); + + event_queue.run().expect("xhcid: failed to handle events"); + unsafe { let _ = syscall::physunmap(address); } diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 59e841b24e..98750bc12c 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -27,6 +27,13 @@ pub const HCS_PARAMS1_MAX_PORTS_SHIFT: u8 = 24; pub const HCS_PARAMS1_MAX_SLOTS_MASK: u32 = 0x0000_00FF; pub const HCS_PARAMS1_MAX_SLOTS_SHIFT: u8 = 0; +pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK: u32 = 0xF800_0000; +pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT: u8 = 27; +pub const HCS_PARAMS2_SPR_BIT: u32 = 1 << HCS_PARAMS2_SPR_SHIFT; +pub const HCS_PARAMS2_SPR_SHIFT: u8 = 26; +pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK: u32 = 0x03E0_0000; +pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT: u8 = 21; + impl CapabilityRegs { pub fn lec(&self) -> bool { self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT) @@ -48,4 +55,17 @@ impl CapabilityRegs { pub fn ext_caps_ptr_in_dwords(&self) -> u16 { ((self.hcc_params1.read() & HCC_PARAMS1_XECP_MASK) >> HCC_PARAMS1_XECP_SHIFT) as u16 } + pub fn max_scratchpad_bufs_lo(&self) -> u8 { + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) + } + pub fn spr(&self) -> bool { + self.hcs_params2.readf(HCS_PARAMS2_SPR_BIT) + } + pub fn max_scratchpad_bufs_hi(&self) -> u8 { + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) + } + pub fn max_scratchpad_bufs(&self) -> u16 { + u16::from(self.max_scratchpad_bufs_lo()) + | (u16::from(self.max_scratchpad_bufs_hi()) << 5) + } } diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs deleted file mode 100644 index c82dc4311e..0000000000 --- a/xhcid/src/xhci/command.rs +++ /dev/null @@ -1,46 +0,0 @@ -use syscall::error::Result; - -use super::event::EventRing; -use super::ring::Ring; -use super::trb::Trb; - -pub struct CommandRing { - pub ring: Ring, - pub events: EventRing, -} - -impl CommandRing { - pub fn new() -> Result { - Ok(CommandRing { - ring: Ring::new(16, true)?, - events: EventRing::new()?, - }) - } - - pub fn crcr(&self) -> u64 { - self.ring.register() - } - - pub fn erdp(&self) -> u64 { - let address = self.events.ring.register(); - address & 0xFFFF_FFFF_FFFF_FFF0 - } - - pub fn erstba(&self) -> u64 { - self.events.ste.physical() as u64 - } - - pub fn next(&mut self) -> (&mut Trb, bool, &mut Trb) { - let cmd = self.ring.next(); - let event = self.events.next(); - (cmd.0, cmd.1, event) - } - - pub fn next_cmd(&mut self) -> (&mut Trb, bool) { - self.ring.next() - } - - pub fn next_event(&mut self) -> &mut Trb { - self.events.next() - } -} diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 74944da174..f3eb970737 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -75,7 +75,7 @@ impl InputContext { pub struct DeviceContextList { pub dcbaa: Dma<[u64; 256]>, - pub contexts: Vec>, + pub contexts: Box<[Dma]>, } impl DeviceContextList { @@ -91,8 +91,8 @@ impl DeviceContextList { } Ok(DeviceContextList { - dcbaa: dcbaa, - contexts: contexts, + dcbaa, + contexts: contexts.into_boxed_slice(), }) } @@ -159,3 +159,41 @@ impl StreamContextArray { self.contexts.physical() as u64 } } + +#[repr(packed)] +#[derive(Clone, Debug)] +pub struct ScratchpadBufferEntry { + pub value: Mmio, +} +impl ScratchpadBufferEntry { + pub fn set_addr(&mut self, addr: u64) { + self.value.write(addr); + } +} + +pub struct ScratchpadBufferArray { + pub entries: Dma<[ScratchpadBufferEntry]>, + pub pages: Vec, +} +impl ScratchpadBufferArray { + pub fn new(entries: u16) -> Result { + let mut entries = unsafe { Dma::zeroed_unsized(entries as usize)? }; + + let pages = entries.iter_mut().map(|entry| { + // TODO: When a better memory allocation API arrives (like the `mem:` scheme which I think is + // being worked on), no assumptions about the page size always being 4k will have to be + // made. + let pointer = syscall::physalloc(4096); + assert_eq!(pointer & 0xFFFF_FFFF_FFFF_F000, pointer, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); + entry.set_addr(pointer); + }); + + Ok(Self { + entries, + pages, + }) + } + pub fn register(&self) -> u64 { + self.entries.physical() + } +} diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index b8301b34be..b3e0af0e35 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -12,6 +12,7 @@ pub struct EventRingSte { _rsvd2: Mmio, } +// TODO: Use atomic operations, and perhaps an occasional lock for reallocating. pub struct EventRing { pub ste: Dma<[EventRingSte]>, pub ring: Ring, @@ -33,4 +34,10 @@ impl EventRing { pub fn next(&mut self) -> &mut Trb { self.ring.next().0 } + pub fn erdp(&self) -> u64 { + self.ring.register() & 0xFFFF_FFFF_FFFF_FFF0 + } + pub fn erstba(&self) -> u64 { + self.ste.physical() as u64 + } } diff --git a/xhcid/src/xhci/executor.rs b/xhcid/src/xhci/executor.rs deleted file mode 100644 index 01fe6603d8..0000000000 --- a/xhcid/src/xhci/executor.rs +++ /dev/null @@ -1 +0,0 @@ -use super::Xhci; diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs new file mode 100644 index 0000000000..a8b777f37a --- /dev/null +++ b/xhcid/src/xhci/irq_reactor.rs @@ -0,0 +1,395 @@ +use std::collections::BTreeMap; +use std::fs::File; +use std::future::Future; +use std::pin::Pin; +use std::sync::{Arc, Mutex}; +use std::sync::atomic::{self, AtomicUsize}; +use std::{mem, task, thread}; + +use crossbeam_channel::{Sender, Receiver}; +use futures::Stream; + +use super::Xhci; +use super::ring::Ring; +use super::trb::{Trb, TrbCompletionCode, TrbType}; + +/// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back +/// by the future unless it completed). +pub struct State { + waker: task::Waker, + kind: StateKind, + message: Arc>>, + is_isoch_or_vf: bool, +} + +pub struct NextEventTrb { + pub event_trb: Trb, + pub src_trb: Option, +} + +// TODO: Perhaps all of the transfer rings used by the xHC should be stored linearly, and then +// indexed using this struct instead. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct RingId { + pub slot: u8, + pub endpoint_num: u8, + pub stream_id: u16, +} + +/// The state specific to a TRB-type. Since some of the event TDs may asynchronously appear, for +/// example the Command Completion Event and the Transfer Event TDs, they have to be +/// distinguishable. Luckily, the xHC also gives us the actual (physical) pointer to the source +/// TRB, from the command ring, unless the event TD has one the completion codes Ring Underrun, +/// Ring Overrun, or VF Event Ring Full Error. When these errors are encountered, it simply +/// indicates that the commands causing the errors continue to be pending, and thus no information +/// is lost. +#[derive(Clone, Copy, Debug)] +pub enum StateKind { + CommandCompletion { phys_ptr: u64 }, + Transfer { phys_ptr: u64, ring_id: RingId }, + Other(TrbType), +} + +impl StateKind { + pub fn trb_type(&self) -> TrbType { + match self.kind { + Self::CommandCompletion { .. } => TrbType::CommandCompletion, + Self::Transfer { .. } => TrbType::Transfer, + Self::Other(ty) => ty, + } + } +} + + +pub struct IrqReactor { + hci: Arc, + current_count: Arc, + irq_file: Option, + receiver: Receiver, + + states: Vec, + + // TODO: Since the IRQ reactor is the only part of this driver that gets event TRBs, perhaps + // the event ring should be owned here? +} + +pub type NewPendingTrb = State; + +pub fn start_irq_reactor(hci: Arc, irq_file: Option) -> thread::JoinHandle<()> { + thread::spawn(move || { + IrqReactor::new(hci, irq_file).run() + }) +} + +impl IrqReactor { + pub fn new(hci: Arc, irq_file: Option) -> Self { + Self { + hci, + irq_file, + current_count: Arc::new(AtomicUsize::new()), + } + } + // TODO: Configure the amount of time to be awaited when no more work can be done. + fn pause(&self) { + std::thread::yield_now(); + } + fn run_polling(mut self) { + loop { + self.handle_requests(); + + let index = self.hci.primary_event_ring.lock().unwrap().next_index(); + + let mut trb; + + 'busy_waiting: loop { + trb = self.hci.primary_event_ring.lock().unwrap().trbs[index]; + + if trb.completion_code() == TrbCompletionCode::Invalid as u8 { + self.pause(); + continue 'busy_waiting; + } + } + self.acknowledge(trb); + self.update_erdp(); + } + } + fn run_with_irq_file(mut self) { + 'event_loop: loop { + self.handle_requests(); + + let irq_file = self.irq_file.as_mut().unwrap(); + + let mut buffer = [0u8; 8]; + let bytes_read = self.irq_file.read(&mut buffer).expect("Failed to read from irq scheme"); + if bytes_read < mem::size_of::() { + panic!("wrong number of bytes read from `irq:`: expected {}, got {}", mem::size_of::(), bytes_read); + } + + if !self.hci.received_irq() { + continue; + } + + let _ = self.irq_file.write(&buffer); + + // TODO: More event rings, probably even with different IRQs. + + let event_ring = self.hci.primary_event_ring.lock().unwrap(); + let trb = event_ring.next(); + + if trb.completion_code() == TrbCompletionCode::Invalid as u8 { + println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt."); + continue 'event_loop; + } + + self.acknowledge(*trb); + trb.reserved(false); + + self.update_erdp(); + } + } + fn update_erdp(&self) { + let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().register(); + let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; + assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); + + self.xhci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); + } + fn handle_requests(&mut self) { + self.states.extend(self.receiver.try_iter()); + } + fn acknowledge(&mut self, trb: Trb) { + let mut index = 0; + + loop { + match self.states[index].kind { + StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => if trb.completion_trb_pointer() == Some(phys_ptr) { + let state = self.states.remove(index).unwrap(); + + // Before waking, it's crucial that the command TRB that generated this event + // be fetched before removing this event TRB from the queue. + let command_trb = match self.hci.command_ring.lock().unwrap().ring.phys_addr_to_entry_mut(phys_ptr) { + Some(command_trb) => { + let t = command_trb.clone(); + command_trb.reserved(false); + t + }, + None => { + println!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb); + continue; + } + }; + + // TODO: Validate the command TRB. + *state.message.lock().unwrap() = Some(NextEventTrb { + src_trb: command_trb.clone(), + event_trb: trb, + }); + + state.waker.wake(); + } else if trb.completion_trb_pointer().is_none() { + println!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); + continue; + } else { + // The event TRB simply didn't match the current future + continue; + } + + StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = self.xhc.lock().unwrap().get_transfer_trb(trb.transfer_event_trb_pointer(), ring_id) { + if trb.transfer_event_trb_pointer() == Some(phys_ptr) { + // Give the source transfer TRB together with the event TRB, to the future. + + let state = self.states.remove(index).unwrap(); + *state.message.lock().unwrap() = Some(NextEventTrb { + src_trb, + event_trb: trb, + }); + state.waker.wake(); + } else if trb.transfer_event_trb_pointer().is_none() { + // Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full. + // + // These errors are caused when either an isoch transfer that shall write data, doesn't + // have any data since the ring is empty, or if an isoch receive is impossible due to a + // full ring. The Virtual Function Event Ring Full is only for Virtual Machine + // Managers, and since this isn't implemented yet, they are irrelevant. + // + // The best solution here is to differentiate between isoch transfers (and + // virtual function event rings when virtualization gets implemented), with + // regular commands and transfers, and send the error TRB to all of them, or + // possibly an error code wrapped in a Result. + self.acknowledge_failed_transfer_trbs(trb); + return; + } else { + // The event TRB simply didn't match the current future + continue; + } + } else { continue } + + StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => { + let state = self.states.remove(index).unwrap(); + state.waker.wake(); + } + + _ => { + index += 1; + if index >= self.states.len() { + break; + } + continue; + } + } + } + } + pub fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { + let mut index = 0; + + loop { + if ! self.states[index].is_isoch_or_vf { + index += 1; + if index >= self.states.len() { + break; + } + continue; + } + let state = self.states.remove(index).unwrap(); + *state.message.lock().unwrap() = Some(NextEventTrb { + event_trb: trb, + src_trb: None, + }); + state.waker.wake(); + } + } + pub fn run(mut self) { + if self.irq_file.is_some() { + self.run_with_irq_file(); + } else { + self.run_polling(); + } + } +} + +struct FutureState { + message: Arc>>, + is_isoch_or_vf: bool, + state_kind: StateKind, +} + +enum EventTrbFuture { + Pending { state: FutureState, sender: Sender, }, + Finished, +} + +impl Future for EventTrbFuture { + type Output = NextEventTrb; + + fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { + match self.get_mut() { + &mut Self::Pending { ref mut state, ref mut sender } => if let Some(message) = state.message.lock().unwrap().take() { + *self.get_mut() = Self::Finished; + + task::Poll::Ready(message) + } else { + sender.send(State { + message: Arc::clone(&state.message), + is_isoch_or_vf: state.is_isoch_or_vf, + state_kind: state.state_kind, + waker: context.waker().clone(), + }).expect("IRQ reactor thread unexpectedly stopped"); + + task::Poll::Pending + } + &mut Self::Finished => panic!("Polling finished EventTrbFuture again."), + } + } +} + +impl Xhci { + pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option { + self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)) + } + pub fn with_ring T>(&self, id: RingId, function: F) -> T { + use super::RingOrStreams; + + let slot_state = self.slot_states.get(&id.slot)?; + let endpoint_state = slot_state.endpoint_states.get(&id.endpoint_num)?; + + let ring_ref = match endpoint_state.transfer { + RingOrStreams::Ring(ref ring) => ring, + RingOrStreams::Streams(ref ctx_arr) => ctx_arr.rings.get(&id.stream_id)?, + }; + + function(ring_ref) + } + pub fn with_ring_mut T>(&self, id: RingId, function: F) -> T { + use super::RingOrStreams; + + let slot_state = self.slot_states.get(&id.slot)?; + let endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; + + let ring_ref = match endpoint_state.transfer { + RingOrStreams::Ring(ref mut ring) => ring, + RingOrStreams::Streams(ref mut ctx_arr) => ctx_arr.rings.get_mut(&id.stream_id)?, + }; + + function(ring_ref) + } + pub fn next_transfer_event_trb(&self, ring_id: RingId, trb: &Trb) -> impl Future + Send + Sync + 'static { + if ! trb.is_transfer_trb() { + panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", trb.trb_type(), trb) + } + + let is_isoch_or_vf = trb.trb_type() == TrbType::Isoch as u8; + + EventTrbFuture::Pending { + state: FutureState { + is_isoch_or_vf, + state_kind: StateKind::Transfer { + ring_id, + phys_ptr: self.with_ring(ring_id, |ring| ring.trb_phys_ptr(trb)/*.expect("Invalid TRB: transfer TRB wasn't in the ring specified. Only direct references to the TRBs of a ring can be used (ring address range: {:p}-{:p}).", ring.start_addr(), ring.end_addr())*/), + }, + message: Arc::new(Mutex::new(None)), + }, + sender: self.irq_reactor_sender.clone(), + } + } + pub fn next_command_completion_event_trb(&self, trb: &Trb) -> impl Future + Send + Sync + 'static { + if ! trb.is_command_trb() { + panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) + } + + let command_ring = self.cmd.lock().unwrap(); + let ring = &command_ring.ring; + + EventTrbFuture::Pending { + state: FutureState { + // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). + is_isoch_or_vf: false, + state_kind: StateKind::CommandCompletion { + phys_ptr: ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb) + }, + message: Arc::new(Mutex::new(None)), + }, + sender: self.irq_reactor_sender.clone(), + } + } + pub fn next_misc_event_trb(&self, trb_type: TrbType) -> impl Future + Send + Sync + 'static { + let valid_trb_types = [ + TrbType::PortStatusChange as u8, + TrbType::BandwidthRequest as u8, + TrbType::Doorbell as u8, + TrbType::HostController as u8, + TrbType::DeviceNotification as u8, + TrbType::MfindexWrap as u8, + ]; + if ! valid_trb_types.contains(&trb_type) { + panic!("Invalid TRB type given to next_misc_event_trb(): {:?}. Only event TRB types that are neither transfer events or command completion events can be used.", trb_type) + } + EventTrbFuture::Pending { + state: FutureState { + is_isoch_or_vf: false, + state_kind: StateKind::Other(trb_type), + message: Arc::new(Mutex::new(None)), + }, + sender: self.irq_reactor_sender.clone(), + } + } +} diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 813ec2728b..3970677053 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,10 +1,14 @@ use std::collections::BTreeMap; use std::convert::TryFrom; +use std::fs::File; +use std::future::Future; use std::pin::Pin; use std::ptr::NonNull; use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak}; -use std::{mem, process, slice, sync::atomic, task}; +use std::{mem, process, slice, sync::atomic, task, thread}; +use chashmap::CHashMap; +use crossbeam_channel::Sender; use serde::Deserialize; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT}; use syscall::io::{Dma, Io}; @@ -15,12 +19,11 @@ use pcid_interface::msi::{MsixTableEntry, MsixCapability}; use pcid_interface::{PcidServerHandle, PciFeature}; mod capability; -mod command; mod context; mod doorbell; mod event; -pub mod executor; mod extended; +pub mod irq_reactor; mod operational; mod port; mod ring; @@ -29,9 +32,10 @@ pub mod scheme; mod trb; use self::capability::CapabilityRegs; -use self::command::CommandRing; -use self::context::{DeviceContextList, InputContext, StreamContextArray}; +use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray}; use self::doorbell::Doorbell; +use self::irq_reactor::NewPendingTrb; +use self::event::EventRing; use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; use self::operational::OperationalRegs; use self::port::Port; @@ -43,6 +47,20 @@ use self::scheme::EndpIfState; use crate::driver_interface::*; +pub enum InterruptMethod { + /// No interrupts whatsoever; the driver will instead rely on polling event rings. + Polling, + + /// Legacy PCI INTx# interrupt pin. + Intx, + + /// Message signaled interrupts. + Msi, + + /// Extended message signaled interrupts. + MsiX(Mutex), +} + pub struct MsixInfo { pub virt_table_base: NonNull, pub virt_pba_base: NonNull, @@ -72,7 +90,7 @@ impl MsixInfo { struct Device<'a> { ring: &'a mut Ring, - cmd: &'a mut CommandRing, + cmd: &'a mut Ring, db: &'a mut Doorbell, int: &'a mut Interrupter, } @@ -104,6 +122,7 @@ impl<'a> Device<'a> { { let event = self.cmd.next_event(); + // TODO: Replace polling here as well. while event.data.read() == 0 { println!(" - Waiting for event"); } @@ -144,43 +163,43 @@ impl<'a> Device<'a> { } pub struct Xhci { - cap: &'static mut CapabilityRegs, - op: &'static mut OperationalRegs, - ports: &'static mut [Port], - dbs: &'static mut [Doorbell], - run: &'static mut RuntimeRegs, - dev_ctx: DeviceContextList, - cmd: CommandRing, + // immutable + cap: &'static CapabilityRegs, + // XXX: It would be really useful to be able to mutably access individual elements of a slice, + // without having to wrap every element in a lock (which wouldn't work since they're packed). + op: Mutex<&'static mut OperationalRegs>, + ports: Mutex<&'static mut [Port]>, + dbs: Mutex<&'static mut [Doorbell]>, + run: Mutex<&'static mut RuntimeRegs>, + cmd: Mutex, + primary_event_ring: Mutex, + + // immutable + dev_ctx: DeviceContextList, + scratchpad_buf_arr: Option, + + // used for the extended capabilities, and so far none of them are mutated, and thus no lock. base: *const u8, - handles: BTreeMap, + handles: CHashMap, next_handle: usize, - port_states: BTreeMap, + port_states: CHashMap, - // TODO: Is this the correct implementation? I mean, there will be a really limited number of - // IRQs, if not just one, and since we probably wont use a thread pool scheduler like those of - // async-std or tokio, one could possibly assume that the futures themselves won't have to push - // all the wakers. - // TODO: This should probably be a BTreeMap (or just a VecMap) of states for each IRQ number, - // if more than one are used. I'm not sure if the XHCI interrupters actually use different - // IRQs, but it would make sense in case the hub has both isochronous (which trigger interrupts - // reapeatedly with some time in between), bulk, control, etc. I might be wrong though... - irq_state: Arc, - - drivers: BTreeMap, + drivers: CHashMap, scheme_name: String, - msi: bool, - msix: bool, - msix_info: Option, - - pcid_handle: PcidServerHandle, + interrupt_method: InterruptMethod, + pcid_handle: Mutex, + irq_reactor: Option>, + irq_reactor_sender: Sender, } struct PortState { slot: u8, - input_context: Dma, + cfg_idx: Option, + if_idx: Option, + input_context: Mutex>, dev_desc: DevDesc, endpoint_states: BTreeMap, } @@ -204,7 +223,7 @@ impl EndpointState { } impl Xhci { - pub fn new(scheme_name: String, address: usize, msi: bool, msix: bool, msix_info: Option, handle: PcidServerHandle) -> Result { + pub fn new(scheme_name: String, address: usize, interrupt_method: InterruptMethod, pcid_handle: PcidServerHandle) -> Result { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); @@ -265,21 +284,17 @@ impl Xhci { dbs, run, dev_ctx: DeviceContextList::new(max_slots)?, - cmd: CommandRing::new()?, + cmd: Ring::new(), + primary_event_ring: EventRing::new(), handles: BTreeMap::new(), next_handle: 0, port_states: BTreeMap::new(), - irq_state: Arc::new(IrqState { - triggered: AtomicBool::new(false), - wakers: Mutex::new(Vec::new()), - }), drivers: BTreeMap::new(), scheme_name, - msi, - msix, - msix_info, - pcid_handle: handle, + + interrupt_method, + pcid_handle: Mutex::new(pcid_handle), }; xhci.init(max_slots); @@ -290,87 +305,87 @@ impl Xhci { pub fn init(&mut self, max_slots: u8) { // Set enabled slots println!(" - Set enabled slots to {}", max_slots); - self.op.config.write(max_slots as u32); - println!(" - Enabled Slots: {}", self.op.config.read() & 0xFF); + self.op.get_mut().config.write(max_slots as u32); + println!(" - Enabled Slots: {}", self.op.get_mut().config.read() & 0xFF); // Set device context address array pointer let dcbaap = self.dev_ctx.dcbaap(); println!(" - Write DCBAAP: {:X}", dcbaap); - self.op.dcbaap.write(dcbaap as u64); + self.op.get_mut().dcbaap.write(dcbaap as u64); // Set command ring control register - let crcr = self.cmd.crcr(); + let crcr = self.cmd.get_mut().register(); + assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); println!(" - Write CRCR: {:X}", crcr); - self.op.crcr.write(crcr as u64); + self.op.get_mut().crcr.write(crcr as u64); // Set event ring segment table registers println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); { - self.run.ints[0].iman.writef(1, true); // clear interrupt pending if set earlier by the BIOS - - println!("IP={}", self.run.ints[0].iman.readf(1)); - - /*if self.msi { - self.pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); - println!("Enabled MSI"); - }*/ - if self.msix { - self.pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); - println!("Enabled MSI-X"); - } - - dbg!(self.pcid_handle.feature_info(PciFeature::MsiX).unwrap()); - dbg!(self.pcid_handle.feature_info(PciFeature::Msi).unwrap()); + let int = &mut self.run.get_mut().ints[0]; let erstz = 1; println!(" - Write ERSTZ: {}", erstz); - self.run.ints[0].erstsz.write(erstz); + int.erstsz.write(erstz); - let erdp = self.cmd.erdp(); + let erdp = self.primary_event_ring.get_mut().erdp(); println!(" - Write ERDP: {:X}", erdp); - self.run.ints[0].erdp.write(erdp as u64 | (1 << 3)); + int.erdp.write(erdp as u64 | (1 << 3)); - let erstba = self.cmd.erstba(); + let erstba = self.primary_event_ring.get_mut().erstba(); println!(" - Write ERSTBA: {:X}", erstba); - self.run.ints[0].erstba.write(erstba as u64); + int.erstba.write(erstba as u64); println!(" - Write IMODC and IMODI: {} and {}", 0, 0); - self.run.ints[0].imod.write(0); + int.imod.write(0); println!(" - Enable interrupts"); - self.run.ints[0].iman.writef(1 << 1, true); + int.iman.writef(1 << 1, true); } - self.op.usb_cmd.writef(1 << 2, true); + self.op.get_mut().usb_cmd.writef(1 << 2, true); + + // Setup the scratchpad buffers that are required for the xHC to function. + self.setup_scratchpads(); // Set run/stop to 1 println!(" - Start"); - self.op.usb_cmd.writef(1, true); + self.op.get_mut().usb_cmd.writef(1, true); // Wait until controller is running println!(" - Wait for running"); - while self.op.usb_sts.readf(1) { + while self.op.get_mut().usb_sts.readf(1) { println!(" - Waiting for XHCI running"); } - println!("IP={}", self.run.ints[0].iman.readf(1)); + println!("IP={}", self.run.get_mut().ints[0].iman.readf(1)); // Ring command doorbell println!(" - Ring doorbell"); - self.dbs[0].write(0); + self.dbs.get_mut()[0].write(0); println!(" - XHCI initialized"); } + pub fn setup_scratchpads(&mut self) -> Result<()> { + let buf_count = self.cap.max_scratchpad_bufs(); + + if buf_count == 0 { + return; + } + self.scratchpad_buf_arr = Some(ScratchpadBufferArray::new(buf_count)?); + self.dev_ctx.dcbaa[0] = self.scratchpad_buf_arr.register(); + } + pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); let cloned_event_trb = - self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?; + self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(slot_ty, cycle))?; Ok(cloned_event_trb.event_slot()) } pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> { - self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.disable_slot(0, cycle))?; + self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.disable_slot(slot, cycle))?; Ok(()) } @@ -378,11 +393,12 @@ impl Xhci { self.dev_ctx.contexts[slot].slot.state() } - pub fn probe(&mut self) -> Result<()> { + pub async fn probe(&self) -> Result<()> { println!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); - for i in 0..self.ports.len() { + + for i in 0..self.ports.lock().unwrap().len() { let (data, state, speed, flags) = { - let port = &self.ports[i]; + let port = &self.ports.lock().unwrap()[i]; (port.read(), port.state(), port.speed(), port.flags()) }; println!( @@ -404,13 +420,13 @@ impl Xhci { println!(" - Slot {}", slot); let mut input = Dma::::zeroed()?; - let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed)?; + let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; let dev_desc = Self::get_dev_desc_raw( - &mut self.ports, - &mut self.run, - &mut self.cmd, - &mut self.dbs, + &mut *self.ports.lock().unwrap(), + &mut *self.run.lock().unwrap(), + &mut *self.cmd.lock().unwrap(), + &mut *self.dbs.lock().unwrap(), i, slot, &mut ring, @@ -420,8 +436,10 @@ impl Xhci { let mut port_state = PortState { slot, - input_context: input, + input_context: Mutex::new(input), dev_desc, + cfg_idx: None, + if_idx: None, endpoint_states: std::iter::once(( 0, EndpointState { @@ -433,7 +451,7 @@ impl Xhci { }; if self.cap.cic() { - self.op.set_cie(true); + self.op.lock().unwrap().set_cie(true); } /*match self.spawn_drivers(i, &mut port_state) { @@ -474,8 +492,8 @@ impl Xhci { Ok(()) } - pub fn address_device( - &mut self, + pub async fn address_device( + &self, input_context: &mut Dma, i: usize, slot_ty: u8, @@ -563,23 +581,45 @@ impl Xhci { let input_context_physical = input_context.physical(); - self.execute_command("ADDRESS_DEVICE", |trb, cycle| { + let (event_trb, _) = self.execute_command(|trb, cycle| { trb.address_device(slot, input_context_physical, false, cycle) - }) - .expect("ADDRESS_DEVICE failed"); + }).await; + + if event_trb.completion_code() != TrbCompletionCode::Success as u8 { + println!("Failed to address device at slot {} (port {})", slot, i); + } + Ok(ring) } + pub fn uses_msi(&self) -> bool { + if let InterruptMethod::Msi = self.interrupt_method { true } else { false } + } + pub fn uses_msix(&self) -> bool { + if let InterruptMethod::MsiX(_) = self.interrupt_method { true } else { false } + } + pub fn msix_info(&self) -> Option<&MsixInfo> { + match self.interrupt_method { + InterruptMethod::MsiX(ref info) => Some(info), + _ => None, + } + } + pub fn msix_info_mut(&mut self) -> Option<&mut MsixInfo> { + match self.interrupt_method { + InterruptMethod::MsiX(ref mut info) => Some(info), + _ => None, + } + } /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always /// true when using MSI/MSI-X. pub fn received_irq(&mut self) -> bool { - if self.msi || self.msix { + if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", self.run.ints[0].iman.readf(1), self.run.ints[0].erdp.readf(3)); - println!("MSI-X PB={}", self.msix_info.as_mut().unwrap().pba(0)); - let entry = self.msix_info.as_mut().unwrap().table_entry_pointer(0); + println!("MSI-X PB={}", self.msix_info_mut().unwrap().pba(0)); + let entry = self.msix_info_mut().unwrap().table_entry_pointer(0); println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); true } else if self.run.ints[0].iman.readf(1) { @@ -595,17 +635,7 @@ impl Xhci { } } - /// Handle an IRQ event. pub fn on_irq(&mut self) { - // Wake all futures awaiting the IRQ. - for waker in self.irq_state.wakers.lock().unwrap().drain(..) { - waker.wake(); - } - } - pub(crate) fn irq(&self) -> IrqFuture { - IrqFuture { - state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)), - } } fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> { // TODO: There should probably be a way to select alternate interfaces, and not just the @@ -784,44 +814,3 @@ lazy_static! { toml::from_slice::(TOML).expect("Failed to parse internally embedded config file") }; } - -pub(crate) struct IrqFuture { - state: IrqFutureState, -} - -struct IrqState { - triggered: AtomicBool, - // TODO: Perhaps a channel? - wakers: Mutex>, -} - -enum IrqFutureState { - Pending(Weak), - Finished, -} - -impl std::future::Future for IrqFuture { - type Output = (); - - fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { - let this = self.get_mut(); - - match &mut this.state { - // TODO: Ordering? - IrqFutureState::Pending(state_weak) => { - let state = state_weak.upgrade().expect( - "IRQ futures keep getting polled even after the driver has been deinitialized", - ); - - if state.triggered.load(atomic::Ordering::SeqCst) { - this.state = IrqFutureState::Finished; - task::Poll::Ready(()) - } else { - state.wakers.lock().unwrap().push(context.waker().clone()); - task::Poll::Pending - } - } - IrqFutureState::Finished => panic!("polling finished future"), - } - } -} diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index c941c70dca..26d0433277 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -1,3 +1,5 @@ +use std::mem; + use syscall::error::Result; use syscall::io::Dma; @@ -26,7 +28,7 @@ impl Ring { addr as u64 | self.cycle as u64 } - pub fn next(&mut self) -> (&mut Trb, bool) { + pub fn next_index(&mut self) -> usize { let mut i; loop { i = self.i; @@ -45,7 +47,11 @@ impl Ring { break; } } + i + } + pub fn next(&mut self) -> (&mut Trb, bool) { + let i = self.next_index(); (&mut self.trbs[i], self.cycle) } /// Endless iterator that iterates through the ring items, over and over again. The iterator @@ -53,6 +59,51 @@ impl Ring { pub fn iter(&self) -> impl Iterator + '_ { Iter { ring: self, i: self.i } } + /// Takes a physical address and returns the index into this ring, that the index represents. + /// Returns `None` if the address is outside the bounds of this ring. + /// + /// # Panics + /// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB. + pub fn phys_addr_to_index(&self, paddr: u64) -> Option { + let base = self.trbs.physical(); + let offset = paddr.checked_sub(base)?; + + assert_eq!(offset % mem::size_of::(), 0, "unaligned TRB physical address"); + + let index = offset / mem::size_of::(); + + if index > self.trbs.len() { + return None; + } + + Some(index) + } + pub fn phys_addr_to_entry_ref(&self, paddr: u64) -> Option<&Trb> { + &self.trbs[self.phys_addr_to_index(paddr)] + } + pub fn phys_addr_to_entry_mut(&self, paddr: u64) -> Option<&mut Trb> { + &mut self.trbs[self.phys_addr_to_index(paddr)] + } + pub fn phys_addr_to_entry(&self, paddr: u64) -> Option { + self.trbs[self.phys_addr_to_index(paddr)].clone() + } + pub(crate) fn start_virt_addr(&self) -> *const Trb { + self.trbs.as_ptr() + } + pub(crate) fn end_virt_addr(&self) -> *const Trb { + unsafe { self.start_virt_addr().offset(self.trbs.len()) } + } + pub fn trb_phys_ptr(&self, trb: &Trb) -> u64 { + let trb_virt_pointer = trb as *const Trb; + let trbs_base_virt_pointer = self.trbs.as_ptr(); + + if trb_virt_pointer < trbs_base_virt_pointer || trb_virt_pointer > trbs_base_virt_pointer + self.trbs.len() * mem::size_of::() { + panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb); + } + let trbs_base_phys_ptr = self.trbs.physical(); + let trb_phys_ptr = trb_virt_pointer - trbs_base_phys_ptr; + trb_phys_ptr + } /* /// Endless mutable iterator that iterates through the ring items, over and over again. The /// iterator doesn't enqueue or dequeue anything, but the trbs are mutably borrowed. diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 1abfc8b056..feaca29bcf 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -17,7 +17,6 @@ use syscall::{ use super::{port, usb}; use super::{Device, EndpointState, Xhci}; -use super::command::CommandRing; use super::context::{ InputContext, SlotState, StreamContext, StreamContextArray, StreamContextType, ENDPOINT_CONTEXT_STATUS_MASK, @@ -211,40 +210,38 @@ impl AnyDescriptor { } impl Xhci { - pub fn execute_command( - &mut self, - cmd_name: &str, - f: F, - ) -> Result { - self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); - let (cmd, cycle, event) = self.cmd.next(); - + pub fn execute_command_noreply(&self, f: F) { + let (cmd, cycle) = self.cmd.lock().unwrap(); f(cmd, cycle); - println!("INTE={}", self.op.usb_cmd.readf(1 << 2)); - println!("IP={}", self.run.ints[0].iman.readf(1)); - self.dbs[0].write(0); - println!("IP={}", self.run.ints[0].iman.readf(1)); + self.dbs.lock().unwrap()[0].write(0); - while event.data.read() == 0/* || self.run.ints[0].iman.readf(1)*/ { - println!(" - {} Waiting for event", cmd_name); - } - println!("IP={}", self.run.ints[0].iman.readf(1)); + // TODO: It's still possible not to reset the TRB, right? + } - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::CommandCompletion as u8 - { - println!("{} failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", cmd_name, event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); - return Err(Error::new(EIO)); - } + pub async fn execute_command( + &self, + f: F, + ) -> (Trb, Trb) { + let next_event = { + let command_ring = self.cmd.lock().unwrap(); - let ret = event.clone(); + let (cmd, cycle) = command_ring.next(); + f(cmd, cycle); - cmd.reserved(false); - event.reserved(false); + // get the future here before awaiting, to destroy the lock before deadlock + self.next_command_completion_event_trb(&cmd) + }; - self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); - Ok(ret) + self.dbs.lock().unwrap()[0].write(0); + + let trbs = next_event.await; + let event_trb = trbs.event_trb; + let command_trb = trbs.src_trb.expect("Command completion event TRBs shall always have a valid pointer to a valid source command TRB"); + + assert_eq!(command_trb.trb_type(), TrbType::CommandCompletion as u8, "The IRQ reactor (or the xHC) gave an invalid event TRB"); + + (event_trb, command_trb) } pub fn execute_control_transfer( &mut self, @@ -418,8 +415,16 @@ impl Xhci { ) } - fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { - let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?); + async fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { + let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; + + let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { + (Some(c), Some(i)) => (c, i), + _ => return Err(Error::new(EIO)), + }; + + let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let slot = self .port_states @@ -427,10 +432,10 @@ impl Xhci { .ok_or(Error::new(EBADF))? .slot; - self.execute_command("RESET_ENDPOINT", |trb, cycle| { - trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle) - })?; - Ok(()) + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { + trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle); + }).await; + handle_event_trb("RESET_ENDPOINT", &event_trb, &command_trb) } fn endp_ctx_interval(speed_id: &ProtocolSpeed, endp_desc: &EndpDesc) -> u8 { @@ -507,62 +512,14 @@ impl Xhci { } } - fn port_state(&self, port: usize) -> Result<&super::PortState> { + fn port_state(&self, port: usize) -> Result> { self.port_states.get(&port).ok_or(Error::new(EBADF)) } - fn port_state_mut(&mut self, port: usize) -> Result<&mut super::PortState> { - self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) - } - fn endpoint_state_mut(&mut self, port: usize, endp_num: u8) -> Result<&mut EndpointState> { - self.port_state_mut(port)? - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADF)) - } - fn input_context(&mut self, port: usize) -> Result<&mut Dma> { - Ok(&mut self.port_state_mut(port)?.input_context) - } - fn endp_ctx( - &mut self, - port: usize, - endp_num_xhc: u8, - ) -> Result<&mut super::context::EndpointContext> { - Ok(self - .input_context(port)? - .device - .endpoints - .get_mut(endp_num_xhc as usize - 1) - .ok_or(Error::new(EIO))?) - } - fn dev_desc(&self, port: usize) -> Result<&DevDesc> { - Ok(&self.port_state(port)?.dev_desc) - } - fn config_descs(&self, port: usize) -> Result<&[ConfDesc]> { - Ok(&self.dev_desc(port)?.config_descs) - } - fn config_desc(&self, port: usize, desc: u8) -> Result<&ConfDesc> { - Ok(self - .config_descs(port)? - .get(usize::from(desc)) - .ok_or(Error::new(EBADF))?) - } - fn endp_descs(&self, port: usize, config_desc: u8, if_desc: u8) -> Result<&[EndpDesc]> { - Ok(&self - .port_state(port)? - .dev_desc - .config_descs - .get(usize::from(config_desc)) - .ok_or(Error::new(EIO))? - .interface_descs - .get(usize::from(if_desc)) - .ok_or(Error::new(EIO))? - .endpoints) - } - fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { + async fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; - if (!self.cap.cic() || !self.op.cie()) + if (!self.cap.cic() || !self.op.lock().unwrap().cie()) && (req.config_desc != 0 || req.interface_desc != None || req.alternate_setting != None) { //return Err(Error::new(EOPNOTSUPP)); @@ -574,9 +531,11 @@ impl Xhci { return Err(Error::new(EBADMSG)); } - let (endp_desc_count, new_context_entries) = { - let endpoints = - self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?; + let (endp_desc_count, new_context_entries, configuration_value) = { + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let config_desc = port_state.dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; + + let endpoints = config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; if endpoints.len() >= 31 { return Err(Error::new(EIO)); @@ -588,18 +547,20 @@ impl Xhci { Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l), None => 1, }) + 1, + config_desc.configuration_value, ) }; let lec = self.cap.lec(); let log_max_psa_size = self.cap.max_psa_size(); - let port_speed_id = self.ports[port].speed(); + let port_speed_id = self.ports.lock().unwrap()[port].speed(); let speed_id: &ProtocolSpeed = self .lookup_psiv(port as u8, port_speed_id) .ok_or(Error::new(EIO))?; { - let input_context = self.input_context(port)?; + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let input_context = port_state.input_context.lock().unwrap(); // Configure the slot context as well, which holds the last index of the endp descs. input_context.add_context.write(1); @@ -625,9 +586,9 @@ impl Xhci { for endp_idx in 0..endp_desc_count as u8 { let endp_num = endp_idx + 1; - let endpoints = - self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?; - let dev_desc = self.dev_desc(port)?; + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let dev_desc = &port_state.dev_desc; + let endpoints = &dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); @@ -685,7 +646,7 @@ impl Xhci { assert_eq!(max_error_count & 0x3, max_error_count); assert_ne!(ep_ty, 0); // 0 means invalid. - let port_state = self.port_state_mut(port)?; + let port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; let ring_ptr = if usb_log_max_streams.is_some() { let mut array = StreamContextArray::new(1 << (primary_streams + 1))?; @@ -728,10 +689,11 @@ impl Xhci { }; assert_eq!(primary_streams & 0x1F, primary_streams); - let input_context = self.input_context(port)?; + let port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; + let input_context = port_state.input_context.lock().unwrap(); input_context.add_context.writef(1 << endp_num_xhc, true); - let endp_ctx = self.endp_ctx(port, endp_num_xhc)?; + let endp_ctx = input_context.device.endpoints.get_mut(endp_num_xhc as usize - 1).ok_or(Error::new(EIO))?; endp_ctx.a.write( u32::from(mult) << 8 @@ -756,14 +718,17 @@ impl Xhci { .write(u32::from(avg_trb_len) | (u32::from(max_esit_payload_lo) << 16)); } - let slot = self.port_state(port)?.slot; - let input_context_physical = self.input_context(port)?.physical(); - self.execute_command("CONFIGURE_ENDPOINT", |trb, cycle| { + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let slot = port_state.slot; + let input_context_physical = port_state.input_context.lock().unwrap().physical(); + + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.configure_endpoint(slot, input_context_physical, cycle) - })?; + }).await; + + handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; // Tell the device about this configuration. - let configuration_value = self.config_desc(port, req.config_desc)?.configuration_value; self.set_configuration(port, configuration_value)?; if let (Some(interface_num), Some(alternate_setting)) = @@ -819,12 +784,6 @@ impl Xhci { unreachable!() } } - fn endp_desc(&self, port_num: usize, endp_num: u8) -> Result<&EndpDesc> { - Ok(self - .endp_descs(port_num, 0, 0)? - .get(usize::from(endp_num) - 1) - .ok_or(Error::new(EBADF))?) - } fn endp_doorbell(endp_num: u8, desc: &EndpDesc, stream_id: u16) -> u32 { let db_target = Self::endp_num_to_dci(endp_num, desc); let db_task_id: u16 = stream_id; @@ -969,11 +928,16 @@ impl Xhci { .port_states .get_mut(&port_id) .ok_or(Error::new(ENOENT))?; + let ports = self.ports.lock().unwrap(); + let run = self.run.lock().unwrap(); + let cmd = self.cmd.lock().unwrap(); + let dbs = self.dbs.lock().unwrap(); + Self::get_dev_desc_raw( - &mut self.ports, - &mut self.run, - &mut self.cmd, - &mut self.dbs, + &mut *ports, + &mut *run, + &mut *cmd, + &mut *dbs, port_id, st.slot, st.endpoint_states @@ -986,7 +950,7 @@ impl Xhci { pub(crate) fn get_dev_desc_raw( ports: &mut [port::Port], run: &mut RuntimeRegs, - cmd: &mut CommandRing, + cmd: &mut Ring, dbs: &mut [Doorbell], port_id: usize, slot: u8, @@ -999,7 +963,7 @@ impl Xhci { // TODO: Should the descriptors be stored in PortState? - run.ints[0].erdp.write(cmd.erdp() | (1 << 3)); + run.ints[0].erdp.write(cmd.register() | (1 << 3)); let mut dev = Device { ring, @@ -1148,11 +1112,6 @@ impl Xhci { setup: usb::Setup, transfer_kind: TransferKind, ) -> Result<()> { - // TODO: This json format might be too high level, but is useful for debugging, - // but when actual device-specific drivers are written, a binary format would - // be better. Maybe something simple like bincode could be used, if a custom binary struct - // is too much overkill. - self.execute_control_transfer( port_num, setup, @@ -1242,7 +1201,8 @@ impl Xhci { PortReqState::WaitingForDeviceBytes(_, _) => return Err(Error::new(EBADF)), PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), }; - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { Handle::PortReq(_, ref mut state) => *state = st, _ => unreachable!(), } @@ -1272,7 +1232,9 @@ impl Xhci { } PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), }; - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + + let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { Handle::PortReq(_, ref mut state) => *state = st, _ => unreachable!(), } @@ -1306,8 +1268,9 @@ impl SchemeMut for Xhci { if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { let mut contents = Vec::new(); - for (index, _) in self - .ports + let ports_guard = self.ports.lock().unwrap(); + + for (index, _) in ports_guard .iter() .enumerate() .filter(|(_, port)| port.flags().contains(port::PortFlags::PORT_CCS)) @@ -1455,34 +1418,36 @@ impl SchemeMut for Xhci { } fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { - match self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::TopLevel(_, ref buf) - | Handle::Port(_, _, ref buf) - | Handle::Endpoints(_, _, ref buf) => { + let guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + match &*guard { + &Handle::TopLevel(_, ref buf) + | &Handle::Port(_, _, ref buf) + | &Handle::Endpoints(_, _, ref buf) => { stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; } - Handle::PortDesc(_, _, ref buf) => { + &Handle::PortDesc(_, _, ref buf) => { stat.st_mode = MODE_FILE; stat.st_size = buf.len() as u64; } - Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) - | Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => { + &Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) + | &Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => { stat.st_mode = MODE_CHR; stat.st_size = buf.len() as u64; } - Handle::PortReq(_, PortReqState::Tmp) - | Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), + &Handle::PortReq(_, PortReqState::Tmp) + | &Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), - Handle::PortState(_, _) | Handle::PortReq(_, _) => stat.st_mode = MODE_CHR, - Handle::Endpoint(_, _, st) => match st { - EndpointHandleTy::Ctl | EndpointHandleTy::Data => stat.st_mode = MODE_CHR, - EndpointHandleTy::Root(_, ref buf) => { + &Handle::PortState(_, _) | &Handle::PortReq(_, _) => stat.st_mode = MODE_CHR, + &Handle::Endpoint(_, _, ref st) => match st { + &EndpointHandleTy::Ctl | &EndpointHandleTy::Data => stat.st_mode = MODE_CHR, + &EndpointHandleTy::Root(_, ref buf) => { stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; } }, - Handle::ConfigureEndpoints(_) => { + &Handle::ConfigureEndpoints(_) => { stat.st_mode = MODE_CHR | 0o200; // write only } } @@ -1490,21 +1455,22 @@ impl SchemeMut for Xhci { } fn fpath(&mut self, fd: usize, buffer: &mut [u8]) -> Result { - // XXX: write!() should return the length instead of (). - let mut src = Vec::::new(); - match self.handles.get(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(_, _) => write!(src, "/").unwrap(), - Handle::Port(port_num, _, _) => write!(src, "/port{}/", port_num).unwrap(), - Handle::PortDesc(port_num, _, _) => { - write!(src, "/port{}/descriptors", port_num).unwrap() + let cursor = io::Cursor::new(buffer); + + let guard = self.handles.get(&fd).ok_or(Error::new(EBADF))?; + match &*guard { + &Handle::TopLevel(_, _) => write!(cursor, "/").unwrap(), + &Handle::Port(port_num, _, _) => write!(cursor, "/port{}/", port_num).unwrap(), + &Handle::PortDesc(port_num, _, _) => { + write!(cursor, "/port{}/descriptors", port_num).unwrap() } - Handle::PortState(port_num, _) => write!(src, "/port{}/state", port_num).unwrap(), - Handle::PortReq(port_num, _) => write!(src, "/port{}/request", port_num).unwrap(), - Handle::Endpoints(port_num, _, _) => { - write!(src, "/port{}/endpoints/", port_num).unwrap() + &Handle::PortState(port_num, _) => write!(cursor, "/port{}/state", port_num).unwrap(), + &Handle::PortReq(port_num, _) => write!(cursor, "/port{}/request", port_num).unwrap(), + &Handle::Endpoints(port_num, _, _) => { + write!(cursor, "/port{}/endpoints/", port_num).unwrap() } - Handle::Endpoint(port_num, endp_num, st) => write!( - src, + &Handle::Endpoint(port_num, endp_num, st) => write!( + cursor, "/port{}/endpoints/{}/{}", port_num, endp_num, @@ -1515,17 +1481,17 @@ impl SchemeMut for Xhci { } ) .unwrap(), - Handle::ConfigureEndpoints(port_num) => { - write!(src, "/port{}/configure", port_num).unwrap() + &Handle::ConfigureEndpoints(port_num) => { + write!(cursor, "/port{}/configure", port_num).unwrap() } } - let bytes_to_read = cmp::min(src.len(), buffer.len()); - buffer[..bytes_to_read].copy_from_slice(&src[..bytes_to_read]); - Ok(bytes_to_read) + let src_len = usize::try_from(cursor.seek(io::SeekFrom::End(0)).unwrap()).unwrap(); + Ok(src_len) } fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { // Directories, or fixed files Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) @@ -1557,7 +1523,8 @@ impl SchemeMut for Xhci { } fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + 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) @@ -1609,7 +1576,8 @@ impl SchemeMut for Xhci { } } fn write(&mut self, fd: usize, buf: &[u8]) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { &mut Handle::ConfigureEndpoints(port_num) => { self.configure_endpoints(port_num, buf)?; Ok(buf.len()) @@ -1667,7 +1635,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }) } - pub fn on_req_reset_device( + pub async fn on_req_reset_device( &mut self, port_num: usize, endp_num: u8, @@ -1678,8 +1646,8 @@ impl Xhci { } // Change the endpoint state from anything, but most likely HALTED (otherwise resetting // would be quite meaningless), to stopped. - self.reset_endpoint(port_num, endp_num, false)?; - self.restart_endpoint(port_num, endp_num)?; + self.reset_endpoint(port_num, endp_num, false).await?; + self.restart_endpoint(port_num, endp_num).await?; if clear_feature { self.device_req_no_data( @@ -1695,37 +1663,46 @@ impl Xhci { } Ok(()) } - pub fn restart_endpoint(&mut self, port_num: usize, endp_num: u8) -> Result<()> { + pub async fn restart_endpoint(&self, port_num: usize, endp_num: u8) -> Result<()> { let port_state = self .port_states .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; + + let endp_desc = port_state + .dev_desc + .config_descs + .get(0) + .ok_or(Error::new(EIO))? + .interface_descs + .get(0) + .ok_or(Error::new(EIO))? + .endpoints + .get(endp_num as usize - 1) + .ok_or(Error::new(EBADFD))?; + let direction = if endp_num != 0 { - let endp_desc = port_state - .dev_desc - .config_descs - .get(0) - .ok_or(Error::new(EIO))? - .interface_descs - .get(0) - .ok_or(Error::new(EIO))? - .endpoints - .get(endp_num as usize - 1) - .ok_or(Error::new(EBADFD))?; endp_desc.direction() } else { EndpDirection::Bidirectional }; - let endpoint_state: &mut EndpointState = port_state + + let endpoint_state = port_state .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADFD))?; + let (has_streams, ring) = match &mut endpoint_state.transfer { &mut super::RingOrStreams::Ring(ref mut ring) => (false, ring), &mut super::RingOrStreams::Streams(ref mut arr) => { (true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?) } }; + let doorbell = Self::endp_doorbell( + endp_num, + endp_desc, + if has_streams { stream_id } else { 0 }, + ); let (cmd, cycle) = ring.next(); cmd.transfer_no_op(0, false, false, false, cycle); @@ -1733,14 +1710,12 @@ impl Xhci { let deque_ptr_and_cycle = ring.register(); let slot = port_state.slot; - self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle)?; + self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle).await?; + + let stream_id = 1u16; - self.dbs[slot as usize].write(Self::endp_doorbell( - endp_num, - self.endp_desc(port_num, endp_num)?, - if has_streams { stream_id } else { 0 }, - )); + self.dbs.lock().unwrap()[slot as usize].write(doorbell); Ok(()) } pub fn endp_direction(&self, port_num: usize, endp_num: u8) -> Result { @@ -1763,16 +1738,24 @@ impl Xhci { pub fn slot(&self, port_num: usize) -> Result { Ok(self.port_states.get(&port_num).ok_or(Error::new(EIO))?.slot) } - pub fn set_tr_deque_ptr( - &mut self, + pub async fn set_tr_deque_ptr( + &self, port_num: usize, endp_num: u8, deque_ptr_and_cycle: u64, ) -> Result<()> { - let slot = self.slot(port_num)?; - let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?); + let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; + let slot = port_state.slot; - self.execute_command("SET_TR_DEQUEUE_POINTER", |trb, cycle| { + let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { + (Some(c), Some(i)) => (c, i), + _ => return Err(Error::new(EIO)), + }; + + let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); + + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.set_tr_deque_ptr( deque_ptr_and_cycle, cycle, @@ -1781,11 +1764,11 @@ impl Xhci { endp_num_xhc, slot, ) - })?; + }).await; - Ok(()) + handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb) } - pub fn on_write_endp_ctl( + pub async fn on_write_endp_ctl( &mut self, port_num: usize, endp_num: u8, @@ -1808,9 +1791,7 @@ impl Xhci { } }, XhciEndpCtlReq::Reset { no_clear_feature } => match ep_if_state { - EndpIfState::Init => { - self.on_req_reset_device(port_num, endp_num, !no_clear_feature)? - } + EndpIfState::Init => self.on_req_reset_device(port_num, endp_num, !no_clear_feature).await?, other => { return Err(Error::new(EBADF)); } @@ -1874,7 +1855,11 @@ impl Xhci { endp_num: u8, buf: &[u8], ) -> Result { - let ep_if_state = &mut self.endpoint_state_mut(port_num, endp_num)?.driver_if_state; + let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; + let endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + + let ep_if_state = &mut endpoint_state.driver_if_state; + match ep_if_state { &mut EndpIfState::WaitingForDataPipe { direction: XhciEndpCtlDirection::Out, @@ -1892,7 +1877,9 @@ impl Xhci { // invoking further data transfer calls if any single transfer returns fewer bytes // than requested. - let ep_if_state = &mut self.endpoint_state_mut(port_num, endp_num)?.driver_if_state; + let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; + let endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + let ep_if_state = &mut endpoint_state.driver_if_state; if let &mut EndpIfState::WaitingForDataPipe { direction: XhciEndpCtlDirection::Out, @@ -2005,6 +1992,18 @@ impl Xhci { _ => return Err(Error::new(EBADF)), } } + pub fn event_handler_finished(&self) { + // write 1 to EHB to clear it + self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true); + } +} +fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { + if event_trb.completion_code() == TrbCompletionCode::Success as u8 { + Ok(()) + } else { + println!("{} command (TRB {:?}) failed with event trb {:?}", name, command_trb, event_trb); + Err(Error::new(EIO)) + } } use std::ops::{Add, Div, Rem}; pub fn div_round_up(a: T, b: T) -> T diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 4ad02bee37..c23f543a38 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -5,6 +5,7 @@ use syscall::io::{Io, Mmio}; use super::context::StreamContextType; #[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum TrbType { Reserved, /* Transfer */ @@ -33,8 +34,8 @@ pub enum TrbType { ForceHeader, NoOpCmd, /* Reserved */ - Rsv24, - Rsv25, + GetExtendedProperty, + SetExtendedProperty, Rsv26, Rsv27, Rsv28, @@ -54,6 +55,7 @@ pub enum TrbType { } #[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum TrbCompletionCode { Invalid, Success, @@ -157,6 +159,34 @@ impl Trb { pub fn completion_param(&self) -> u32 { self.status.read() & TRB_STATUS_COMPLETION_PARAM_MASK } + fn has_completion_trb_pointer(&self) -> bool { + if self.completion_code() == TrbCompletionCode::RingUnderrun as u8 || self.completion_code() == TrbCompletionCode::RingOverrun as u8 { + false + } else if self.completion_code() == TrbCompletionCode::VfEventRingFull as u8 { + false + } else { + true + } + } + pub fn completion_trb_pointer(&self) -> Option { + debug_assert_eq!(self.trb_type(), TrbType::CommandCompletion as u8); + + if self.has_completion_trb_pointer() { + Some(self.data.read()) + } else { + None + } + } + pub fn transfer_event_trb_pointer(&self) -> Option { + debug_assert_eq!(self.trb_type(), TrbType::Transfer as u8); + + if self.has_completion_trb_pointer() { + Some(self.data.read()) + } else { + None + } + } + pub fn event_slot(&self) -> u8 { (self.control.read() >> 24) as u8 } @@ -383,6 +413,43 @@ impl Trb { | ((TrbType::Normal as u32) << 10), ) } + pub fn is_command_trb(&self) -> bool { + let valid_trb_types = [ + TrbType::NoOpCmd as u8, + TrbType::EnableSlot as u8, + TrbType::DisableSlot as u8, + TrbType::AddressDevice as u8, + TrbType::ConfigureEndpoint as u8, + TrbType::EvaluateContext as u8, + TrbType::ResetEndpoint as u8, + TrbType::StopEndpoint as u8, + TrbType::SetTrDequeuePointer as u8, + TrbType::ResetDevice as u8, + TrbType::ForceEvent as u8, + TrbType::NegotiateBandwidth as u8, + TrbType::SetLatencyToleranceValue as u8, + TrbType::GetPortBandwidth as u8, + TrbType::ForceHeader as u8, + TrbType::GetExtendedProperty as u8, + TrbType::SetExtendedProperty as u8, + ]; + valid_trb_types.contains(&self.trb_type()) + } + pub fn is_transfer_trb(&self) -> bool { + // XXX: Unfortunately, the only way to use match statements with integer constants, is to + // precast them into valid enum values, which either requires a derive macro such as + // num_traits's #[derive(FromPrimitive)], or manually writing the reverse match statement + // first. + let valid_trb_types = [ + TrbType::Normal as u8, + TrbType::SetupStage as u8, + TrbType::DataStage as u8, + TrbType::StatusStage as u8, + TrbType::Isoch as u8, + TrbType::NoOp as u8, + ]; + valid_trb_types.contains(&self.trb_type()) + } } impl fmt::Debug for Trb { From bae238bbef3c8aa3d47f98d81d487aff610f2254 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 26 Mar 2020 19:17:31 +0100 Subject: [PATCH 07/22] Asyncify Xhci::execute_transfer. --- xhcid/src/xhci/irq_reactor.rs | 3 +- xhcid/src/xhci/scheme.rs | 112 +++++++++++++++++++--------------- 2 files changed, 63 insertions(+), 52 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index a8b777f37a..4d808f6f30 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -357,14 +357,13 @@ impl Xhci { } let command_ring = self.cmd.lock().unwrap(); - let ring = &command_ring.ring; EventTrbFuture::Pending { state: FutureState { // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). is_isoch_or_vf: false, state_kind: StateKind::CommandCompletion { - phys_ptr: ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb) + phys_ptr: command_ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb) }, message: Arc::new(Mutex::new(None)), }, diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index feaca29bcf..c96d3d9c08 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -306,7 +306,9 @@ impl Xhci { } /// NOTE: There has to be AT LEAST one successful invocation of `d`, that actually updates the /// TRB (it could be a NO-OP in the worst case). - pub fn execute_transfer( + /// The function is also required to set the Interrupt on Completion flag, or this function + /// will never complete. + pub async fn execute_transfer( &mut self, port_num: usize, endp_num: u8, @@ -318,6 +320,14 @@ impl Xhci { D: FnMut(&mut Trb, bool) -> ControlFlow, { let port_state = self.port_state_mut(port_num)?; + + let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { + (Some(c), Some(i)) => (c, i), + _ => return Err(Error::new(EIO)), + }; + + let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let slot = port_state.slot; let endp_state = port_state .endpoint_states @@ -338,57 +348,43 @@ impl Xhci { .ok_or(Error::new(EBADF))?), }; - loop { + let future = loop { let (trb, cycle) = ring.next(); + match d(trb, cycle) { - ControlFlow::Break => break, + ControlFlow::Break => { + break self.next_transfer_event_trb(super::irq_reactor::RingId { slot, endpoint_num: endp_num, stream_id }, &trb); + } ControlFlow::Continue => continue, } - } + }; - self.dbs[usize::from(slot)].write(Self::endp_doorbell( + self.dbs.lock().unwrap()[usize::from(slot)].write(Self::endp_doorbell( endp_num, - self.endp_desc(port_num, endp_num)?, + endp_desc, if has_streams { stream_id } else { 0 }, )); - let cloned_trb = { - let event = self.cmd.next_event(); - while event.data.read() == 0 { - println!(" - {} Waiting for event", name); - } + let trbs = future.await; + let event_trb = trbs.event_trb; + let transfer_trb = trbs.src_trb.unwrap(); - // FIXME: EDTLA if event data was set - if event.completion_code() != TrbCompletionCode::ShortPacket as u8 - && event.transfer_length() != 0 - { - println!( - "Event trb didn't yield a short packet, but some bytes were not transferred" - ); - } + handle_transfer_event_trb("EXECUTE_TRANSFER", &event_trb, &transfer_trb)?; - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::Transfer as u8 - { - println!( - "Custom transfer event failed with {:#0x} {:#0x} {:#0x}", - event.data.read(), - event.status.read(), - event.control.read() - ); - } - // TODO: Handle event data - println!("EVENT DATA: {:?}", event.event_data()); + // FIXME: EDTLA if event data was set + if event_trb.completion_code() != TrbCompletionCode::ShortPacket as u8 + && event_trb.transfer_length() != 0 + { + println!( + "Event trb didn't yield a short packet, but some bytes were not transferred" + ); + return Err(Error::new(EIO)); + } - let cloned_trb = event.clone(); - event.reserved(false); + // TODO: Handle event data + println!("EVENT DATA: {:?}", event_trb.event_data()); - cloned_trb - }; - - self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); - - Ok(cloned_trb) + Ok(event_trb) } fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { self.execute_control_transfer( @@ -435,6 +431,8 @@ impl Xhci { let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle); }).await; + self.event_handler_finished(); + handle_event_trb("RESET_ENDPOINT", &event_trb, &command_trb) } @@ -512,9 +510,12 @@ impl Xhci { } } - fn port_state(&self, port: usize) -> Result> { + fn port_state(&self, port: usize) -> Result> { self.port_states.get(&port).ok_or(Error::new(EBADF)) } + fn port_state_mut(&self, port: usize) -> Result> { + self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) + } async fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; @@ -725,6 +726,7 @@ impl Xhci { let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.configure_endpoint(slot, input_context_physical, cycle) }).await; + self.event_handler_finished(); handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; @@ -739,7 +741,7 @@ impl Xhci { Ok(()) } - fn transfer_read( + async fn transfer_read( &mut self, port_num: usize, endp_idx: u8, @@ -753,9 +755,9 @@ impl Xhci { } else { DeviceReqData::NoData }, - ) + ).await } - fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> { + async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> { self.transfer( port_num, endp_idx, @@ -764,7 +766,7 @@ impl Xhci { } else { DeviceReqData::NoData }, - ) + ).await } const fn def_control_endp_doorbell() -> u32 { 1 @@ -791,7 +793,7 @@ impl Xhci { (u32::from(db_task_id) << 16) | u32::from(db_target) } // TODO: Rename DeviceReqData to something more general. - fn transfer( + async fn transfer( &mut self, port_num: usize, endp_idx: u8, @@ -913,7 +915,8 @@ impl Xhci { ControlFlow::Break } }, - )?; + ).await?; + self.event_handler_finished(); let bytes_transferred = buf.len() as u32 - event.transfer_length(); @@ -1615,6 +1618,7 @@ impl Xhci { } else { 1 }; + let raw = self .dev_ctx .contexts @@ -1626,6 +1630,7 @@ impl Xhci { .a .read() & super::context::ENDPOINT_CONTEXT_STATUS_MASK; + Ok(match raw { 0 => EndpointStatus::Disabled, 1 => EndpointStatus::Enabled, @@ -1698,6 +1703,7 @@ impl Xhci { (true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?) } }; + let stream_id = 1u16; let doorbell = Self::endp_doorbell( endp_num, endp_desc, @@ -1712,9 +1718,6 @@ impl Xhci { self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle).await?; - - - let stream_id = 1u16; self.dbs.lock().unwrap()[slot as usize].write(doorbell); Ok(()) } @@ -1765,6 +1768,7 @@ impl Xhci { slot, ) }).await; + self.event_handler_finished(); handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb) } @@ -1802,7 +1806,7 @@ impl Xhci { // Yield the result directly because no bytes have to be sent or received // beforehand. let (completion_code, bytes_transferred) = - self.transfer(port_num, endp_num - 1, DeviceReqData::NoData)?; + self.transfer(port_num, endp_num - 1, DeviceReqData::NoData).await?; if bytes_transferred > 0 { return Err(Error::new(EIO)); } @@ -2005,6 +2009,14 @@ fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<() Err(Error::new(EIO)) } } +fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> { + if event_trb.completion_code() == TrbCompletionCode::Success as u8 || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 { + Ok(()) + } else { + println!("{} transfer (TRB {:?}) failed with event trb {:?}", name, transfer_trb, event_trb); + Err(Error::new(EIO)) + } +} use std::ops::{Add, Div, Rem}; pub fn div_round_up(a: T, b: T) -> T where From 6791429cd2ff9476c2f36ee23bf659be048260ac Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 27 Mar 2020 23:44:01 +0100 Subject: [PATCH 08/22] Fix most high-level errors in xhcid. --- xhcid/src/main.rs | 52 +--- xhcid/src/xhci/capability.rs | 4 +- xhcid/src/xhci/context.rs | 16 +- xhcid/src/xhci/irq_reactor.rs | 134 ++++++---- xhcid/src/xhci/mod.rs | 271 +++++++++++-------- xhcid/src/xhci/ring.rs | 17 +- xhcid/src/xhci/scheme.rs | 490 ++++++++++++++++------------------ xhcid/src/xhci/trb.rs | 4 +- 8 files changed, 503 insertions(+), 485 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 1a3e35e03b..4077bdb912 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -25,7 +25,11 @@ use syscall::io::Io; use crate::xhci::{InterruptMethod, Xhci}; -mod driver_interface; +// Declare as pub so that no warnings appear due to parts of the interface code not being used by +// the driver. Since there's also a dedicated crate for the driver interface, those warnings don't +// mean anything. +pub mod driver_interface; + mod usb; mod xhci; @@ -181,7 +185,7 @@ fn main() { table_entry_pointer.msg_data.write(msg_data); table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - (Some(interrupt_handle), InterruptMethod::MsiX(info)) + (Some(interrupt_handle), InterruptMethod::MsiX(Mutex::new(info))) } } else if pci_config.func.legacy_interrupt_pin.is_some() { // legacy INTx# interrupt pins. @@ -212,8 +216,9 @@ fn main() { File::from_raw_fd(socket_fd as RawFd) })); - let hci = Arc::new(Xhci::new(name, address, interrupt_method, irq_file.as_mut(), pcid_handle).expect("xhcid: failed to allocate device")); - hci.probe().expect("xhcid: failed to probe"); + let hci = Arc::new(Xhci::new(name, address, interrupt_method, pcid_handle).expect("xhcid: failed to allocate device")); + xhci::start_irq_reactor(&hci, irq_file); + futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); let mut event_queue = EventQueue::<()>::new().expect("xhcid: failed to create event queue"); @@ -223,49 +228,12 @@ fn main() { let todo = Arc::new(Mutex::new(Vec::::new())); let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); - if let Some(irq_file) = irq_file { - let hci_irq = hci.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add(irq_file.as_raw_fd(), move |_| -> io::Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - - let hci = hci_irq.lock().unwrap(); - let socket = socket_irq.lock().unwrap(); - let todo = todo_irq.lock().unwrap(); - - if hci.received_irq() { - hci.on_irq(); - - irq_file.write(&mut irq)?; - - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - hci.handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket.write(&todo[i])?; - todo.remove(i); - } - } - } - - Ok(None) - }) - .expect("xhcid: failed to catch events on IRQ file"); - } - let socket_fd = socket.lock().unwrap().as_raw_fd(); let socket_packet = socket.clone(); event_queue .add(socket_fd, move |_| -> io::Result> { let mut socket = socket_packet.lock().unwrap(); - let mut hci = hci.lock().unwrap(); + let mut hci = hci; let mut todo = todo.lock().unwrap(); loop { diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 98750bc12c..4ec7b10a15 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -56,13 +56,13 @@ impl CapabilityRegs { ((self.hcc_params1.read() & HCC_PARAMS1_XECP_MASK) >> HCC_PARAMS1_XECP_SHIFT) as u16 } pub fn max_scratchpad_bufs_lo(&self) -> u8 { - ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) as u8 } pub fn spr(&self) -> bool { self.hcs_params2.readf(HCS_PARAMS2_SPR_BIT) } pub fn max_scratchpad_bufs_hi(&self) -> u8 { - ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) as u8 } pub fn max_scratchpad_bufs(&self) -> u16 { u16::from(self.max_scratchpad_bufs_lo()) diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index f3eb970737..1093a6e250 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -161,7 +161,6 @@ impl StreamContextArray { } #[repr(packed)] -#[derive(Clone, Debug)] pub struct ScratchpadBufferEntry { pub value: Mmio, } @@ -179,21 +178,20 @@ impl ScratchpadBufferArray { pub fn new(entries: u16) -> Result { let mut entries = unsafe { Dma::zeroed_unsized(entries as usize)? }; - let pages = entries.iter_mut().map(|entry| { - // TODO: When a better memory allocation API arrives (like the `mem:` scheme which I think is - // being worked on), no assumptions about the page size always being 4k will have to be - // made. - let pointer = syscall::physalloc(4096); + let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result { + // TODO: Get the page size using fstatvfs on the `memory:` scheme. + let pointer = syscall::physalloc(4096)?; assert_eq!(pointer & 0xFFFF_FFFF_FFFF_F000, pointer, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); - entry.set_addr(pointer); - }); + entry.set_addr(pointer as u64); + Ok(pointer) + }).collect::, _>>()?; Ok(Self { entries, pages, }) } - pub fn register(&self) -> u64 { + pub fn register(&self) -> usize { self.entries.physical() } } diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 4d808f6f30..977fa56584 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::fs::File; use std::future::Future; +use std::io::prelude::*; use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::sync::atomic::{self, AtomicUsize}; @@ -8,6 +9,7 @@ use std::{mem, task, thread}; use crossbeam_channel::{Sender, Receiver}; use futures::Stream; +use syscall::Io; use super::Xhci; use super::ring::Ring; @@ -31,10 +33,19 @@ pub struct NextEventTrb { // indexed using this struct instead. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct RingId { - pub slot: u8, + pub port: u8, pub endpoint_num: u8, pub stream_id: u16, } +impl RingId { + pub const fn default_control_pipe(port: u8) -> Self { + Self { + port, + endpoint_num: 0, + stream_id: 0, + } + } +} /// The state specific to a TRB-type. Since some of the event TDs may asynchronously appear, for /// example the Command Completion Event and the Transfer Event TDs, they have to be @@ -52,10 +63,10 @@ pub enum StateKind { impl StateKind { pub fn trb_type(&self) -> TrbType { - match self.kind { - Self::CommandCompletion { .. } => TrbType::CommandCompletion, - Self::Transfer { .. } => TrbType::Transfer, - Self::Other(ty) => ty, + match self { + &Self::CommandCompletion { .. } => TrbType::CommandCompletion, + &Self::Transfer { .. } => TrbType::Transfer, + &Self::Other(ty) => ty, } } } @@ -63,7 +74,6 @@ impl StateKind { pub struct IrqReactor { hci: Arc, - current_count: Arc, irq_file: Option, receiver: Receiver, @@ -75,18 +85,13 @@ pub struct IrqReactor { pub type NewPendingTrb = State; -pub fn start_irq_reactor(hci: Arc, irq_file: Option) -> thread::JoinHandle<()> { - thread::spawn(move || { - IrqReactor::new(hci, irq_file).run() - }) -} - impl IrqReactor { - pub fn new(hci: Arc, irq_file: Option) -> Self { + pub fn new(hci: Arc, receiver: Receiver, irq_file: Option) -> Self { Self { hci, irq_file, - current_count: Arc::new(AtomicUsize::new()), + receiver, + states: Vec::new(), } } // TODO: Configure the amount of time to be awaited when no more work can be done. @@ -97,30 +102,31 @@ impl IrqReactor { loop { self.handle_requests(); - let index = self.hci.primary_event_ring.lock().unwrap().next_index(); + let index = self.hci.primary_event_ring.lock().unwrap().ring.next_index(); let mut trb; 'busy_waiting: loop { - trb = self.hci.primary_event_ring.lock().unwrap().trbs[index]; + trb = self.hci.primary_event_ring.lock().unwrap().ring.trbs[index]; if trb.completion_code() == TrbCompletionCode::Invalid as u8 { self.pause(); continue 'busy_waiting; } } + if self.check_event_ring_full(&trb) { continue } self.acknowledge(trb); self.update_erdp(); } } fn run_with_irq_file(mut self) { + let irq_file = self.irq_file.as_mut().expect("Calling IrqReactor::run_with_irq_file without the IRQ file being None"); + 'event_loop: loop { self.handle_requests(); - let irq_file = self.irq_file.as_mut().unwrap(); - let mut buffer = [0u8; 8]; - let bytes_read = self.irq_file.read(&mut buffer).expect("Failed to read from irq scheme"); + let bytes_read = irq_file.read(&mut buffer).expect("Failed to read from irq scheme"); if bytes_read < mem::size_of::() { panic!("wrong number of bytes read from `irq:`: expected {}, got {}", mem::size_of::(), bytes_read); } @@ -129,30 +135,38 @@ impl IrqReactor { continue; } - let _ = self.irq_file.write(&buffer); + let _ = irq_file.write(&buffer); // TODO: More event rings, probably even with different IRQs. let event_ring = self.hci.primary_event_ring.lock().unwrap(); - let trb = event_ring.next(); - if trb.completion_code() == TrbCompletionCode::Invalid as u8 { - println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt."); - continue 'event_loop; + let mut count = 0; + + 'trb_loop: loop { + let trb = event_ring.next(); + + if trb.completion_code() == TrbCompletionCode::Invalid as u8 { + if count == 0 { println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } + continue 'event_loop; + } else { count += 1 } + + if self.check_event_ring_full(trb) { + continue 'trb_loop; + } + self.acknowledge(*trb); + trb.reserved(false); + + self.update_erdp(); } - - self.acknowledge(*trb); - trb.reserved(false); - - self.update_erdp(); } } fn update_erdp(&self) { - let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().register(); + let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().erdp(); let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); - self.xhci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); + self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); } fn handle_requests(&mut self) { self.states.extend(self.receiver.try_iter()); @@ -163,11 +177,11 @@ impl IrqReactor { loop { match self.states[index].kind { StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => if trb.completion_trb_pointer() == Some(phys_ptr) { - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event // be fetched before removing this event TRB from the queue. - let command_trb = match self.hci.command_ring.lock().unwrap().ring.phys_addr_to_entry_mut(phys_ptr) { + let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(phys_ptr) { Some(command_trb) => { let t = command_trb.clone(); command_trb.reserved(false); @@ -181,7 +195,7 @@ impl IrqReactor { // TODO: Validate the command TRB. *state.message.lock().unwrap() = Some(NextEventTrb { - src_trb: command_trb.clone(), + src_trb: Some(command_trb.clone()), event_trb: trb, }); @@ -194,13 +208,13 @@ impl IrqReactor { continue; } - StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = self.xhc.lock().unwrap().get_transfer_trb(trb.transfer_event_trb_pointer(), ring_id) { + StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = trb.transfer_event_trb_pointer().map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)).flatten() { if trb.transfer_event_trb_pointer() == Some(phys_ptr) { // Give the source transfer TRB together with the event TRB, to the future. - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); *state.message.lock().unwrap() = Some(NextEventTrb { - src_trb, + src_trb: Some(src_trb), event_trb: trb, }); state.waker.wake(); @@ -225,7 +239,7 @@ impl IrqReactor { } else { continue } StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => { - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); state.waker.wake(); } @@ -239,7 +253,7 @@ impl IrqReactor { } } } - pub fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { + fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { let mut index = 0; loop { @@ -250,7 +264,7 @@ impl IrqReactor { } continue; } - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); *state.message.lock().unwrap() = Some(NextEventTrb { event_trb: trb, src_trb: None, @@ -258,6 +272,23 @@ impl IrqReactor { state.waker.wake(); } } + /// Checks if an event TRB is a Host Controller Event, with the completion code Event Ring + /// Full. If so, it grows the event ring. The return value is whether the event ring was full, + /// and then grown. + fn check_event_ring_full(&mut self, event_trb: &Trb) -> bool { + let had_event_ring_full_error = event_trb.trb_type() == TrbType::HostController as u8 && event_trb.completion_code() == TrbCompletionCode::EventRingFull as u8; + + if had_event_ring_full_error { + self.grow_event_ring(); + } + had_event_ring_full_error + } + /// Grows the event ring + fn grow_event_ring(&mut self) { + // TODO + println!("TODO: grow event ring"); + } + pub fn run(mut self) { if self.irq_file.is_some() { self.run_with_irq_file(); @@ -291,7 +322,7 @@ impl Future for EventTrbFuture { sender.send(State { message: Arc::clone(&state.message), is_isoch_or_vf: state.is_isoch_or_vf, - state_kind: state.state_kind, + kind: state.state_kind, waker: context.waker().clone(), }).expect("IRQ reactor thread unexpectedly stopped"); @@ -304,12 +335,12 @@ impl Future for EventTrbFuture { impl Xhci { pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option { - self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)) + self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)).flatten() } - pub fn with_ring T>(&self, id: RingId, function: F) -> T { + pub fn with_ring T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; - let slot_state = self.slot_states.get(&id.slot)?; + let slot_state = self.port_states.get(&(id.port as usize))?; let endpoint_state = slot_state.endpoint_states.get(&id.endpoint_num)?; let ring_ref = match endpoint_state.transfer { @@ -317,12 +348,12 @@ impl Xhci { RingOrStreams::Streams(ref ctx_arr) => ctx_arr.rings.get(&id.stream_id)?, }; - function(ring_ref) + Some(function(ring_ref)) } - pub fn with_ring_mut T>(&self, id: RingId, function: F) -> T { + pub fn with_ring_mut T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; - let slot_state = self.slot_states.get(&id.slot)?; + let slot_state = self.port_states.get(&(id.port as usize))?; let endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; let ring_ref = match endpoint_state.transfer { @@ -330,7 +361,7 @@ impl Xhci { RingOrStreams::Streams(ref mut ctx_arr) => ctx_arr.rings.get_mut(&id.stream_id)?, }; - function(ring_ref) + Some(function(ring_ref)) } pub fn next_transfer_event_trb(&self, ring_id: RingId, trb: &Trb) -> impl Future + Send + Sync + 'static { if ! trb.is_transfer_trb() { @@ -344,7 +375,7 @@ impl Xhci { is_isoch_or_vf, state_kind: StateKind::Transfer { ring_id, - phys_ptr: self.with_ring(ring_id, |ring| ring.trb_phys_ptr(trb)/*.expect("Invalid TRB: transfer TRB wasn't in the ring specified. Only direct references to the TRBs of a ring can be used (ring address range: {:p}-{:p}).", ring.start_addr(), ring.end_addr())*/), + phys_ptr: self.with_ring(ring_id, |ring| ring.trb_phys_ptr(trb)).unwrap(), }, message: Arc::new(Mutex::new(None)), }, @@ -363,7 +394,7 @@ impl Xhci { // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). is_isoch_or_vf: false, state_kind: StateKind::CommandCompletion { - phys_ptr: command_ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb) + phys_ptr: command_ring.trb_phys_ptr(trb), }, message: Arc::new(Mutex::new(None)), }, @@ -379,7 +410,7 @@ impl Xhci { TrbType::DeviceNotification as u8, TrbType::MfindexWrap as u8, ]; - if ! valid_trb_types.contains(&trb_type) { + if ! valid_trb_types.contains(&(trb_type as u8)) { panic!("Invalid TRB type given to next_misc_event_trb(): {:?}. Only event TRB types that are neither transfer events or command completion events can be used.", trb_type) } EventTrbFuture::Pending { @@ -391,4 +422,5 @@ impl Xhci { sender: self.irq_reactor_sender.clone(), } } + } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 3970677053..e2da2a887a 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -4,13 +4,16 @@ use std::fs::File; use std::future::Future; use std::pin::Pin; use std::ptr::NonNull; -use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak}; +use std::sync::{Arc, Mutex, MutexGuard, Weak}; +use std::sync::atomic::{AtomicBool, AtomicUsize}; + use std::{mem, process, slice, sync::atomic, task, thread}; use chashmap::CHashMap; -use crossbeam_channel::Sender; +use crossbeam_channel::{Receiver, Sender}; use serde::Deserialize; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT}; +use syscall::flag::O_RDONLY; use syscall::io::{Dma, Io}; use crate::usb; @@ -34,14 +37,14 @@ mod trb; use self::capability::CapabilityRegs; use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray}; use self::doorbell::Doorbell; -use self::irq_reactor::NewPendingTrb; +use self::irq_reactor::{IrqReactor, NewPendingTrb, RingId}; use self::event::EventRing; use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; use self::operational::OperationalRegs; use self::port::Port; use self::ring::Ring; use self::runtime::{Interrupter, RuntimeRegs}; -use self::trb::{TransferKind, TrbCompletionCode, TrbType}; +use self::trb::{TransferKind, Trb, TrbCompletionCode, TrbType}; use self::scheme::EndpIfState; @@ -88,70 +91,61 @@ impl MsixInfo { } } -struct Device<'a> { - ring: &'a mut Ring, - cmd: &'a mut Ring, - db: &'a mut Doorbell, - int: &'a mut Interrupter, -} - -impl<'a> Device<'a> { - fn get_desc(&mut self, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) { +impl Xhci { + /// Gets descriptors, before the port state is initiated. + async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, ring: &mut Ring, desc: &mut Dma) -> Result<()> { let len = mem::size_of::(); - { - let (cmd, cycle) = self.ring.next(); + let future = { + let (cmd, cycle) = ring.next(); cmd.setup( usb::Setup::get_descriptor(kind, index, 0, len as u16), TransferKind::In, cycle, ); - } - { - let (cmd, cycle) = self.ring.next(); + let (cmd, cycle) = ring.next(); cmd.data(desc.physical(), len as u16, true, cycle); - } - { - let (cmd, cycle) = self.ring.next(); - cmd.status(false, cycle); - } + let (cmd, cycle) = ring.next(); + cmd.status(0, true, true, false, false, cycle); - self.db.write(1); + self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &cmd) + }; - { - let event = self.cmd.next_event(); - // TODO: Replace polling here as well. - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - } + self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); - self.int.erdp.write(self.cmd.erdp() | (1 << 3)); + let trbs = future.await; + let event_trb = trbs.event_trb; + let status_trb = trbs.src_trb.unwrap(); + + self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; + + self.event_handler_finished(); + Ok(()) } - fn get_device(&mut self) -> Result { + async fn fetch_dev_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result { let mut desc = Dma::::zeroed()?; - self.get_desc(usb::DescriptorKind::Device, 0, &mut desc); + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, ring, &mut desc).await?; Ok(*desc) } - fn get_config(&mut self, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { + async fn fetch_config_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc(usb::DescriptorKind::Configuration, config, &mut desc); + self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, ring, &mut desc).await?; Ok(*desc) } - fn get_bos(&mut self) -> Result<(usb::BosDescriptor, [u8; 4087])> { + async fn fetch_bos_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result<(usb::BosDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc(usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc); + self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, ring, &mut desc).await?; Ok(*desc) } - fn get_string(&mut self, index: u8) -> Result { + async fn fetch_string_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; - self.get_desc(usb::DescriptorKind::String, index, &mut sdesc); + self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, ring, &mut sdesc).await?; let len = sdesc.0 as usize; if len > 2 { @@ -165,6 +159,7 @@ impl<'a> Device<'a> { pub struct Xhci { // immutable cap: &'static CapabilityRegs, + page_size: usize, // XXX: It would be really useful to be able to mutably access individual elements of a slice, // without having to wrap every element in a lock (which wouldn't work since they're packed). @@ -183,7 +178,7 @@ pub struct Xhci { base: *const u8, handles: CHashMap, - next_handle: usize, + next_handle: AtomicUsize, port_states: CHashMap, drivers: CHashMap, @@ -191,16 +186,25 @@ pub struct Xhci { interrupt_method: InterruptMethod, pcid_handle: Mutex, - irq_reactor: Option>, + + irq_reactor: Mutex>>, + irq_reactor_sender: Sender, + + // not used, but still stored so that the thread, when created, can get the channel without the + // channel being in a mutex. + irq_reactor_receiver: Receiver, } +unsafe impl Send for Xhci {} +unsafe impl Sync for Xhci {} + struct PortState { slot: u8, cfg_idx: Option, if_idx: Option, input_context: Mutex>, - dev_desc: DevDesc, + dev_desc: Option, endpoint_states: BTreeMap, } @@ -227,6 +231,13 @@ impl Xhci { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); + let page_size = { + let memory_fd = syscall::open("memory:", O_RDONLY)?; + let mut stat = syscall::data::StatVfs::default(); + syscall::fstatvfs(memory_fd, &mut stat)?; + stat.f_bsize as usize + }; + let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; println!(" - OP {:X}", op_base); @@ -276,25 +287,42 @@ impl Xhci { let run = unsafe { &mut *(run_base as *mut RuntimeRegs) }; println!(" - RUNTIME {:X}", run_base); - let mut xhci = Xhci { - base: address as *const u8, - cap, - op, - ports, - dbs, - run, - dev_ctx: DeviceContextList::new(max_slots)?, - cmd: Ring::new(), - primary_event_ring: EventRing::new(), - handles: BTreeMap::new(), - next_handle: 0, - port_states: BTreeMap::new(), + // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the + // DMA allocation (which is at least a 4k page). + let entries_per_page = page_size / mem::size_of::(); + let cmd = Ring::new(entries_per_page, true)?; - drivers: BTreeMap::new(), + let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); + + let mut xhci = Self { + base: address as *const u8, + + cap, + page_size, + + op: Mutex::new(op), + ports: Mutex::new(ports), + dbs: Mutex::new(dbs), + run: Mutex::new(run), + + dev_ctx: DeviceContextList::new(max_slots)?, + scratchpad_buf_arr: None, // initialized in init() + + cmd: Mutex::new(cmd), + primary_event_ring: Mutex::new(EventRing::new()?), + handles: CHashMap::new(), + next_handle: AtomicUsize::new(0), + port_states: CHashMap::new(), + + drivers: CHashMap::new(), scheme_name, interrupt_method, pcid_handle: Mutex::new(pcid_handle), + + irq_reactor: Mutex::new(None), + irq_reactor_sender, + irq_reactor_receiver, }; xhci.init(max_slots); @@ -302,37 +330,37 @@ impl Xhci { Ok(xhci) } - pub fn init(&mut self, max_slots: u8) { + pub fn init(&mut self, max_slots: u8) -> Result<()> { // Set enabled slots println!(" - Set enabled slots to {}", max_slots); - self.op.get_mut().config.write(max_slots as u32); - println!(" - Enabled Slots: {}", self.op.get_mut().config.read() & 0xFF); + self.op.get_mut().unwrap().config.write(max_slots as u32); + println!(" - Enabled Slots: {}", self.op.get_mut().unwrap().config.read() & 0xFF); // Set device context address array pointer let dcbaap = self.dev_ctx.dcbaap(); println!(" - Write DCBAAP: {:X}", dcbaap); - self.op.get_mut().dcbaap.write(dcbaap as u64); + self.op.get_mut().unwrap().dcbaap.write(dcbaap as u64); // Set command ring control register - let crcr = self.cmd.get_mut().register(); + let crcr = self.cmd.get_mut().unwrap().register(); assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); println!(" - Write CRCR: {:X}", crcr); - self.op.get_mut().crcr.write(crcr as u64); + self.op.get_mut().unwrap().crcr.write(crcr as u64); // Set event ring segment table registers - println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); + println!(" - Interrupter 0: {:X}", self.run.get_mut().unwrap().ints.as_ptr() as usize); { - let int = &mut self.run.get_mut().ints[0]; + let int = &mut self.run.get_mut().unwrap().ints[0]; let erstz = 1; println!(" - Write ERSTZ: {}", erstz); int.erstsz.write(erstz); - let erdp = self.primary_event_ring.get_mut().erdp(); + let erdp = self.primary_event_ring.get_mut().unwrap().erdp() | (!1); println!(" - Write ERDP: {:X}", erdp); int.erdp.write(erdp as u64 | (1 << 3)); - let erstba = self.primary_event_ring.get_mut().erstba(); + let erstba = self.primary_event_ring.get_mut().unwrap().erstba(); println!(" - Write ERSTBA: {:X}", erstba); int.erstba.write(erstba as u64); @@ -343,49 +371,66 @@ impl Xhci { int.iman.writef(1 << 1, true); } - self.op.get_mut().usb_cmd.writef(1 << 2, true); + self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true); // Setup the scratchpad buffers that are required for the xHC to function. - self.setup_scratchpads(); + self.setup_scratchpads()?; // Set run/stop to 1 println!(" - Start"); - self.op.get_mut().usb_cmd.writef(1, true); + self.op.get_mut().unwrap().usb_cmd.writef(1, true); // Wait until controller is running println!(" - Wait for running"); - while self.op.get_mut().usb_sts.readf(1) { + while self.op.get_mut().unwrap().usb_sts.readf(1) { println!(" - Waiting for XHCI running"); } - println!("IP={}", self.run.get_mut().ints[0].iman.readf(1)); + println!("IP={}", self.run.get_mut().unwrap().ints[0].iman.readf(1)); // Ring command doorbell println!(" - Ring doorbell"); - self.dbs.get_mut()[0].write(0); + self.dbs.get_mut().unwrap()[0].write(0); println!(" - XHCI initialized"); + + if self.cap.cic() { + self.op.lock().unwrap().set_cie(true); + } + + Ok(()) } pub fn setup_scratchpads(&mut self) -> Result<()> { let buf_count = self.cap.max_scratchpad_bufs(); if buf_count == 0 { - return; + return Ok(()); } - self.scratchpad_buf_arr = Some(ScratchpadBufferArray::new(buf_count)?); - self.dev_ctx.dcbaa[0] = self.scratchpad_buf_arr.register(); + let scratchpad_buf_arr = ScratchpadBufferArray::new(buf_count)?; + self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; + self.scratchpad_buf_arr = Some(scratchpad_buf_arr); + + Ok(()) } - pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result { + pub async fn enable_port_slot(&mut self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); - let cloned_event_trb = - self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(slot_ty, cycle))?; - Ok(cloned_event_trb.event_slot()) + let (event_trb, command_trb) = + self.execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)).await; + + self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb); + self.event_handler_finished(); + + Ok(event_trb.event_slot()) } - pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> { - self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.disable_slot(slot, cycle))?; + pub async fn disable_port_slot(&mut self, slot: u8) -> Result<()> { + let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)).await; + + self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb); + self.event_handler_finished(); + Ok(()) } @@ -415,29 +460,19 @@ impl Xhci { .supported_protocol(i as u8) .expect("Failed to find supported protocol information for port") .proto_slot_ty(); - let slot = self.enable_port_slot(slot_ty)?; + let slot = self.enable_port_slot(slot_ty).await?; println!(" - Slot {}", slot); let mut input = Dma::::zeroed()?; let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; - let dev_desc = Self::get_dev_desc_raw( - &mut *self.ports.lock().unwrap(), - &mut *self.run.lock().unwrap(), - &mut *self.cmd.lock().unwrap(), - &mut *self.dbs.lock().unwrap(), - i, - slot, - &mut ring, - )?; - - self.update_default_control_pipe(&mut input, slot, &dev_desc)?; + // TODO: Should the descriptors be cached in PortState, or refetched? let mut port_state = PortState { slot, input_context: Mutex::new(input), - dev_desc, + dev_desc: None, cfg_idx: None, if_idx: None, endpoint_states: std::iter::once(( @@ -450,9 +485,9 @@ impl Xhci { .collect::>(), }; - if self.cap.cic() { - self.op.lock().unwrap().set_cie(true); - } + let dev_desc = self.get_desc(i, slot, &mut ring).await?; + port_state.dev_desc = Some(dev_desc); + self.update_default_control_pipe(&mut input, slot, &dev_desc).await?; /*match self.spawn_drivers(i, &mut port_state) { Ok(()) => (), @@ -466,7 +501,7 @@ impl Xhci { Ok(()) } - pub fn update_default_control_pipe( + pub async fn update_default_control_pipe( &mut self, input_context: &mut Dma, slot_id: u8, @@ -486,9 +521,13 @@ impl Xhci { b |= (new_max_packet_size) << 16; endp_ctx.b.write(b); - self.execute_command("EVALUATE_CONTEXT", |trb, cycle| { + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) - })?; + }).await; + + self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb); + self.event_handler_finished(); + Ok(()) } @@ -598,15 +637,16 @@ impl Xhci { pub fn uses_msix(&self) -> bool { if let InterruptMethod::MsiX(_) = self.interrupt_method { true } else { false } } - pub fn msix_info(&self) -> Option<&MsixInfo> { + // TODO: Perhaps use an rwlock? + pub fn msix_info(&self) -> Option> { match self.interrupt_method { - InterruptMethod::MsiX(ref info) => Some(info), + InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), _ => None, } } - pub fn msix_info_mut(&mut self) -> Option<&mut MsixInfo> { + pub fn msix_info_mut(&mut self) -> Option> { match self.interrupt_method { - InterruptMethod::MsiX(ref mut info) => Some(info), + InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), _ => None, } } @@ -614,18 +654,20 @@ impl Xhci { /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always /// true when using MSI/MSI-X. pub fn received_irq(&mut self) -> bool { + let runtime_regs = self.run.lock().unwrap(); + if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. - println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", self.run.ints[0].iman.readf(1), self.run.ints[0].erdp.readf(3)); + println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); println!("MSI-X PB={}", self.msix_info_mut().unwrap().pba(0)); let entry = self.msix_info_mut().unwrap().table_entry_pointer(0); println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); true - } else if self.run.ints[0].iman.readf(1) { + } else if runtime_regs.ints[0].iman.readf(1) { // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is // a special register to specify whether the IRQ actually came from the xHC. - self.run.ints[0].iman.writef(1, true); + runtime_regs.ints[0].iman.writef(1, true); // The interrupt came from the xHC. true @@ -634,8 +676,6 @@ impl Xhci { false } - } - pub fn on_irq(&mut self) { } fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> { // TODO: There should probably be a way to select alternate interfaces, and not just the @@ -645,12 +685,14 @@ impl Xhci { let ifdesc = &ps .dev_desc + .as_ref().unwrap() .config_descs .first() .ok_or(Error::new(EBADF))? .interface_descs .first() .ok_or(Error::new(EBADF))?; + let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| { @@ -787,6 +829,15 @@ impl Xhci { .find(|speed| speed.psiv() == psiv) } } +pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { + let receiver = hci.irq_reactor_receiver.clone(); + let hci_clone = Arc::clone(&hci); + + *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { + IrqReactor::new(hci_clone, receiver, irq_file).run() + })); +} + #[derive(Deserialize)] struct DriverConfig { name: String, diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index 26d0433277..2e067efce3 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -64,9 +64,10 @@ impl Ring { /// /// # Panics /// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB. + // TODO: Use usize instead of u64. pub fn phys_addr_to_index(&self, paddr: u64) -> Option { let base = self.trbs.physical(); - let offset = paddr.checked_sub(base)?; + let offset = paddr.checked_sub(base as u64)? as usize; assert_eq!(offset % mem::size_of::(), 0, "unaligned TRB physical address"); @@ -79,29 +80,29 @@ impl Ring { Some(index) } pub fn phys_addr_to_entry_ref(&self, paddr: u64) -> Option<&Trb> { - &self.trbs[self.phys_addr_to_index(paddr)] + Some(&self.trbs[self.phys_addr_to_index(paddr)?]) } pub fn phys_addr_to_entry_mut(&self, paddr: u64) -> Option<&mut Trb> { - &mut self.trbs[self.phys_addr_to_index(paddr)] + Some(&mut self.trbs[self.phys_addr_to_index(paddr)?]) } pub fn phys_addr_to_entry(&self, paddr: u64) -> Option { - self.trbs[self.phys_addr_to_index(paddr)].clone() + Some(self.trbs[self.phys_addr_to_index(paddr)?].clone()) } pub(crate) fn start_virt_addr(&self) -> *const Trb { self.trbs.as_ptr() } pub(crate) fn end_virt_addr(&self) -> *const Trb { - unsafe { self.start_virt_addr().offset(self.trbs.len()) } + unsafe { self.start_virt_addr().offset(self.trbs.len() as isize) } } pub fn trb_phys_ptr(&self, trb: &Trb) -> u64 { let trb_virt_pointer = trb as *const Trb; let trbs_base_virt_pointer = self.trbs.as_ptr(); - if trb_virt_pointer < trbs_base_virt_pointer || trb_virt_pointer > trbs_base_virt_pointer + self.trbs.len() * mem::size_of::() { + if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) || (trb_virt_pointer as usize) > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::() { panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb); } - let trbs_base_phys_ptr = self.trbs.physical(); - let trb_phys_ptr = trb_virt_pointer - trbs_base_phys_ptr; + let trbs_base_phys_ptr = self.trbs.physical() as u64; + let trb_phys_ptr = trb_virt_pointer as u64 - trbs_base_phys_ptr; trb_phys_ptr } /* diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c96d3d9c08..3ecc690cae 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,7 +1,9 @@ use std::convert::TryFrom; use std::io::prelude::*; +use std::sync::atomic; use std::{cmp, io, mem, path, str}; +use futures::executor::block_on; use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; @@ -15,7 +17,7 @@ use syscall::{ }; use super::{port, usb}; -use super::{Device, EndpointState, Xhci}; +use super::{EndpointState, Xhci}; use super::context::{ InputContext, SlotState, StreamContext, StreamContextArray, StreamContextType, @@ -23,6 +25,7 @@ use super::context::{ }; use super::doorbell::Doorbell; use super::extended::ProtocolSpeed; +use super::irq_reactor::RingId; use super::operational::OperationalRegs; use super::ring::Ring; use super::runtime::RuntimeRegs; @@ -139,31 +142,6 @@ impl From for SuperSpeedPlusIsochCmp { } } -impl IfDesc { - fn new( - dev: &mut Device, - desc: usb::InterfaceDescriptor, - endps: impl IntoIterator, - hid_descs: impl IntoIterator, - ) -> Result { - Ok(Self { - alternate_setting: desc.alternate_setting, - class: desc.class, - interface_str: if desc.interface_str > 0 { - Some(dev.get_string(desc.interface_str)?) - } else { - None - }, - kind: desc.kind, - number: desc.number, - protocol: desc.protocol, - sub_class: desc.sub_class, - endpoints: endps.into_iter().collect(), - hid_descs: hid_descs.into_iter().collect(), - }) - } -} - /// Any descriptor that can be stored in the config desc "data" area. #[derive(Debug)] pub enum AnyDescriptor { @@ -210,8 +188,35 @@ impl AnyDescriptor { } impl Xhci { + async fn new_if_desc( + &self, + port_id: usize, + slot: u8, + ring: &mut Ring, + desc: usb::InterfaceDescriptor, + endps: impl IntoIterator, + hid_descs: impl IntoIterator, + ) -> Result { + Ok(IfDesc { + alternate_setting: desc.alternate_setting, + class: desc.class, + interface_str: if desc.interface_str > 0 { + Some(self.fetch_string_desc(port_id, slot, ring, desc.interface_str).await?) + } else { + None + }, + kind: desc.kind, + number: desc.number, + protocol: desc.protocol, + sub_class: desc.sub_class, + endpoints: endps.into_iter().collect(), + hid_descs: hid_descs.into_iter().collect(), + }) + } pub fn execute_command_noreply(&self, f: F) { - let (cmd, cycle) = self.cmd.lock().unwrap(); + let command_ring = self.cmd.lock().unwrap(); + + let (cmd, cycle) = command_ring.next(); f(cmd, cycle); self.dbs.lock().unwrap()[0].write(0); @@ -243,7 +248,7 @@ impl Xhci { (event_trb, command_trb) } - pub fn execute_control_transfer( + pub async fn execute_control_transfer( &mut self, port_num: usize, setup: usb::Setup, @@ -254,62 +259,60 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { - let slot = self.port_state(port_num)?.slot; - let ring = self - .endpoint_state_mut(port_num, 0)? - .ring() - .ok_or(Error::new(EIO))?; + let port_state = self.port_state(port_num)?; + let slot = port_state.slot; + + let future = { + let endpoint_state = port_state + .endpoint_states + .get_mut(&0).ok_or(Error::new(EIO))?; + + let ring = endpoint_state + .ring() + .ok_or(Error::new(EIO))?; - { let (cmd, cycle) = ring.next(); cmd.setup(setup, tk, cycle); - } - if tk != TransferKind::NoData { - loop { - let (trb, cycle) = ring.next(); - match d(trb, cycle) { - ControlFlow::Break => break, - ControlFlow::Continue => continue, + + if tk != TransferKind::NoData { + loop { + let (trb, cycle) = ring.next(); + match d(trb, cycle) { + ControlFlow::Break => break, + ControlFlow::Continue => continue, + } } } - } - { + let (cmd, cycle) = ring.next(); - cmd.status(tk == TransferKind::In, cycle); - } - self.dbs[usize::from(slot)].write(Self::def_control_endp_doorbell()); - let cloned_trb = { - let event = self.cmd.next_event(); - while event.data.read() == 0 { - println!(" - {} Waiting for event", name); - } + let interrupter = 0; + let ioc = true; + let ch = false; + let ent = false; - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::Transfer as u8 - { - println!( - "{} CONTROL TRANSFER ERROR, EVENT TRB {:#0x} {:#0x} {:#0}»", - name, - event.data.read(), - event.status.read(), - event.control.read() - ); - } - event.reserved(false); - event.clone() + cmd.status(interrupter, tk == TransferKind::In, ioc, ch, ent, cycle); + self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), cmd) }; - self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); + self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); - Ok(cloned_trb) + let trbs = future.await; + let event_trb = trbs.event_trb; + let status_trb = trbs.src_trb.unwrap(); + + handle_transfer_event_trb("CONTROL_TRANSFER", &event_trb, &status_trb)?; + + self.event_handler_finished(); + + Ok(event_trb) } /// NOTE: There has to be AT LEAST one successful invocation of `d`, that actually updates the /// TRB (it could be a NO-OP in the worst case). /// The function is also required to set the Interrupt on Completion flag, or this function /// will never complete. pub async fn execute_transfer( - &mut self, + &self, port_num: usize, endp_num: u8, stream_id: u16, @@ -326,7 +329,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let slot = port_state.slot; let endp_state = port_state @@ -353,7 +356,7 @@ impl Xhci { match d(trb, cycle) { ControlFlow::Break => { - break self.next_transfer_event_trb(super::irq_reactor::RingId { slot, endpoint_num: endp_num, stream_id }, &trb); + break self.next_transfer_event_trb(super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, &trb); } ControlFlow::Continue => continue, } @@ -386,20 +389,20 @@ impl Xhci { Ok(event_trb) } - fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { + async fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { self.execute_control_transfer( port, req, TransferKind::NoData, "DEVICE_REQ_NO_DATA", |_, _| ControlFlow::Break, - )?; + ).await?; Ok(()) } - fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { - self.device_req_no_data(port, usb::Setup::set_configuration(config)) + async fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { + self.device_req_no_data(port, usb::Setup::set_configuration(config)).await } - fn set_interface( + async fn set_interface( &mut self, port: usize, interface_num: u8, @@ -408,7 +411,7 @@ impl Xhci { self.device_req_no_data( port, usb::Setup::set_interface(interface_num, alternate_setting), - ) + ).await } async fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { @@ -419,7 +422,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let slot = self @@ -534,7 +537,7 @@ impl Xhci { let (endp_desc_count, new_context_entries, configuration_value) = { let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let config_desc = port_state.dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; + let config_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; let endpoints = config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; @@ -588,7 +591,7 @@ impl Xhci { let endp_num = endp_idx + 1; let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let dev_desc = &port_state.dev_desc; + let dev_desc = port_state.dev_desc.as_ref().unwrap(); let endpoints = &dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; @@ -731,12 +734,12 @@ impl Xhci { handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; // Tell the device about this configuration. - self.set_configuration(port, configuration_value)?; + self.set_configuration(port, configuration_value).await?; if let (Some(interface_num), Some(alternate_setting)) = (req.interface_desc, req.alternate_setting) { - self.set_interface(port, interface_num, alternate_setting)?; + self.set_interface(port, interface_num, alternate_setting).await?; } Ok(()) @@ -747,28 +750,36 @@ impl Xhci { endp_idx: u8, buf: &mut [u8], ) -> Result<(u8, u32)> { + if buf.is_empty() { + return Err(Error::new(EINVAL)); + } + let dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(buf.len())? }; + + let (completion_code, bytes_transferred) = self.transfer( + port_num, + endp_idx, + Some(dma_buffer), + PortReqDirection::DeviceToHost, + ).await?; + + buf.copy_from_slice(&*dma_buffer.as_ref()); + Ok((completion_code, bytes_transferred)) + } + async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, sbuf: &[u8]) -> Result<(u8, u32)> { + if sbuf.is_empty() { + return Err(Error::new(EINVAL)); + } + let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; + dma_buffer.copy_from_slice(sbuf); + self.transfer( port_num, endp_idx, - if !buf.is_empty() { - DeviceReqData::In(buf) - } else { - DeviceReqData::NoData - }, + Some(dma_buffer), + PortReqDirection::HostToDevice, ).await } - async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> { - self.transfer( - port_num, - endp_idx, - if !buf.is_empty() { - DeviceReqData::Out(buf) - } else { - DeviceReqData::NoData - }, - ).await - } - const fn def_control_endp_doorbell() -> u32 { + pub const fn def_control_endp_doorbell() -> u32 { 1 } // TODO: Wrap DCIs and driver-level endp_num into distinct types, due to the high chance of @@ -794,39 +805,23 @@ impl Xhci { } // TODO: Rename DeviceReqData to something more general. async fn transfer( - &mut self, + &self, port_num: usize, endp_idx: u8, - mut buf: DeviceReqData, + dma_buf: Option>, + direction: PortReqDirection, ) -> Result<(u8, u32)> { // TODO: Check that only readable enpoints are read, etc. let endp_num = endp_idx + 1; - // TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc), - // UB. - let dma_buffer = match buf { - DeviceReqData::Out(sbuf) => { - if sbuf.is_empty() { - return Err(Error::new(EINVAL)); - } - let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; - dma_buffer.copy_from_slice(sbuf); - Some(dma_buffer) - } - DeviceReqData::In(ref dbuf) => { - if dbuf.is_empty() { - return Err(Error::new(EINVAL)); - } - Some(unsafe { Dma::<[u8]>::zeroed_unsized(dbuf.len()) }?) - } - DeviceReqData::NoData => None, - }; let port_state = self .port_states .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; + let endp_desc: &EndpDesc = port_state .dev_desc + .as_ref().unwrap() .config_descs .get(0) .ok_or(Error::new(EIO))? @@ -843,7 +838,7 @@ impl Xhci { return Err(Error::new(ENOSYS)); } - if EndpDirection::from(buf.direction()) != endp_desc.direction() { + if EndpDirection::from(direction) != endp_desc.direction() { return Err(Error::new(EBADF)); } @@ -852,23 +847,22 @@ impl Xhci { let (buffer, idt, estimated_td_size) = { let (buffer, idt) = - if buf.len() <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { - buf.map_buf(|sbuf| { + if dma_buf.map(|buf| buf.len()).unwrap_or(0) <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { + dma_buf.map(|sbuf| { let mut bytes = [0u8; 8]; - bytes[..buf.len()].copy_from_slice(&sbuf[..buf.len()]); - // FIXME: little endian, right? + bytes[..sbuf.len()].copy_from_slice(&sbuf); (u64::from_le_bytes(bytes), true) }) .unwrap_or((0, false)) } else { ( - dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, + dma_buf.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, false, ) }; let estimated_td_size = cmp::min( u8::try_from( - div_round_up(buf.len(), max_transfer_size as usize) * mem::size_of::(), + div_round_up(dma_buf.map(|buf| buf.len()).unwrap_or(0), max_transfer_size as usize) * mem::size_of::(), ) .ok() .unwrap_or(0x1F), @@ -879,7 +873,7 @@ impl Xhci { let stream_id = 1u16; - let mut bytes_left = buf.len(); + let mut bytes_left = dma_buf.map(|buf| buf.len()).unwrap_or(0); let event = self.execute_transfer( port_num, @@ -918,162 +912,120 @@ impl Xhci { ).await?; self.event_handler_finished(); - let bytes_transferred = buf.len() as u32 - event.transfer_length(); - - if let DeviceReqData::In(dbuf) = &mut buf { - dbuf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); - } + let bytes_transferred = dma_buf.map(|buf| buf.len() as u32 - event.transfer_length()).unwrap_or(0); Ok((event.completion_code(), bytes_transferred)) } - pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result { - let st = self - .port_states - .get_mut(&port_id) - .ok_or(Error::new(ENOENT))?; - let ports = self.ports.lock().unwrap(); - let run = self.run.lock().unwrap(); - let cmd = self.cmd.lock().unwrap(); - let dbs = self.dbs.lock().unwrap(); - - Self::get_dev_desc_raw( - &mut *ports, - &mut *run, - &mut *cmd, - &mut *dbs, - port_id, - st.slot, - st.endpoint_states - .get_mut(&0) - .ok_or(Error::new(EIO))? - .ring() - .ok_or(Error::new(EIO))?, - ) - } - pub(crate) fn get_dev_desc_raw( - ports: &mut [port::Port], - run: &mut RuntimeRegs, - cmd: &mut Ring, - dbs: &mut [Doorbell], + pub async fn get_desc( + &self, port_id: usize, slot: u8, ring: &mut Ring, ) -> Result { - let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; + let port = self.ports.lock().unwrap().get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } - // TODO: Should the descriptors be stored in PortState? - - run.ints[0].erdp.write(cmd.register() | (1 << 3)); - - let mut dev = Device { - ring, - cmd, - db: &mut dbs[slot as usize], - int: &mut run.ints[0], - }; - - let raw_dd = dev.get_device()?; + let raw_dd = self.fetch_dev_desc(port_id, slot, ring).await?; let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { - Some(dev.get_string(raw_dd.manufacturer_str)?) + Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.manufacturer_str).await?) } else { None }, if raw_dd.product_str > 0 { - Some(dev.get_string(raw_dd.product_str)?) + Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.product_str).await?) } else { None }, if raw_dd.serial_str > 0 { - Some(dev.get_string(raw_dd.serial_str)?) + Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.serial_str).await?) } else { None }, ); - let (bos_desc, bos_data) = dev.get_bos()?; + let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot, ring).await?; let supports_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); let supports_superspeedplus = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); - let config_descs = (0..raw_dd.configurations) - .map(|index| -> Result<_> { - let (desc, data) = dev.get_config(index)?; + let mut config_descs = SmallVec::new(); - let extra_length = desc.total_length as usize - mem::size_of_val(&desc); - let data = &data[..extra_length]; + for index in 0..raw_dd.configurations { + let (desc, data) = self.fetch_config_desc(port_id, slot, ring, index).await?; - let mut i = 0; - let mut descriptors = Vec::new(); + let extra_length = desc.total_length as usize - mem::size_of_val(&desc); + let data = &data[..extra_length]; - while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { - descriptors.push(descriptor); - i += len; - } + let mut i = 0; + let mut descriptors = Vec::new(); - let mut interface_descs = SmallVec::new(); - let mut iter = descriptors.into_iter(); + while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { + descriptors.push(descriptor); + i += len; + } - while let Some(item) = iter.next() { - if let AnyDescriptor::Interface(idesc) = item { - let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); - let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); + let mut interface_descs = SmallVec::new(); + let mut iter = descriptors.into_iter(); - for _ in 0..idesc.endpoints { + while let Some(item) = iter.next() { + if let AnyDescriptor::Interface(idesc) = item { + let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); + let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); + + for _ in 0..idesc.endpoints { + let next = match iter.next() { + Some(AnyDescriptor::Endpoint(n)) => n, + Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { + hid_descs.push(h.into()); + break; + } + _ => break, + }; + let mut endp = EndpDesc::from(next); + + if supports_superspeed { let next = match iter.next() { - Some(AnyDescriptor::Endpoint(n)) => n, - Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { - hid_descs.push(h.into()); - break; - } + Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, _ => break, }; - let mut endp = EndpDesc::from(next); + endp.ssc = Some(SuperSpeedCmp::from(next)); - if supports_superspeed { + if endp.has_ssp_companion() && supports_superspeedplus { let next = match iter.next() { - Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, + Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => n, _ => break, }; - endp.ssc = Some(SuperSpeedCmp::from(next)); - - if endp.has_ssp_companion() && supports_superspeedplus { - let next = match iter.next() { - Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => n, - _ => break, - }; - endp.sspc = Some(SuperSpeedPlusIsochCmp::from(next)); - } + endp.sspc = Some(SuperSpeedPlusIsochCmp::from(next)); } - endpoints.push(endp); } - - interface_descs.push(IfDesc::new(&mut dev, idesc, endpoints, hid_descs)?); - } else { - // TODO - break; + endpoints.push(endp); } - } - Ok(ConfDesc { - kind: desc.kind, - configuration: if desc.configuration_str > 0 { - Some(dev.get_string(desc.configuration_str)?) - } else { - None - }, - configuration_value: desc.configuration_value, - attributes: desc.attributes, - max_power: desc.max_power, - interface_descs, - }) - }) - .collect::>>()?; + interface_descs.push(self.new_if_desc(port_id, slot, ring, idesc, endpoints, hid_descs).await?); + } else { + // TODO + break; + } + } + + config_descs.push(ConfDesc { + kind: desc.kind, + configuration: if desc.configuration_str > 0 { + Some(self.fetch_string_desc(port_id, slot, ring, desc.configuration_str).await?) + } else { + None + }, + configuration_value: desc.configuration_value, + attributes: desc.attributes, + max_power: desc.max_power, + interface_descs, + }); + }; Ok(DevDesc { kind: raw_dd.kind, @@ -1108,7 +1060,7 @@ impl Xhci { bytes_to_read } - fn port_req_transfer( + async fn port_req_transfer( &mut self, port_num: usize, data_buffer: Option<&mut Dma<[u8]>>, @@ -1129,7 +1081,7 @@ impl Xhci { ); ControlFlow::Break }, - )?; + ).await?; Ok(()) } fn port_req_init_st(&mut self, port_num: usize, req: &PortReq) -> Result { @@ -1169,7 +1121,7 @@ impl Xhci { // FIXME: Make sure there aren't any other PortReq handles, perhaps by storing the state in // PortState? } - fn handle_port_req_write( + async fn handle_port_req_write( &mut self, fd: usize, port_num: usize, @@ -1184,7 +1136,7 @@ impl Xhci { if let PortReqState::TmpSetup(setup) = st { // No need for any additional reads or writes, before completing. - self.port_req_transfer(port_num, None, setup, TransferKind::NoData)?; + self.port_req_transfer(port_num, None, setup, TransferKind::NoData).await?; st = PortReqState::Init; } @@ -1196,7 +1148,7 @@ impl Xhci { } dma_buffer.copy_from_slice(buf); - self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::Out)?; + self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::Out).await?; st = PortReqState::Init; buf.len() @@ -1211,7 +1163,7 @@ impl Xhci { } Ok(bytes_written) } - fn handle_port_req_read( + async fn handle_port_req_read( &mut self, fd: usize, port_num: usize, @@ -1223,7 +1175,7 @@ impl Xhci { if buf.len() != dma_buffer.len() { return Err(Error::new(EINVAL)); } - self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::In)?; + self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::In).await?; buf.copy_from_slice(&dma_buffer); st = PortReqState::Init; @@ -1413,8 +1365,7 @@ impl SchemeMut for Xhci { _ => return Err(Error::new(ENOENT)), }; - let fd = self.next_handle; - self.next_handle += 1; + let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed); self.handles.insert(fd, handle); Ok(fd) @@ -1545,7 +1496,7 @@ impl SchemeMut 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 => self.on_read_endp_data(port_num, endp_num, buf), + EndpointHandleTy::Data => block_on(self.on_read_endp_data(port_num, endp_num, buf)), EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), }, &mut Handle::PortState(port_num, ref mut offset) => { @@ -1574,7 +1525,7 @@ impl SchemeMut for Xhci { } &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); - self.handle_port_req_read(fd, port_num, state, buf) + block_on(self.handle_port_req_read(fd, port_num, state, buf)) } } } @@ -1582,17 +1533,17 @@ impl SchemeMut for Xhci { let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { &mut Handle::ConfigureEndpoints(port_num) => { - self.configure_endpoints(port_num, buf)?; + block_on(self.configure_endpoints(port_num, buf))?; Ok(buf.len()) } &mut Handle::Endpoint(port_num, endp_num, ref ep_file_ty) => match ep_file_ty { - EndpointHandleTy::Ctl => self.on_write_endp_ctl(port_num, endp_num, buf), - EndpointHandleTy::Data => self.on_write_endp_data(port_num, endp_num, buf), + EndpointHandleTy::Ctl => block_on(self.on_write_endp_ctl(port_num, endp_num, buf)), + EndpointHandleTy::Data => block_on(self.on_write_endp_data(port_num, endp_num, buf)), EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), }, &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); - self.handle_port_req_write(fd, port_num, state, buf) + block_on(self.handle_port_req_write(fd, port_num, state, buf)) } // TODO: Introduce PortReqState::Waiting, which this write call changes to // PortReqState::ReadyToWrite when all bytes are written. @@ -1608,13 +1559,28 @@ impl SchemeMut for Xhci { } impl Xhci { pub fn get_endp_status(&mut self, port_num: usize, endp_num: u8) -> Result { - let slot = self + let port_state = self .port_states .get(&port_num) - .ok_or(Error::new(EBADFD))? - .slot; + .ok_or(Error::new(EBADFD))?; + + let slot = port_state.slot; + + let endp_desc = port_state + .dev_desc + .as_ref().unwrap() + .config_descs + .get(0) + .ok_or(Error::new(EIO))? + .interface_descs + .get(0) + .ok_or(Error::new(EIO))? + .endpoints + .get(endp_num as usize - 1) + .ok_or(Error::new(EBADFD))?; + let endp_num_xhc = if endp_num != 0 { - Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?) + Self::endp_num_to_dci(endp_num, endp_desc) } else { 1 }; @@ -1664,7 +1630,7 @@ impl Xhci { index: 0, // TODO: interface num length: 0, }, - )?; + ).await?; } Ok(()) } @@ -1676,6 +1642,7 @@ impl Xhci { let endp_desc = port_state .dev_desc + .as_ref().unwrap() .config_descs .get(0) .ok_or(Error::new(EIO))? @@ -1727,6 +1694,7 @@ impl Xhci { .get(&port_num) .ok_or(Error::new(EIO))? .dev_desc + .as_ref().unwrap() .config_descs .first() .ok_or(Error::new(EIO))? @@ -1755,7 +1723,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let (event_trb, command_trb) = self.execute_command(|trb, cycle| { @@ -1806,7 +1774,7 @@ impl Xhci { // Yield the result directly because no bytes have to be sent or received // beforehand. let (completion_code, bytes_transferred) = - self.transfer(port_num, endp_num - 1, DeviceReqData::NoData).await?; + self.transfer(port_num, endp_num - 1, None, PortReqDirection::DeviceToHost).await?; if bytes_transferred > 0 { return Err(Error::new(EIO)); } @@ -1853,7 +1821,7 @@ impl Xhci { bytes_transferred, } } - pub fn on_write_endp_data( + pub async fn on_write_endp_data( &mut self, port_num: usize, endp_num: u8, @@ -1874,7 +1842,7 @@ impl Xhci { return Err(Error::new(EINVAL)); } let (completion_code, some_bytes_transferred) = - self.transfer_write(port_num, endp_num - 1, buf)?; + self.transfer_write(port_num, endp_num - 1, buf).await?; let result = Self::transfer_result(completion_code, some_bytes_transferred); // To avoid having to read from the Ctl interface file, the client should stop @@ -1937,7 +1905,7 @@ impl Xhci { serde_json::to_writer(&mut cursor, &res).or(Err(Error::new(EIO)))?; Ok(cursor.seek(io::SeekFrom::Current(0)).unwrap() as usize) } - pub fn on_read_endp_data( + pub async fn on_read_endp_data( &mut self, port_num: usize, endp_num: u8, @@ -1962,7 +1930,7 @@ impl Xhci { } let (completion_code, some_bytes_transferred) = - self.transfer_read(port_num, endp_num - 1, buf)?; + self.transfer_read(port_num, endp_num - 1, buf).await?; // Just as with on_write_endp_data, a client issuing multiple reads must always // stop reading if one read returns fewer bytes than expected. @@ -2001,7 +1969,7 @@ impl Xhci { self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true); } } -fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { +pub fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { if event_trb.completion_code() == TrbCompletionCode::Success as u8 { Ok(()) } else { @@ -2009,7 +1977,7 @@ fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<() Err(Error::new(EIO)) } } -fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> { +pub fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> { if event_trb.completion_code() == TrbCompletionCode::Success as u8 || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 { Ok(()) } else { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index c23f543a38..1a91800bbf 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -374,10 +374,10 @@ impl Trb { ); } - pub fn status(&mut self, input: bool, cycle: bool) { + pub fn status(&mut self, interrupter: u16, input: bool, ioc: bool, ch: bool, ent: bool, cycle: bool) { self.set( 0, - 0, + u32::from(interrupter) << 22, ((input as u32) << 16) | ((TrbType::StatusStage as u32) << 10) | (1 << 5) From 078a929bfcc1c6f5b641592d72a927c1327b5b40 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 11:56:56 +0100 Subject: [PATCH 09/22] Fix borrow checker errors, except SchemeMut::handle. --- xhcid/src/main.rs | 1 - xhcid/src/xhci/context.rs | 5 +- xhcid/src/xhci/irq_reactor.rs | 71 ++++++----- xhcid/src/xhci/mod.rs | 40 ++++--- xhcid/src/xhci/ring.rs | 5 +- xhcid/src/xhci/scheme.rs | 214 +++++++++++++++++++--------------- 6 files changed, 187 insertions(+), 149 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 4077bdb912..37de0739a4 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -233,7 +233,6 @@ fn main() { event_queue .add(socket_fd, move |_| -> io::Result> { let mut socket = socket_packet.lock().unwrap(); - let mut hci = hci; let mut todo = todo.lock().unwrap(); loop { diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 1093a6e250..45023397cc 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -175,12 +175,11 @@ pub struct ScratchpadBufferArray { pub pages: Vec, } impl ScratchpadBufferArray { - pub fn new(entries: u16) -> Result { + pub fn new(page_size: usize, entries: u16) -> Result { let mut entries = unsafe { Dma::zeroed_unsized(entries as usize)? }; let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result { - // TODO: Get the page size using fstatvfs on the `memory:` scheme. - let pointer = syscall::physalloc(4096)?; + let pointer = unsafe { syscall::physalloc(page_size)? }; assert_eq!(pointer & 0xFFFF_FFFF_FFFF_F000, pointer, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); entry.set_addr(pointer as u64); Ok(pointer) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 977fa56584..7ab7b8f677 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -94,39 +94,44 @@ impl IrqReactor { states: Vec::new(), } } - // TODO: Configure the amount of time to be awaited when no more work can be done. + // TODO: Configure the amount of time wait when no more work can be done (for IRQ-less polling). fn pause(&self) { std::thread::yield_now(); } fn run_polling(mut self) { - loop { + let hci_clone = Arc::clone(&self.hci); + + 'event_loop: loop { self.handle_requests(); - let index = self.hci.primary_event_ring.lock().unwrap().ring.next_index(); + let mut event_ring_guard = hci_clone.primary_event_ring.lock().unwrap(); + + let index = event_ring_guard.ring.next_index(); let mut trb; 'busy_waiting: loop { - trb = self.hci.primary_event_ring.lock().unwrap().ring.trbs[index]; + trb = &event_ring_guard.ring.trbs[index]; if trb.completion_code() == TrbCompletionCode::Invalid as u8 { self.pause(); continue 'busy_waiting; } } - if self.check_event_ring_full(&trb) { continue } - self.acknowledge(trb); + if self.check_event_ring_full(trb.clone()) { continue 'event_loop } + + self.acknowledge(trb.clone()); self.update_erdp(); } } fn run_with_irq_file(mut self) { - let irq_file = self.irq_file.as_mut().expect("Calling IrqReactor::run_with_irq_file without the IRQ file being None"); + let hci_clone = Arc::clone(&self.hci); 'event_loop: loop { self.handle_requests(); let mut buffer = [0u8; 8]; - let bytes_read = irq_file.read(&mut buffer).expect("Failed to read from irq scheme"); + let bytes_read = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); if bytes_read < mem::size_of::() { panic!("wrong number of bytes read from `irq:`: expected {}, got {}", mem::size_of::(), bytes_read); } @@ -135,11 +140,11 @@ impl IrqReactor { continue; } - let _ = irq_file.write(&buffer); + let _ = self.irq_file.as_mut().unwrap().write(&buffer); // TODO: More event rings, probably even with different IRQs. - let event_ring = self.hci.primary_event_ring.lock().unwrap(); + let mut event_ring = hci_clone.primary_event_ring.lock().unwrap(); let mut count = 0; @@ -151,10 +156,10 @@ impl IrqReactor { continue 'event_loop; } else { count += 1 } - if self.check_event_ring_full(trb) { + if self.check_event_ring_full(trb.clone()) { continue 'trb_loop; } - self.acknowledge(*trb); + self.acknowledge(trb.clone()); trb.reserved(false); self.update_erdp(); @@ -196,7 +201,7 @@ impl IrqReactor { // TODO: Validate the command TRB. *state.message.lock().unwrap() = Some(NextEventTrb { src_trb: Some(command_trb.clone()), - event_trb: trb, + event_trb: trb.clone(), }); state.waker.wake(); @@ -215,7 +220,7 @@ impl IrqReactor { let state = self.states.remove(index); *state.message.lock().unwrap() = Some(NextEventTrb { src_trb: Some(src_trb), - event_trb: trb, + event_trb: trb.clone(), }); state.waker.wake(); } else if trb.transfer_event_trb_pointer().is_none() { @@ -266,7 +271,7 @@ impl IrqReactor { } let state = self.states.remove(index); *state.message.lock().unwrap() = Some(NextEventTrb { - event_trb: trb, + event_trb: trb.clone(), src_trb: None, }); state.waker.wake(); @@ -275,7 +280,7 @@ impl IrqReactor { /// Checks if an event TRB is a Host Controller Event, with the completion code Event Ring /// Full. If so, it grows the event ring. The return value is whether the event ring was full, /// and then grown. - fn check_event_ring_full(&mut self, event_trb: &Trb) -> bool { + fn check_event_ring_full(&mut self, event_trb: Trb) -> bool { let had_event_ring_full_error = event_trb.trb_type() == TrbType::HostController as u8 && event_trb.completion_code() == TrbCompletionCode::EventRingFull as u8; if had_event_ring_full_error { @@ -313,23 +318,27 @@ impl Future for EventTrbFuture { type Output = NextEventTrb; fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { - match self.get_mut() { - &mut Self::Pending { ref mut state, ref mut sender } => if let Some(message) = state.message.lock().unwrap().take() { - *self.get_mut() = Self::Finished; + let this = self.get_mut(); - task::Poll::Ready(message) - } else { - sender.send(State { - message: Arc::clone(&state.message), - is_isoch_or_vf: state.is_isoch_or_vf, - kind: state.state_kind, - waker: context.waker().clone(), - }).expect("IRQ reactor thread unexpectedly stopped"); + let message = match this { + &mut Self::Pending { ref state, ref sender } => match state.message.lock().unwrap().take() { + Some(message) => message, - task::Poll::Pending + None => { + sender.send(State { + message: Arc::clone(&state.message), + is_isoch_or_vf: state.is_isoch_or_vf, + kind: state.state_kind, + waker: context.waker().clone(), + }).expect("IRQ reactor thread unexpectedly stopped"); + + return task::Poll::Pending; + } } &mut Self::Finished => panic!("Polling finished EventTrbFuture again."), - } + }; + *this = Self::Finished; + task::Poll::Ready(message) } } @@ -353,8 +362,8 @@ impl Xhci { pub fn with_ring_mut T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; - let slot_state = self.port_states.get(&(id.port as usize))?; - let endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; + let mut slot_state = self.port_states.get_mut(&(id.port as usize))?; + let mut endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; let ring_ref = match endpoint_state.transfer { RingOrStreams::Ring(ref mut ring) => ring, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index e2da2a887a..4cd98ae907 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -125,25 +125,25 @@ impl Xhci { Ok(()) } - async fn fetch_dev_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result { + async fn fetch_dev_desc(&self, port: usize, slot: u8, ring: &mut Ring) -> Result { let mut desc = Dma::::zeroed()?; self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, ring, &mut desc).await?; Ok(*desc) } - async fn fetch_config_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { + async fn fetch_config_desc(&self, port: usize, slot: u8, ring: &mut Ring, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, ring, &mut desc).await?; Ok(*desc) } - async fn fetch_bos_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result<(usb::BosDescriptor, [u8; 4087])> { + async fn fetch_bos_desc(&self, port: usize, slot: u8, ring: &mut Ring) -> Result<(usb::BosDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, ring, &mut desc).await?; Ok(*desc) } - async fn fetch_string_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, index: u8) -> Result { + async fn fetch_string_desc(&self, port: usize, slot: u8, ring: &mut Ring, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, ring, &mut sdesc).await?; @@ -407,14 +407,14 @@ impl Xhci { if buf_count == 0 { return Ok(()); } - let scratchpad_buf_arr = ScratchpadBufferArray::new(buf_count)?; + let scratchpad_buf_arr = ScratchpadBufferArray::new(self.page_size,buf_count)?; self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; self.scratchpad_buf_arr = Some(scratchpad_buf_arr); Ok(()) } - pub async fn enable_port_slot(&mut self, slot_ty: u8) -> Result { + pub async fn enable_port_slot(&self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); let (event_trb, command_trb) = @@ -425,7 +425,7 @@ impl Xhci { Ok(event_trb.event_slot()) } - pub async fn disable_port_slot(&mut self, slot: u8) -> Result<()> { + pub async fn disable_port_slot(&self, slot: u8) -> Result<()> { let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)).await; self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb); @@ -485,9 +485,18 @@ impl Xhci { .collect::>(), }; - let dev_desc = self.get_desc(i, slot, &mut ring).await?; + let ring = port_state.endpoint_states.get_mut(&0).unwrap().ring().unwrap(); + + let dev_desc = self.get_desc(i, slot, ring).await?; port_state.dev_desc = Some(dev_desc); - self.update_default_control_pipe(&mut input, slot, &dev_desc).await?; + + + { + let mut input = port_state.input_context.lock().unwrap(); + let dev_desc = port_state.dev_desc.as_ref().unwrap(); + + self.update_default_control_pipe(&mut *input, slot, dev_desc).await?; + } /*match self.spawn_drivers(i, &mut port_state) { Ok(()) => (), @@ -502,7 +511,7 @@ impl Xhci { } pub async fn update_default_control_pipe( - &mut self, + &self, input_context: &mut Dma, slot_id: u8, dev_desc: &DevDesc, @@ -644,7 +653,7 @@ impl Xhci { _ => None, } } - pub fn msix_info_mut(&mut self) -> Option> { + pub fn msix_info_mut(&self) -> Option> { match self.interrupt_method { InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), _ => None, @@ -653,15 +662,16 @@ impl Xhci { /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always /// true when using MSI/MSI-X. - pub fn received_irq(&mut self) -> bool { - let runtime_regs = self.run.lock().unwrap(); + pub fn received_irq(&self) -> bool { + let mut runtime_regs = self.run.lock().unwrap(); if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); println!("MSI-X PB={}", self.msix_info_mut().unwrap().pba(0)); - let entry = self.msix_info_mut().unwrap().table_entry_pointer(0); + let mut msix = self.msix_info_mut().unwrap(); + let entry = msix.table_entry_pointer(0); println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); true } else if runtime_regs.ints[0].iman.readf(1) { @@ -677,7 +687,7 @@ impl Xhci { } } - fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> { + fn spawn_drivers(&self, port: usize, ps: &mut PortState) -> Result<()> { // TODO: There should probably be a way to select alternate interfaces, and not just the // first one. // TODO: Now that there are some good error crates, I don't think errno.h error codes are diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index 2e067efce3..f6e6ee0696 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -82,8 +82,9 @@ impl Ring { pub fn phys_addr_to_entry_ref(&self, paddr: u64) -> Option<&Trb> { Some(&self.trbs[self.phys_addr_to_index(paddr)?]) } - pub fn phys_addr_to_entry_mut(&self, paddr: u64) -> Option<&mut Trb> { - Some(&mut self.trbs[self.phys_addr_to_index(paddr)?]) + pub fn phys_addr_to_entry_mut(&mut self, paddr: u64) -> Option<&mut Trb> { + let index = self.phys_addr_to_index(paddr)?; + Some(&mut self.trbs[index]) } pub fn phys_addr_to_entry(&self, paddr: u64) -> Option { Some(self.trbs[self.phys_addr_to_index(paddr)?].clone()) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 3ecc690cae..28a6fd2b9d 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -214,7 +214,7 @@ impl Xhci { }) } pub fn execute_command_noreply(&self, f: F) { - let command_ring = self.cmd.lock().unwrap(); + let mut command_ring = self.cmd.lock().unwrap(); let (cmd, cycle) = command_ring.next(); f(cmd, cycle); @@ -229,7 +229,7 @@ impl Xhci { f: F, ) -> (Trb, Trb) { let next_event = { - let command_ring = self.cmd.lock().unwrap(); + let mut command_ring = self.cmd.lock().unwrap(); let (cmd, cycle) = command_ring.next(); f(cmd, cycle); @@ -249,7 +249,7 @@ impl Xhci { (event_trb, command_trb) } pub async fn execute_control_transfer( - &mut self, + &self, port_num: usize, setup: usb::Setup, tk: TransferKind, @@ -259,11 +259,11 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { - let port_state = self.port_state(port_num)?; + let mut port_state = self.port_state_mut(port_num)?; let slot = port_state.slot; let future = { - let endpoint_state = port_state + let mut endpoint_state = port_state .endpoint_states .get_mut(&0).ok_or(Error::new(EIO))?; @@ -322,16 +322,16 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { - let port_state = self.port_state_mut(port_num)?; + let mut port_state = self.port_state_mut(port_num)?; let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { (Some(c), Some(i)) => (c, i), _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let slot = port_state.slot; + let endp_state = port_state .endpoint_states .get_mut(&endp_num) @@ -362,6 +362,8 @@ impl Xhci { } }; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + self.dbs.lock().unwrap()[usize::from(slot)].write(Self::endp_doorbell( endp_num, endp_desc, @@ -389,7 +391,7 @@ impl Xhci { Ok(event_trb) } - async fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { + async fn device_req_no_data(&self, port: usize, req: usb::Setup) -> Result<()> { self.execute_control_transfer( port, req, @@ -399,11 +401,11 @@ impl Xhci { ).await?; Ok(()) } - async fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { + async fn set_configuration(&self, port: usize, config: u8) -> Result<()> { self.device_req_no_data(port, usb::Setup::set_configuration(config)).await } async fn set_interface( - &mut self, + &self, port: usize, interface_num: u8, alternate_setting: u8, @@ -414,7 +416,7 @@ impl Xhci { ).await } - async fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { + async fn reset_endpoint(&self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { @@ -519,7 +521,7 @@ impl Xhci { fn port_state_mut(&self, port: usize) -> Result> { self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) } - async fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { + async fn configure_endpoints(&self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; @@ -539,7 +541,7 @@ impl Xhci { let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; let config_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; - let endpoints = config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; + let endpoints = &config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; if endpoints.len() >= 31 { return Err(Error::new(EIO)); @@ -564,7 +566,7 @@ impl Xhci { { let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let input_context = port_state.input_context.lock().unwrap(); + let mut input_context = port_state.input_context.lock().unwrap(); // Configure the slot context as well, which holds the last index of the endp descs. input_context.add_context.write(1); @@ -650,7 +652,7 @@ impl Xhci { assert_eq!(max_error_count & 0x3, max_error_count); assert_ne!(ep_ty, 0); // 0 means invalid. - let port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; + let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; let ring_ptr = if usb_log_max_streams.is_some() { let mut array = StreamContextArray::new(1 << (primary_streams + 1))?; @@ -694,7 +696,7 @@ impl Xhci { assert_eq!(primary_streams & 0x1F, primary_streams); let port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; - let input_context = port_state.input_context.lock().unwrap(); + let mut input_context = port_state.input_context.lock().unwrap(); input_context.add_context.writef(1 << endp_num_xhc, true); let endp_ctx = input_context.device.endpoints.get_mut(endp_num_xhc as usize - 1).ok_or(Error::new(EIO))?; @@ -745,7 +747,7 @@ impl Xhci { Ok(()) } async fn transfer_read( - &mut self, + &self, port_num: usize, endp_idx: u8, buf: &mut [u8], @@ -755,29 +757,30 @@ impl Xhci { } let dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(buf.len())? }; - let (completion_code, bytes_transferred) = self.transfer( + let (completion_code, bytes_transferred, dma_buffer) = self.transfer( port_num, endp_idx, Some(dma_buffer), PortReqDirection::DeviceToHost, ).await?; - buf.copy_from_slice(&*dma_buffer.as_ref()); + buf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); Ok((completion_code, bytes_transferred)) } - async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, sbuf: &[u8]) -> Result<(u8, u32)> { + async fn transfer_write(&self, port_num: usize, endp_idx: u8, sbuf: &[u8]) -> Result<(u8, u32)> { if sbuf.is_empty() { return Err(Error::new(EINVAL)); } let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; dma_buffer.copy_from_slice(sbuf); - self.transfer( + let (completion_code, bytes_transferred, _) = self.transfer( port_num, endp_idx, Some(dma_buffer), PortReqDirection::HostToDevice, - ).await + ).await?; + Ok((completion_code, bytes_transferred)) } pub const fn def_control_endp_doorbell() -> u32 { 1 @@ -810,7 +813,7 @@ impl Xhci { endp_idx: u8, dma_buf: Option>, direction: PortReqDirection, - ) -> Result<(u8, u32)> { + ) -> Result<(u8, u32, Option>)> { // TODO: Check that only readable enpoints are read, etc. let endp_num = endp_idx + 1; @@ -847,8 +850,8 @@ impl Xhci { let (buffer, idt, estimated_td_size) = { let (buffer, idt) = - if dma_buf.map(|buf| buf.len()).unwrap_or(0) <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { - dma_buf.map(|sbuf| { + if dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0) <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { + dma_buf.as_ref().map(|sbuf| { let mut bytes = [0u8; 8]; bytes[..sbuf.len()].copy_from_slice(&sbuf); (u64::from_le_bytes(bytes), true) @@ -862,7 +865,7 @@ impl Xhci { }; let estimated_td_size = cmp::min( u8::try_from( - div_round_up(dma_buf.map(|buf| buf.len()).unwrap_or(0), max_transfer_size as usize) * mem::size_of::(), + div_round_up(dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0), max_transfer_size as usize) * mem::size_of::(), ) .ok() .unwrap_or(0x1F), @@ -873,7 +876,7 @@ impl Xhci { let stream_id = 1u16; - let mut bytes_left = dma_buf.map(|buf| buf.len()).unwrap_or(0); + let mut bytes_left = dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0); let event = self.execute_transfer( port_num, @@ -912,9 +915,9 @@ impl Xhci { ).await?; self.event_handler_finished(); - let bytes_transferred = dma_buf.map(|buf| buf.len() as u32 - event.transfer_length()).unwrap_or(0); + let bytes_transferred = dma_buf.as_ref().map(|buf| buf.len() as u32 - event.transfer_length()).unwrap_or(0); - Ok((event.completion_code(), bytes_transferred)) + Ok((event.completion_code(), bytes_transferred, dma_buf)) } pub async fn get_desc( &self, @@ -922,7 +925,8 @@ impl Xhci { slot: u8, ring: &mut Ring, ) -> Result { - let port = self.ports.lock().unwrap().get(port_id).ok_or(Error::new(ENOENT))?; + let ports = self.ports.lock().unwrap(); + let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } @@ -1043,7 +1047,7 @@ impl Xhci { config_descs, }) } - fn port_desc_json(&mut self, port_id: usize) -> Result> { + fn port_desc_json(&self, port_id: usize) -> Result> { let dev_desc = &self .port_states .get(&port_id) @@ -1061,7 +1065,7 @@ impl Xhci { bytes_to_read } async fn port_req_transfer( - &mut self, + &self, port_num: usize, data_buffer: Option<&mut Dma<[u8]>>, setup: usb::Setup, @@ -1084,7 +1088,7 @@ impl Xhci { ).await?; Ok(()) } - fn port_req_init_st(&mut self, port_num: usize, req: &PortReq) -> Result { + fn port_req_init_st(&self, port_num: usize, req: &PortReq) -> Result { use usb::setup::*; let direction = ReqDirection::from(req.direction); @@ -1122,7 +1126,7 @@ impl Xhci { // PortState? } async fn handle_port_req_write( - &mut self, + &self, fd: usize, port_num: usize, mut st: PortReqState, @@ -1156,7 +1160,7 @@ impl Xhci { PortReqState::WaitingForDeviceBytes(_, _) => return Err(Error::new(EBADF)), PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), }; - let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { Handle::PortReq(_, ref mut state) => *state = st, _ => unreachable!(), @@ -1164,7 +1168,7 @@ impl Xhci { Ok(bytes_written) } async fn handle_port_req_read( - &mut self, + &self, fd: usize, port_num: usize, mut st: PortReqState, @@ -1188,7 +1192,7 @@ impl Xhci { PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), }; - let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { Handle::PortReq(_, ref mut state) => *state = st, _ => unreachable!(), @@ -1372,7 +1376,7 @@ impl SchemeMut for Xhci { } fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { - let guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; match &*guard { &Handle::TopLevel(_, ref buf) @@ -1409,7 +1413,7 @@ impl SchemeMut for Xhci { } fn fpath(&mut self, fd: usize, buffer: &mut [u8]) -> Result { - let cursor = io::Cursor::new(buffer); + let mut cursor = io::Cursor::new(buffer); let guard = self.handles.get(&fd).ok_or(Error::new(EBADF))?; match &*guard { @@ -1423,15 +1427,15 @@ impl SchemeMut for Xhci { &Handle::Endpoints(port_num, _, _) => { write!(cursor, "/port{}/endpoints/", port_num).unwrap() } - &Handle::Endpoint(port_num, endp_num, st) => write!( + &Handle::Endpoint(port_num, endp_num, ref st) => write!( cursor, "/port{}/endpoints/{}/{}", port_num, endp_num, match st { - EndpointHandleTy::Root(_, _) => "", - EndpointHandleTy::Ctl => "ctl", - EndpointHandleTy::Data => "data", + &EndpointHandleTy::Root(_, _) => "", + &EndpointHandleTy::Ctl => "ctl", + &EndpointHandleTy::Data => "data", } ) .unwrap(), @@ -1444,7 +1448,7 @@ impl SchemeMut for Xhci { } fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { - let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { // Directories, or fixed files Handle::TopLevel(ref mut offset, ref buf) @@ -1477,7 +1481,7 @@ impl SchemeMut for Xhci { } fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { - let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) @@ -1530,7 +1534,8 @@ impl SchemeMut for Xhci { } } fn write(&mut self, fd: usize, buf: &[u8]) -> Result { - let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { &mut Handle::ConfigureEndpoints(port_num) => { block_on(self.configure_endpoints(port_num, buf))?; @@ -1558,7 +1563,7 @@ impl SchemeMut for Xhci { } } impl Xhci { - pub fn get_endp_status(&mut self, port_num: usize, endp_num: u8) -> Result { + pub fn get_endp_status(&self, port_num: usize, endp_num: u8) -> Result { let port_state = self .port_states .get(&port_num) @@ -1607,7 +1612,7 @@ impl Xhci { }) } pub async fn on_req_reset_device( - &mut self, + &self, port_num: usize, endp_num: u8, clear_feature: bool, @@ -1635,10 +1640,28 @@ impl Xhci { Ok(()) } pub async fn restart_endpoint(&self, port_num: usize, endp_num: u8) -> Result<()> { - let port_state = self + let mut port_state = self .port_states .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; + let slot = port_state.slot; + + let mut endpoint_state = port_state + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADFD))?; + + let (has_streams, ring) = match &mut endpoint_state.transfer { + &mut super::RingOrStreams::Ring(ref mut ring) => (false, ring), + &mut super::RingOrStreams::Streams(ref mut arr) => { + (true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?) + } + }; + + let (cmd, cycle) = ring.next(); + cmd.transfer_no_op(0, false, false, false, cycle); + + let deque_ptr_and_cycle = ring.register(); let endp_desc = port_state .dev_desc @@ -1653,39 +1676,22 @@ impl Xhci { .get(endp_num as usize - 1) .ok_or(Error::new(EBADFD))?; - let direction = if endp_num != 0 { - endp_desc.direction() + let doorbell = if endp_num != 0 { + let stream_id = 1u16; + + Self::endp_doorbell( + endp_num, + endp_desc, + if has_streams { stream_id } else { 0 }, + ) } else { - EndpDirection::Bidirectional + Self::def_control_endp_doorbell() }; - let endpoint_state = port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADFD))?; - - let (has_streams, ring) = match &mut endpoint_state.transfer { - &mut super::RingOrStreams::Ring(ref mut ring) => (false, ring), - &mut super::RingOrStreams::Streams(ref mut arr) => { - (true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?) - } - }; - let stream_id = 1u16; - let doorbell = Self::endp_doorbell( - endp_num, - endp_desc, - if has_streams { stream_id } else { 0 }, - ); - - let (cmd, cycle) = ring.next(); - cmd.transfer_no_op(0, false, false, false, cycle); - - let deque_ptr_and_cycle = ring.register(); - let slot = port_state.slot; + self.dbs.lock().unwrap()[slot as usize].write(doorbell); self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle).await?; - self.dbs.lock().unwrap()[slot as usize].write(doorbell); Ok(()) } pub fn endp_direction(&self, port_num: usize, endp_num: u8) -> Result { @@ -1741,19 +1747,22 @@ impl Xhci { handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb) } pub async fn on_write_endp_ctl( - &mut self, + &self, port_num: usize, endp_num: u8, buf: &[u8], ) -> Result { - let ep_if_state = &mut self + let mut port_state = self .port_states .get_mut(&port_num) - .ok_or(Error::new(EBADF))? + .ok_or(Error::new(EBADF))?; + + let ep_if_state = &mut port_state .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADF))? .driver_if_state; + let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; match req { XhciEndpCtlReq::Status => match ep_if_state { @@ -1773,16 +1782,18 @@ impl Xhci { if direction == XhciEndpCtlDirection::NoData { // Yield the result directly because no bytes have to be sent or received // beforehand. - let (completion_code, bytes_transferred) = + let (completion_code, bytes_transferred, _) = self.transfer(port_num, endp_num - 1, None, PortReqDirection::DeviceToHost).await?; if bytes_transferred > 0 { return Err(Error::new(EIO)); } let result = Self::transfer_result(completion_code, 0); - let new_state = &mut self + + let mut port_state = self .port_states .get_mut(&port_num) - .ok_or(Error::new(EBADF))? + .ok_or(Error::new(EBADF))?; + let new_state = &mut port_state .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADF))? @@ -1822,13 +1833,13 @@ impl Xhci { } } pub async fn on_write_endp_data( - &mut self, + &self, port_num: usize, endp_num: u8, buf: &[u8], ) -> Result { - let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; - let endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + let mut port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; + let mut endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; let ep_if_state = &mut endpoint_state.driver_if_state; @@ -1849,8 +1860,8 @@ impl Xhci { // invoking further data transfer calls if any single transfer returns fewer bytes // than requested. - let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; - let endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + let mut port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; + let mut endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; let ep_if_state = &mut endpoint_state.driver_if_state; if let &mut EndpIfState::WaitingForDataPipe { @@ -1873,15 +1884,17 @@ impl Xhci { } } pub fn on_read_endp_ctl( - &mut self, + &self, port_num: usize, endp_num: u8, buf: &mut [u8], ) -> Result { - let ep_if_state = &mut self + let port_state = &mut self .port_states .get_mut(&port_num) - .ok_or(Error::new(EBADF))? + .ok_or(Error::new(EBADF))?; + + let ep_if_state = &mut port_state .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADF))? @@ -1906,19 +1919,22 @@ impl Xhci { Ok(cursor.seek(io::SeekFrom::Current(0)).unwrap() as usize) } pub async fn on_read_endp_data( - &mut self, + &self, port_num: usize, endp_num: u8, buf: &mut [u8], ) -> Result { - let ep_if_state = &mut self + let mut port_state = self .port_states .get_mut(&port_num) - .ok_or(Error::new(EBADF))? + .ok_or(Error::new(EBADF))?; + + let mut ep_if_state = &mut port_state .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADF))? .driver_if_state; + match ep_if_state { &mut EndpIfState::WaitingForDataPipe { direction: XhciEndpCtlDirection::In, @@ -1937,14 +1953,18 @@ impl Xhci { let result = Self::transfer_result(completion_code, some_bytes_transferred); - let ep_if_state = &mut self + let mut port_state = self .port_states .get_mut(&port_num) - .ok_or(Error::new(EBADF))? + .ok_or(Error::new(EBADF))?; + + let mut ep_state = port_state .endpoint_states .get_mut(&endp_num) - .ok_or(Error::new(EBADF))? - .driver_if_state; + .ok_or(Error::new(EBADF))?; + + let ep_if_state = &mut ep_state.driver_if_state; + if let &mut EndpIfState::WaitingForDataPipe { direction: XhciEndpCtlDirection::In, bytes_to_transfer, From 9e34ed3fbf9140e40765d3f8d5da7ac445fe458a Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 12:03:48 +0100 Subject: [PATCH 10/22] It compiles! --- xhcid/src/main.rs | 2 +- xhcid/src/xhci/scheme.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 37de0739a4..50ca1adccf 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -20,7 +20,7 @@ use std::env; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; -use syscall::scheme::SchemeMut; +use syscall::scheme::Scheme; use syscall::io::Io; use crate::xhci::{InterruptMethod, Xhci}; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 28a6fd2b9d..f605de6ee4 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; use syscall::io::{Dma, Io}; -use syscall::scheme::SchemeMut; +use syscall::scheme::Scheme; use syscall::{ Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, ENOTDIR, ENXIO, EOPNOTSUPP, EOVERFLOW, EPERM, EPROTO, ESPIPE, MODE_CHR, MODE_DIR, @@ -1201,8 +1201,8 @@ impl Xhci { } } -impl SchemeMut for Xhci { - fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { +impl Scheme for Xhci { + fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid != 0 { return Err(Error::new(EACCES)); } @@ -1375,7 +1375,7 @@ impl SchemeMut for Xhci { Ok(fd) } - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { + fn fstat(&self, id: usize, stat: &mut Stat) -> Result { let mut guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; match &*guard { @@ -1412,7 +1412,7 @@ impl SchemeMut for Xhci { Ok(0) } - fn fpath(&mut self, fd: usize, buffer: &mut [u8]) -> Result { + fn fpath(&self, fd: usize, buffer: &mut [u8]) -> Result { let mut cursor = io::Cursor::new(buffer); let guard = self.handles.get(&fd).ok_or(Error::new(EBADF))?; @@ -1447,7 +1447,7 @@ impl SchemeMut for Xhci { Ok(src_len) } - fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { + fn seek(&self, fd: usize, pos: usize, whence: usize) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { // Directories, or fixed files @@ -1480,7 +1480,7 @@ impl SchemeMut for Xhci { } } - fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { + fn read(&self, fd: usize, buf: &mut [u8]) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { Handle::TopLevel(ref mut offset, ref src_buf) @@ -1533,7 +1533,7 @@ impl SchemeMut for Xhci { } } } - fn write(&mut self, fd: usize, buf: &[u8]) -> Result { + fn write(&self, fd: usize, buf: &[u8]) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { @@ -1555,7 +1555,7 @@ impl SchemeMut for Xhci { _ => return Err(Error::new(EBADF)), } } - fn close(&mut self, fd: usize) -> Result { + fn close(&self, fd: usize) -> Result { if self.handles.remove(&fd).is_none() { return Err(Error::new(EBADF)); } From e58245b280f66cff9e7863c29849ab244dc1ede2 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 12:30:32 +0100 Subject: [PATCH 11/22] Use an event queue in the IRQ reactor. --- xhcid/src/xhci/irq_reactor.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 7ab7b8f677..81299046a6 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -5,12 +5,16 @@ use std::io::prelude::*; use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::sync::atomic::{self, AtomicUsize}; -use std::{mem, task, thread}; +use std::{io, mem, task, thread}; + +use std::os::unix::io::AsRawFd; use crossbeam_channel::{Sender, Receiver}; use futures::Stream; use syscall::Io; +use event::EventQueue; + use super::Xhci; use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; @@ -126,18 +130,26 @@ impl IrqReactor { } fn run_with_irq_file(mut self) { let hci_clone = Arc::clone(&self.hci); + let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); + let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); - 'event_loop: loop { - self.handle_requests(); + event_queue.add(irq_fd, move |_| -> io::Result> { let mut buffer = [0u8; 8]; + let bytes_read = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); + + self.handle_requests(); + if bytes_read < mem::size_of::() { - panic!("wrong number of bytes read from `irq:`: expected {}, got {}", mem::size_of::(), bytes_read); + // continue the loop when the next IRQ arrives + return Ok(None); } + if !self.hci.received_irq() { - continue; + // continue only when an IRQ to this device was received + return Ok(None); } let _ = self.irq_file.as_mut().unwrap().write(&buffer); @@ -153,18 +165,20 @@ impl IrqReactor { if trb.completion_code() == TrbCompletionCode::Invalid as u8 { if count == 0 { println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } - continue 'event_loop; + // no more events were found, continue the loop + return Ok(None); } else { count += 1 } if self.check_event_ring_full(trb.clone()) { - continue 'trb_loop; + return Ok(None); } self.acknowledge(trb.clone()); trb.reserved(false); self.update_erdp(); } - } + }).expect("xhcid: failed to catch irq events"); + event_queue.run().expect("xhcid: failed to run IRQ event queue"); } fn update_erdp(&self) { let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().erdp(); From ddf71d48e60d881de020dee8be6ef221b834f976 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 15:52:39 +0100 Subject: [PATCH 12/22] Get the Enable Slot cmd working, asynchronously! This is the first command that actually worked by calling the IRQ reactor and then getting a response. While this may not be that much on its own, it means the async/await model actually works in this context. Now the major problem is getting rid of all the deadlocks, and later remove block_on(future) in the Scheme impl, and instead go async with future spawning instead. --- xhcid/src/xhci/irq_reactor.rs | 51 ++++++++++++++++++++--------------- xhcid/src/xhci/mod.rs | 15 ++++++++--- xhcid/src/xhci/ring.rs | 4 ++- xhcid/src/xhci/scheme.rs | 12 ++++++--- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 81299046a6..9371bc33c6 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -13,7 +13,7 @@ use crossbeam_channel::{Sender, Receiver}; use futures::Stream; use syscall::Io; -use event::EventQueue; +use event::{Event, EventQueue}; use super::Xhci; use super::ring::Ring; @@ -21,6 +21,7 @@ use super::trb::{Trb, TrbCompletionCode, TrbType}; /// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back /// by the future unless it completed). +#[derive(Debug)] pub struct State { waker: task::Waker, kind: StateKind, @@ -28,6 +29,7 @@ pub struct State { is_isoch_or_vf: bool, } +#[derive(Debug)] pub struct NextEventTrb { pub event_trb: Trb, pub src_trb: Option, @@ -103,11 +105,10 @@ impl IrqReactor { std::thread::yield_now(); } fn run_polling(mut self) { + println!("Running IRQ reactor in polling mode."); let hci_clone = Arc::clone(&self.hci); 'event_loop: loop { - self.handle_requests(); - let mut event_ring_guard = hci_clone.primary_event_ring.lock().unwrap(); let index = event_ring_guard.ring.next_index(); @@ -124,34 +125,32 @@ impl IrqReactor { } if self.check_event_ring_full(trb.clone()) { continue 'event_loop } + self.handle_requests(); self.acknowledge(trb.clone()); self.update_erdp(); } } fn run_with_irq_file(mut self) { + println!("Running IRQ reactor with IRQ file and event queue"); + let hci_clone = Arc::clone(&self.hci); let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); event_queue.add(irq_fd, move |_| -> io::Result> { - + println!("IRQ event queue notified"); let mut buffer = [0u8; 8]; - let bytes_read = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); - - self.handle_requests(); - - if bytes_read < mem::size_of::() { - // continue the loop when the next IRQ arrives - return Ok(None); - } - + let _ = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); if !self.hci.received_irq() { // continue only when an IRQ to this device was received + println!("no interrupt pending"); return Ok(None); } + println!("IRQ reactor received an IRQ"); + let _ = self.irq_file.as_mut().unwrap().write(&buffer); // TODO: More event rings, probably even with different IRQs. @@ -169,15 +168,22 @@ impl IrqReactor { return Ok(None); } else { count += 1 } + println!("Found event TRB: {:?}", trb); + if self.check_event_ring_full(trb.clone()) { + println!("Had to resize event TRB, retrying..."); + hci_clone.event_handler_finished(); return Ok(None); } + + self.handle_requests(); self.acknowledge(trb.clone()); trb.reserved(false); self.update_erdp(); } }).expect("xhcid: failed to catch irq events"); + //event_queue.trigger_all(Event { fd: 0, flags: 0 }).expect("irq reactor failed to trigger events"); event_queue.run().expect("xhcid: failed to run IRQ event queue"); } fn update_erdp(&self) { @@ -185,17 +191,22 @@ impl IrqReactor { let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); + println!("Updated ERDP to {:#0x}", dequeue_pointer); + self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); } fn handle_requests(&mut self) { - self.states.extend(self.receiver.try_iter()); + self.states.extend(self.receiver.try_iter().inspect(|req| println!("Received request: {:?}", req))); } fn acknowledge(&mut self, trb: Trb) { let mut index = 0; loop { + if index >= self.states.len() { return } + match self.states[index].kind { - StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => if trb.completion_trb_pointer() == Some(phys_ptr) { + StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) { + println!("Found matching command completion future"); let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event @@ -218,6 +229,7 @@ impl IrqReactor { event_trb: trb.clone(), }); + println!("Waking up future with waker: {:?}", state.waker); state.waker.wake(); } else if trb.completion_trb_pointer().is_none() { println!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); @@ -264,9 +276,6 @@ impl IrqReactor { _ => { index += 1; - if index >= self.states.len() { - break; - } continue; } } @@ -405,13 +414,11 @@ impl Xhci { sender: self.irq_reactor_sender.clone(), } } - pub fn next_command_completion_event_trb(&self, trb: &Trb) -> impl Future + Send + Sync + 'static { + pub fn next_command_completion_event_trb(&self, command_ring: &Ring, trb: &Trb) -> impl Future + Send + Sync + 'static { if ! trb.is_command_trb() { panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) } - - let command_ring = self.cmd.lock().unwrap(); - + dbg!(command_ring.trbs.physical()); EventTrbFuture::Pending { state: FutureState { // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 4cd98ae907..b67e123832 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -356,7 +356,7 @@ impl Xhci { println!(" - Write ERSTZ: {}", erstz); int.erstsz.write(erstz); - let erdp = self.primary_event_ring.get_mut().unwrap().erdp() | (!1); + let erdp = self.primary_event_ring.get_mut().unwrap().erdp(); println!(" - Write ERDP: {:X}", erdp); int.erdp.write(erdp as u64 | (1 << 3)); @@ -368,7 +368,7 @@ impl Xhci { int.imod.write(0); println!(" - Enable interrupts"); - int.iman.writef(1 << 1, true); + int.iman.writef(1 << 1 | 1, true); } self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true); @@ -395,7 +395,7 @@ impl Xhci { println!(" - XHCI initialized"); if self.cap.cic() { - self.op.lock().unwrap().set_cie(true); + self.op.get_mut().unwrap().set_cie(true); } Ok(()) @@ -441,7 +441,9 @@ impl Xhci { pub async fn probe(&self) -> Result<()> { println!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); - for i in 0..self.ports.lock().unwrap().len() { + let port_count = { self.ports.lock().unwrap().len() }; + + for i in 0..port_count { let (data, state, speed, flags) = { let port = &self.ports.lock().unwrap()[i]; (port.read(), port.state(), port.speed(), port.flags()) @@ -460,6 +462,8 @@ impl Xhci { .supported_protocol(i as u8) .expect("Failed to find supported protocol information for port") .proto_slot_ty(); + + println!("Got slot type: {}", slot_ty); let slot = self.enable_port_slot(slot_ty).await?; println!(" - Slot {}", slot); @@ -843,7 +847,10 @@ pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { let receiver = hci.irq_reactor_receiver.clone(); let hci_clone = Arc::clone(&hci); + println!("About to start IRQ reactor"); + *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { + println!("Started IRQ reactor thread"); IrqReactor::new(hci_clone, receiver, irq_file).run() })); } diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index f6e6ee0696..67cafcf080 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -102,8 +102,10 @@ impl Ring { if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) || (trb_virt_pointer as usize) > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::() { panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb); } + let trb_offset_from_base = trb_virt_pointer as u64 - trbs_base_virt_pointer as u64; + let trbs_base_phys_ptr = self.trbs.physical() as u64; - let trb_phys_ptr = trb_virt_pointer as u64 - trbs_base_phys_ptr; + let trb_phys_ptr = trbs_base_phys_ptr + trb_offset_from_base; trb_phys_ptr } /* diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index f605de6ee4..c21436677d 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -230,12 +230,16 @@ impl Xhci { ) -> (Trb, Trb) { let next_event = { let mut command_ring = self.cmd.lock().unwrap(); + let (cmd_index, cycle) = (command_ring.next_index(), command_ring.cycle); - let (cmd, cycle) = command_ring.next(); - f(cmd, cycle); + { + let command_trb = &mut command_ring.trbs[cmd_index]; + f(command_trb, cycle); + } // get the future here before awaiting, to destroy the lock before deadlock - self.next_command_completion_event_trb(&cmd) + let command_trb = &command_ring.trbs[cmd_index]; + self.next_command_completion_event_trb(&*command_ring, command_trb) }; self.dbs.lock().unwrap()[0].write(0); @@ -244,7 +248,7 @@ impl Xhci { let event_trb = trbs.event_trb; let command_trb = trbs.src_trb.expect("Command completion event TRBs shall always have a valid pointer to a valid source command TRB"); - assert_eq!(command_trb.trb_type(), TrbType::CommandCompletion as u8, "The IRQ reactor (or the xHC) gave an invalid event TRB"); + assert_eq!(event_trb.trb_type(), TrbType::CommandCompletion as u8, "The IRQ reactor (or the xHC) gave an invalid event TRB"); (event_trb, command_trb) } From f3d2d3e2d1a24a67509f6eb6845a19cb21773f5e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 22:38:22 +0100 Subject: [PATCH 13/22] Fix the IRQ reactor when doing subsequent cmds. --- xhcid/src/xhci/irq_reactor.rs | 37 +++++++++++++++++++++++------------ xhcid/src/xhci/mod.rs | 5 ++++- xhcid/src/xhci/scheme.rs | 24 ++++++++++++----------- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 9371bc33c6..61d7f548a7 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -18,6 +18,7 @@ use event::{Event, EventQueue}; use super::Xhci; use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; +use super::event::EventRing; /// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back /// by the future unless it completed). @@ -127,7 +128,8 @@ impl IrqReactor { self.handle_requests(); self.acknowledge(trb.clone()); - self.update_erdp(); + + self.update_erdp(&*event_ring_guard); } } fn run_with_irq_file(mut self) { @@ -137,6 +139,8 @@ impl IrqReactor { let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); + let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() }; + event_queue.add(irq_fd, move |_| -> io::Result> { println!("IRQ event queue notified"); let mut buffer = [0u8; 8]; @@ -160,34 +164,36 @@ impl IrqReactor { let mut count = 0; 'trb_loop: loop { - let trb = event_ring.next(); + let event_trb = &mut event_ring.ring.trbs[event_trb_index]; - if trb.completion_code() == TrbCompletionCode::Invalid as u8 { + if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { if count == 0 { println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } // no more events were found, continue the loop return Ok(None); } else { count += 1 } - println!("Found event TRB: {:?}", trb); + println!("Found event TRB: {:?}", event_trb); - if self.check_event_ring_full(trb.clone()) { + if self.check_event_ring_full(event_trb.clone()) { println!("Had to resize event TRB, retrying..."); hci_clone.event_handler_finished(); return Ok(None); } self.handle_requests(); - self.acknowledge(trb.clone()); - trb.reserved(false); + self.acknowledge(event_trb.clone()); - self.update_erdp(); + event_trb.reserved(false); + + self.update_erdp(&*event_ring); + + event_trb_index = event_ring.ring.next_index(); } }).expect("xhcid: failed to catch irq events"); - //event_queue.trigger_all(Event { fd: 0, flags: 0 }).expect("irq reactor failed to trigger events"); event_queue.run().expect("xhcid: failed to run IRQ event queue"); } - fn update_erdp(&self) { - let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().erdp(); + fn update_erdp(&self, event_ring: &EventRing) { + let dequeue_pointer_and_dcs = event_ring.erdp(); let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); @@ -202,7 +208,7 @@ impl IrqReactor { let mut index = 0; loop { - if index >= self.states.len() { return } + if index >= self.states.len() { break } match self.states[index].kind { StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) { @@ -210,7 +216,7 @@ impl IrqReactor { let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event - // be fetched before removing this event TRB from the queue. + // is fetched before removing this event TRB from the queue. let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(phys_ptr) { Some(command_trb) => { let t = command_trb.clone(); @@ -231,6 +237,8 @@ impl IrqReactor { println!("Waking up future with waker: {:?}", state.waker); state.waker.wake(); + + return; } else if trb.completion_trb_pointer().is_none() { println!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); continue; @@ -249,6 +257,7 @@ impl IrqReactor { event_trb: trb.clone(), }); state.waker.wake(); + return; } else if trb.transfer_event_trb_pointer().is_none() { // Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full. // @@ -272,6 +281,7 @@ impl IrqReactor { StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => { let state = self.states.remove(index); state.waker.wake(); + return; } _ => { @@ -280,6 +290,7 @@ impl IrqReactor { } } } + println!("Lost event TRB: {:?}", trb); } fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { let mut index = 0; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index b67e123832..b81f0b38bf 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -470,6 +470,7 @@ impl Xhci { let mut input = Dma::::zeroed()?; let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; + println!("Addressed device"); // TODO: Should the descriptors be cached in PortState, or refetched? @@ -538,7 +539,7 @@ impl Xhci { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) }).await; - self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb); + self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; self.event_handler_finished(); Ok(()) @@ -633,9 +634,11 @@ impl Xhci { let input_context_physical = input_context.physical(); + println!("pre_address_device"); let (event_trb, _) = self.execute_command(|trb, cycle| { trb.address_device(slot, input_context_physical, false, cycle) }).await; + println!("post_address_device"); if event_trb.completion_code() != TrbCompletionCode::Success as u8 { println!("Failed to address device at slot {} (port {})", slot, i); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c21436677d..c722986af7 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -213,17 +213,11 @@ impl Xhci { hid_descs: hid_descs.into_iter().collect(), }) } - pub fn execute_command_noreply(&self, f: F) { - let mut command_ring = self.cmd.lock().unwrap(); - - let (cmd, cycle) = command_ring.next(); - f(cmd, cycle); - - self.dbs.lock().unwrap()[0].write(0); - - // TODO: It's still possible not to reset the TRB, right? - } - + /// Pushes a command TRB to the command ring, rings the doorbell, and then awaits its Command + /// Completion Event. + /// + /// # Locking + /// This function will lock `Xhci::cmd` and `Xhci::dbs`. pub async fn execute_command( &self, f: F, @@ -242,7 +236,9 @@ impl Xhci { self.next_command_completion_event_trb(&*command_ring, command_trb) }; + println!("Ringing doorbell"); self.dbs.lock().unwrap()[0].write(0); + println!("Doorbell rung"); let trbs = next_event.await; let event_trb = trbs.event_trb; @@ -1988,7 +1984,13 @@ impl Xhci { _ => return Err(Error::new(EBADF)), } } + /// Notifies the xHC that the current event handler has finished, so that new interrupts can be + /// sent. This is required after each invocation of `Self::execute_command`. + /// + /// # Locking + /// This function locks `Xhci::run`. pub fn event_handler_finished(&self) { + println!("Event handler finished"); // write 1 to EHB to clear it self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true); } From 08616920d61a8a99107363d34895a0e395df6fcf Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 29 Mar 2020 13:49:57 +0200 Subject: [PATCH 14/22] Get descriptor fetching working. --- xhcid/src/xhci/irq_reactor.rs | 4 +-- xhcid/src/xhci/mod.rs | 51 ++++++++++++++++++++++------------- xhcid/src/xhci/scheme.rs | 41 +++++++++++++++++----------- xhcid/src/xhci/trb.rs | 6 +++-- 4 files changed, 65 insertions(+), 37 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 61d7f548a7..0abc6a2a9b 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -406,7 +406,7 @@ impl Xhci { Some(function(ring_ref)) } - pub fn next_transfer_event_trb(&self, ring_id: RingId, trb: &Trb) -> impl Future + Send + Sync + 'static { + pub fn next_transfer_event_trb(&self, ring_id: RingId, ring: &Ring, trb: &Trb) -> impl Future + Send + Sync + 'static { if ! trb.is_transfer_trb() { panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", trb.trb_type(), trb) } @@ -418,7 +418,7 @@ impl Xhci { is_isoch_or_vf, state_kind: StateKind::Transfer { ring_id, - phys_ptr: self.with_ring(ring_id, |ring| ring.trb_phys_ptr(trb)).unwrap(), + phys_ptr: ring.trb_phys_ptr(trb), }, message: Arc::new(Mutex::new(None)), }, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index b81f0b38bf..8e11e56781 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -12,7 +12,7 @@ use std::{mem, process, slice, sync::atomic, task, thread}; use chashmap::CHashMap; use crossbeam_channel::{Receiver, Sender}; use serde::Deserialize; -use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT}; +use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; use syscall::flag::O_RDONLY; use syscall::io::{Dma, Io}; @@ -93,10 +93,16 @@ impl MsixInfo { impl Xhci { /// Gets descriptors, before the port state is initiated. - async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, ring: &mut Ring, desc: &mut Dma) -> Result<()> { + async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) -> Result<()> { + println!("A"); let len = mem::size_of::(); let future = { + println!("B"); + let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; + let ring = port_state.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().expect("no ring for the default control pipe"); + println!("C"); + let (cmd, cycle) = ring.next(); cmd.setup( usb::Setup::get_descriptor(kind, index, 0, len as u16), @@ -107,45 +113,52 @@ impl Xhci { let (cmd, cycle) = ring.next(); cmd.data(desc.physical(), len as u16, true, cycle); - let (cmd, cycle) = ring.next(); + let last_index = ring.next_index(); + let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); cmd.status(0, true, true, false, false, cycle); - self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &cmd) + println!("D"); + self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &ring, &ring.trbs[last_index]) }; + println!("E"); self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); + println!("F"); let trbs = future.await; let event_trb = trbs.event_trb; let status_trb = trbs.src_trb.unwrap(); + println!("G"); self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; + println!("H"); self.event_handler_finished(); + println!("I"); Ok(()) } - async fn fetch_dev_desc(&self, port: usize, slot: u8, ring: &mut Ring) -> Result { + async fn fetch_dev_desc(&self, port: usize, slot: u8) -> Result { let mut desc = Dma::::zeroed()?; - self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, ring, &mut desc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?; Ok(*desc) } - async fn fetch_config_desc(&self, port: usize, slot: u8, ring: &mut Ring, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { + async fn fetch_config_desc(&self, port: usize, slot: u8, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, ring, &mut desc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, &mut desc).await?; Ok(*desc) } - async fn fetch_bos_desc(&self, port: usize, slot: u8, ring: &mut Ring) -> Result<(usb::BosDescriptor, [u8; 4087])> { + async fn fetch_bos_desc(&self, port: usize, slot: u8) -> Result<(usb::BosDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, ring, &mut desc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc).await?; Ok(*desc) } - async fn fetch_string_desc(&self, port: usize, slot: u8, ring: &mut Ring, index: u8) -> Result { + async fn fetch_string_desc(&self, port: usize, slot: u8, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; - self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, ring, &mut sdesc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, &mut sdesc).await?; let len = sdesc.0 as usize; if len > 2 { @@ -489,14 +502,16 @@ impl Xhci { )) .collect::>(), }; + self.port_states.insert(i, port_state); - let ring = port_state.endpoint_states.get_mut(&0).unwrap().ring().unwrap(); - - let dev_desc = self.get_desc(i, slot, ring).await?; - port_state.dev_desc = Some(dev_desc); - + println!("pre get desc"); + let dev_desc = self.get_desc(i, slot).await?; + println!("post get desc"); + self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); { + let mut port_state = self.port_states.get_mut(&i).unwrap(); + let mut input = port_state.input_context.lock().unwrap(); let dev_desc = port_state.dev_desc.as_ref().unwrap(); @@ -508,7 +523,6 @@ impl Xhci { Err(err) => println!("Failed to spawn driver for port {}: `{}`", i, err), }*/ - self.port_states.insert(i, port_state); } } @@ -643,6 +657,7 @@ impl Xhci { if event_trb.completion_code() != TrbCompletionCode::Success as u8 { println!("Failed to address device at slot {} (port {})", slot, i); } + self.event_handler_finished(); Ok(ring) } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c722986af7..3709b18845 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -192,7 +192,6 @@ impl Xhci { &self, port_id: usize, slot: u8, - ring: &mut Ring, desc: usb::InterfaceDescriptor, endps: impl IntoIterator, hid_descs: impl IntoIterator, @@ -201,7 +200,7 @@ impl Xhci { alternate_setting: desc.alternate_setting, class: desc.class, interface_str: if desc.interface_str > 0 { - Some(self.fetch_string_desc(port_id, slot, ring, desc.interface_str).await?) + Some(self.fetch_string_desc(port_id, slot, desc.interface_str).await?) } else { None }, @@ -284,7 +283,8 @@ impl Xhci { } } - let (cmd, cycle) = ring.next(); + let last_index = ring.next_index(); + let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); let interrupter = 0; let ioc = true; @@ -292,7 +292,7 @@ impl Xhci { let ent = false; cmd.status(interrupter, tk == TransferKind::In, ioc, ch, ent, cycle); - self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), cmd) + self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), ring, &ring.trbs[last_index]) }; self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); @@ -352,11 +352,12 @@ impl Xhci { }; let future = loop { - let (trb, cycle) = ring.next(); + let last_index = ring.next_index(); + let (trb, cycle) = (&mut ring.trbs[last_index], ring.cycle); match d(trb, cycle) { ControlFlow::Break => { - break self.next_transfer_event_trb(super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, &trb); + break self.next_transfer_event_trb(super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, ring, &ring.trbs[last_index]); } ControlFlow::Continue => continue, } @@ -923,35 +924,43 @@ impl Xhci { &self, port_id: usize, slot: u8, - ring: &mut Ring, ) -> Result { + println!("Checkpoint 1"); let ports = self.ports.lock().unwrap(); let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } - let raw_dd = self.fetch_dev_desc(port_id, slot, ring).await?; + println!("Checkpoint 2"); + let raw_dd = self.fetch_dev_desc(port_id, slot).await?; + println!("Checkpoint 3"); let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { - Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.manufacturer_str).await?) + println!("Checkpoint 4a"); + Some(self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str).await?) } else { None }, if raw_dd.product_str > 0 { - Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.product_str).await?) + println!("Checkpoint 4b"); + Some(self.fetch_string_desc(port_id, slot, raw_dd.product_str).await?) } else { None }, if raw_dd.serial_str > 0 { - Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.serial_str).await?) + println!("Checkpoint 4c"); + Some(self.fetch_string_desc(port_id, slot, raw_dd.serial_str).await?) } else { None }, ); - let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot, ring).await?; + println!("Checkpoint 5"); + let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?; + println!("Checkpoint 6"); + let supports_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); let supports_superspeedplus = @@ -960,7 +969,9 @@ impl Xhci { let mut config_descs = SmallVec::new(); for index in 0..raw_dd.configurations { - let (desc, data) = self.fetch_config_desc(port_id, slot, ring, index).await?; + println!("Checkpoint 7: {}", index); + let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; + println!("Checkpoint 8: {}", index); let extra_length = desc.total_length as usize - mem::size_of_val(&desc); let data = &data[..extra_length]; @@ -1010,7 +1021,7 @@ impl Xhci { endpoints.push(endp); } - interface_descs.push(self.new_if_desc(port_id, slot, ring, idesc, endpoints, hid_descs).await?); + interface_descs.push(self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs).await?); } else { // TODO break; @@ -1020,7 +1031,7 @@ impl Xhci { config_descs.push(ConfDesc { kind: desc.kind, configuration: if desc.configuration_str > 0 { - Some(self.fetch_string_desc(port_id, slot, ring, desc.configuration_str).await?) + Some(self.fetch_string_desc(port_id, slot, desc.configuration_str).await?) } else { None }, diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 1a91800bbf..a26a28f626 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -378,9 +378,11 @@ impl Trb { self.set( 0, u32::from(interrupter) << 22, - ((input as u32) << 16) + (u32::from(input) << 16) | ((TrbType::StatusStage as u32) << 10) - | (1 << 5) + | (u32::from(ioc) << 5) + | (u32::from(ch) << 4) + | (u32::from(ent) << 1) | (cycle as u32), ); } From ae49a0ba30dbfc8848e3dd97e47dc65ac8988f15 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 4 Apr 2020 11:55:52 +0200 Subject: [PATCH 15/22] Update chashmap version. --- Cargo.lock | 269 +++++++++++++++++++++++------------------------ xhcid/Cargo.toml | 2 +- 2 files changed, 132 insertions(+), 139 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2eeb19c3db..d171dc02ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,8 +47,8 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -90,7 +90,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -144,10 +144,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chashmap" version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://gitlab.redox-os.org/redox-os/chashmap.git#da92c702e052cde00db5e409dfb234af71928152" dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -182,10 +182,11 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -206,8 +207,8 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -221,10 +222,10 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -317,9 +318,9 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -363,10 +364,10 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -428,7 +429,7 @@ name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -467,7 +468,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.66" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -480,10 +481,19 @@ name = "lock_api" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lock_api" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.3.9" @@ -517,10 +527,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memoffset" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -540,7 +550,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -559,7 +569,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -573,7 +583,7 @@ version = "0.6.7" source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#22580ca398cdb5ed6f50fb61134e5579e2213999" dependencies = [ "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", ] @@ -594,7 +604,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -607,7 +617,7 @@ dependencies = [ "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.2 (git+https://github.com/a8m/pb)", @@ -627,7 +637,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-uni dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -694,8 +704,8 @@ name = "num_cpus" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -725,29 +735,12 @@ dependencies = [ [[package]] name = "owning_ref" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "owning_ref" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parking_lot" version = "0.7.1" @@ -758,14 +751,13 @@ dependencies = [ ] [[package]] -name = "parking_lot_core" -version = "0.2.14" +name = "parking_lot" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -773,13 +765,27 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "partitionlib" version = "0.1.0" @@ -795,8 +801,8 @@ name = "pbr" version = "1.0.2" source = "git+https://github.com/a8m/pb#87c29c05486afa7335916c870ea3621ff7ef2966" dependencies = [ - "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -807,7 +813,7 @@ name = "pbr" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -820,11 +826,11 @@ dependencies = [ "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -862,7 +868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -880,22 +886,10 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -904,7 +898,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -959,7 +953,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -971,7 +965,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1047,7 +1041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1094,7 +1088,7 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1109,7 +1103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "scopeguard" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1125,9 +1119,9 @@ name = "scroll_derive" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1146,7 +1140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1158,7 +1152,7 @@ version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1176,30 +1170,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.47" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1220,7 +1214,7 @@ name = "smallvec" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1256,11 +1250,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1269,7 +1263,7 @@ name = "termion" version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1285,20 +1279,20 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror-impl" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1306,7 +1300,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1457,7 +1451,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", @@ -1471,7 +1465,7 @@ name = "toml" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1558,7 +1552,7 @@ dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1678,19 +1672,19 @@ name = "xhcid" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)", + "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "pcid 0.1.0", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1712,15 +1706,15 @@ dependencies = [ "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff41a3c2c1e39921b9003de14bf0439c7b63a9039637c291e1a64925d8ddfa45" +"checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" +"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" +"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" @@ -1736,7 +1730,7 @@ dependencies = [ "checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" "checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" "checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" -"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" +"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" @@ -1746,15 +1740,16 @@ dependencies = [ "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" +"checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" "checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" @@ -1772,12 +1767,11 @@ dependencies = [ "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" -"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" +"checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" +"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" "checksum pbr 1.0.2 (git+https://github.com/a8m/pb)" = "" "checksum pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4403eb718d70c03ee279e51737782902c68cca01e870a33b6a2f9dfb50b9cd83" @@ -1786,9 +1780,8 @@ dependencies = [ "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420" "checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" -"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" @@ -1809,10 +1802,10 @@ dependencies = [ "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" "checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" -"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" "checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" "checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" "checksum scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" "checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" @@ -1820,9 +1813,9 @@ dependencies = [ "checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" -"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" -"checksum serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "15913895b61e0be854afd32fd4163fcd2a3df34142cf2cb961b310ce694cbf90" +"checksum serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" +"checksum serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" +"checksum serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" @@ -1831,11 +1824,11 @@ dependencies = [ "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" +"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "205684fd018ca14432b12cce6ea3d46763311a571c3d294e71ba3f01adcf1aad" -"checksum thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57e4d2e50ca050ed44fb58309bdce3efa79948f84f9993ad1978de5eebdce5a7" +"checksum thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e3711fd1c4e75b3eff12ba5c40dba762b6b65c5476e8174c1a664772060c49bf" +"checksum thiserror-impl 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2b85ba4c9aa32dd3343bd80eb8d22e9b54b7688c17ea3907f236885353b233" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index e46a79a13b..3b1b2a622b 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -13,7 +13,7 @@ path = "src/lib.rs" [dependencies] bitflags = "1" -chashmap = "2.2.2" +chashmap = { git = "https://gitlab.redox-os.org/redox-os/chashmap.git" } crossbeam-channel = "0.4" futures = "0.3" plain = "0.2" From 80d3affa1c993c56f1978f942e6f40e11ef58719 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 4 Apr 2020 23:43:38 +0200 Subject: [PATCH 16/22] Enable xhci logging, powered by redox-log. --- Cargo.lock | 94 +++++++++++++++++++++++++++++------------------ xhcid/Cargo.toml | 3 +- xhcid/src/main.rs | 42 +++++++++++++-------- 3 files changed, 86 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d171dc02ee..9c56aa7049 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,7 +47,7 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -90,7 +90,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -150,6 +150,16 @@ dependencies = [ "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "chrono" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "clap" version = "2.33.0" @@ -317,8 +327,8 @@ name = "futures-macro" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -346,7 +356,7 @@ dependencies = [ "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -364,7 +374,7 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", @@ -704,7 +714,7 @@ name = "num_cpus" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -828,9 +838,9 @@ dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -858,7 +868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-hack" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -868,7 +878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -889,7 +899,7 @@ name = "quote" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1005,6 +1015,15 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox-log" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#2e887e91e34edc90a2341678781e9271e70bc210" +dependencies = [ + "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_event" version = "0.1.0" @@ -1119,7 +1138,7 @@ name = "scroll_derive" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1170,18 +1189,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1193,7 +1212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1214,7 +1233,7 @@ name = "smallvec" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1253,7 +1272,7 @@ name = "syn" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1279,18 +1298,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "thiserror-impl 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror-impl" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1465,7 +1484,7 @@ name = "toml" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1552,7 +1571,7 @@ dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1676,15 +1695,16 @@ dependencies = [ "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pcid 0.1.0", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1707,6 +1727,7 @@ dependencies = [ "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "" +"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" @@ -1730,7 +1751,7 @@ dependencies = [ "checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" "checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" "checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" -"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" @@ -1778,9 +1799,9 @@ dependencies = [ "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420" +"checksum proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" "checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" -"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -1794,6 +1815,7 @@ dependencies = [ "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git)" = "" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" @@ -1813,8 +1835,8 @@ dependencies = [ "checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" -"checksum serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" +"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" +"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" "checksum serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" @@ -1827,8 +1849,8 @@ dependencies = [ "checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e3711fd1c4e75b3eff12ba5c40dba762b6b65c5476e8174c1a664772060c49bf" -"checksum thiserror-impl 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2b85ba4c9aa32dd3343bd80eb8d22e9b54b7688c17ea3907f236885353b233" +"checksum thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f0570dc61221295909abdb95c739f2e74325e14293b2026b0a7e195091ec54ae" +"checksum thiserror-impl 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "227362df41d566be41a28f64401e07a043157c21c14b9785a0d8e256f940a8fd" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 3b1b2a622b..c1ef18ce37 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -18,8 +18,9 @@ crossbeam-channel = "0.4" futures = "0.3" plain = "0.2" lazy_static = "1.4" -spin = "0.4" +log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git" } redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 50ca1adccf..fedea2b399 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,13 +1,6 @@ #[macro_use] extern crate bitflags; -extern crate event; -extern crate plain; -extern crate syscall; -use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; -use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; - -use event::{Event, EventQueue}; use std::convert::TryInto; use std::fs::{self, File}; use std::future::Future; @@ -17,6 +10,12 @@ use std::pin::Pin; use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use std::env; + +use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; +use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; + +use event::{Event, EventQueue}; +use log::info; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; @@ -81,14 +80,30 @@ async fn handle_packet(hci: Arc, packet: Packet) -> Packet { } fn main() { + let mut args = env::args().skip(1); + + let mut name = args.next().expect("xhcid: no name provided"); + name.push_str("_xhci"); + // Daemonize if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { return; } + match redox_log::RedoxLogger::new("usb", "host", "xhci.log") { + Ok(logger) => match logger.with_stdout_mirror().enable() { + Ok(()) => { + println!("xhcid: enabled logger"); + log::set_max_level(log::LevelFilter::Trace); + } + Err(error) => eprintln!("xhcid: failed to set default logger: {}", error), + } + Err(error) => eprintln!("xhcid: failed to initialize logger: {}", error), + } + let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); - println!("XHCI PCI CONFIG: {:?}", pci_config); + info!("XHCI PCI CONFIG: {:?}", pci_config); let bar = pci_config.func.bars[0]; let irq = pci_config.func.legacy_interrupt_line; @@ -104,7 +119,7 @@ fn main() { }; let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); - println!("XHCI PCI FEATURES: {:?}", all_pci_features); + info!("XHCI PCI FEATURES: {:?}", all_pci_features); let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); @@ -114,12 +129,12 @@ fn main() { if has_msi && !msi_enabled && !has_msix { pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); - println!("Enabled MSI"); + info!("Enabled MSI"); msi_enabled = true; } if has_msix && !msix_enabled { pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); - println!("Enabled MSI-X"); + info!("Enabled MSI-X"); msix_enabled = true; } @@ -197,11 +212,6 @@ fn main() { std::thread::sleep(std::time::Duration::from_millis(300)); - let mut args = env::args().skip(1); - - let mut name = args.next().expect("xhcid: no name provided"); - name.push_str("_xhci"); - print!( "{}", format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq) From 74c77412bf960cd5bc5eb2fe95434ec80f5a0e78 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 5 Apr 2020 00:17:55 +0200 Subject: [PATCH 17/22] Replace all calls to [e]println with log macros. --- xhcid/src/xhci/context.rs | 3 +- xhcid/src/xhci/irq_reactor.rs | 33 +++++----- xhcid/src/xhci/mod.rs | 111 ++++++++++++++-------------------- xhcid/src/xhci/scheme.rs | 23 ++----- 4 files changed, 72 insertions(+), 98 deletions(-) diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 45023397cc..e971ad28a7 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; +use log::debug; use syscall::error::Result; use syscall::io::{Dma, Io, Mmio}; @@ -59,7 +60,7 @@ pub struct InputContext { } impl InputContext { pub fn dump_control(&self) { - println!( + debug!( "INPUT CONTEXT: {} {} [{} {} {} {} {}] {}", self.drop_context.read(), self.add_context.read(), diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 0abc6a2a9b..581e2214d2 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -10,6 +10,7 @@ use std::{io, mem, task, thread}; use std::os::unix::io::AsRawFd; use crossbeam_channel::{Sender, Receiver}; +use log::{debug, error, info, warn, trace}; use futures::Stream; use syscall::Io; @@ -106,7 +107,7 @@ impl IrqReactor { std::thread::yield_now(); } fn run_polling(mut self) { - println!("Running IRQ reactor in polling mode."); + debug!("Running IRQ reactor in polling mode."); let hci_clone = Arc::clone(&self.hci); 'event_loop: loop { @@ -133,7 +134,7 @@ impl IrqReactor { } } fn run_with_irq_file(mut self) { - println!("Running IRQ reactor with IRQ file and event queue"); + debug!("Running IRQ reactor with IRQ file and event queue"); let hci_clone = Arc::clone(&self.hci); let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); @@ -142,18 +143,18 @@ impl IrqReactor { let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() }; event_queue.add(irq_fd, move |_| -> io::Result> { - println!("IRQ event queue notified"); + trace!("IRQ event queue notified"); let mut buffer = [0u8; 8]; let _ = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); if !self.hci.received_irq() { // continue only when an IRQ to this device was received - println!("no interrupt pending"); + trace!("no interrupt pending"); return Ok(None); } - println!("IRQ reactor received an IRQ"); + trace!("IRQ reactor received an IRQ"); let _ = self.irq_file.as_mut().unwrap().write(&buffer); @@ -167,15 +168,15 @@ impl IrqReactor { let event_trb = &mut event_ring.ring.trbs[event_trb_index]; if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { - if count == 0 { println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } + if count == 0 { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } // no more events were found, continue the loop return Ok(None); } else { count += 1 } - println!("Found event TRB: {:?}", event_trb); + trace!("Found event TRB: {:?}", event_trb); if self.check_event_ring_full(event_trb.clone()) { - println!("Had to resize event TRB, retrying..."); + info!("Had to resize event TRB, retrying..."); hci_clone.event_handler_finished(); return Ok(None); } @@ -197,12 +198,12 @@ impl IrqReactor { let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); - println!("Updated ERDP to {:#0x}", dequeue_pointer); + debug!("Updated ERDP to {:#0x}", dequeue_pointer); self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); } fn handle_requests(&mut self) { - self.states.extend(self.receiver.try_iter().inspect(|req| println!("Received request: {:?}", req))); + self.states.extend(self.receiver.try_iter().inspect(|req| trace!("Received request: {:?}", req))); } fn acknowledge(&mut self, trb: Trb) { let mut index = 0; @@ -212,7 +213,7 @@ impl IrqReactor { match self.states[index].kind { StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) { - println!("Found matching command completion future"); + trace!("Found matching command completion future"); let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event @@ -224,7 +225,7 @@ impl IrqReactor { t }, None => { - println!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb); + warn!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb); continue; } }; @@ -235,12 +236,12 @@ impl IrqReactor { event_trb: trb.clone(), }); - println!("Waking up future with waker: {:?}", state.waker); + trace!("Waking up future with waker: {:?}", state.waker); state.waker.wake(); return; } else if trb.completion_trb_pointer().is_none() { - println!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); + warn!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); continue; } else { // The event TRB simply didn't match the current future @@ -290,7 +291,7 @@ impl IrqReactor { } } } - println!("Lost event TRB: {:?}", trb); + warn!("Lost event TRB: {:?}", trb); } fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { let mut index = 0; @@ -325,7 +326,7 @@ impl IrqReactor { /// Grows the event ring fn grow_event_ring(&mut self) { // TODO - println!("TODO: grow event ring"); + error!("TODO: grow event ring"); } pub fn run(mut self) { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 8e11e56781..6656b78fe9 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -11,6 +11,7 @@ use std::{mem, process, slice, sync::atomic, task, thread}; use chashmap::CHashMap; use crossbeam_channel::{Receiver, Sender}; +use log::{debug, error, info, trace, warn}; use serde::Deserialize; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; use syscall::flag::O_RDONLY; @@ -94,14 +95,11 @@ impl MsixInfo { impl Xhci { /// Gets descriptors, before the port state is initiated. async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) -> Result<()> { - println!("A"); let len = mem::size_of::(); let future = { - println!("B"); let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; let ring = port_state.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().expect("no ring for the default control pipe"); - println!("C"); let (cmd, cycle) = ring.next(); cmd.setup( @@ -117,24 +115,18 @@ impl Xhci { let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); cmd.status(0, true, true, false, false, cycle); - println!("D"); self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &ring, &ring.trbs[last_index]) }; - println!("E"); self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); - println!("F"); let trbs = future.await; let event_trb = trbs.event_trb; let status_trb = trbs.src_trb.unwrap(); - println!("G"); self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; - println!("H"); self.event_handler_finished(); - println!("I"); Ok(()) } @@ -242,7 +234,7 @@ impl EndpointState { impl Xhci { pub fn new(scheme_name: String, address: usize, interrupt_method: InterruptMethod, pcid_handle: PcidServerHandle) -> Result { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; - println!(" - CAP {:X}", address); + debug!("CAP REGS BASE {:X}", address); let page_size = { let memory_fd = syscall::open("memory:", O_RDONLY)?; @@ -253,52 +245,52 @@ impl Xhci { let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; - println!(" - OP {:X}", op_base); + debug!("OP REGS BASE {:X}", op_base); let (max_slots, max_ports) = { - println!(" - Wait for ready"); + debug!("Waiting for xHC becoming ready."); // Wait until controller is ready while op.usb_sts.readf(1 << 11) { - println!(" - Waiting for XHCI ready"); + trace!("Waiting for the xHC to be ready."); } - println!(" - Stop"); + debug!("Stopping the xHC"); // Set run/stop to 0 op.usb_cmd.writef(1, false); - println!(" - Wait for not running"); + debug!("Waiting for the xHC to stop."); // Wait until controller not running while !op.usb_sts.readf(1) { - println!(" - Waiting for XHCI stopped"); + trace!("Waiting for the xHC to stop."); } - println!(" - Reset"); + debug!("Resetting the xHC."); op.usb_cmd.writef(1 << 1, true); while op.usb_sts.readf(1 << 1) { - println!(" - Waiting for XHCI reset"); + trace!("Waiting for the xHC to reset."); } - println!(" - Read max slots"); + debug!("Reading max slots."); let max_slots = cap.max_slots(); let max_ports = cap.max_ports(); - println!(" - Max Slots: {}, Max Ports {}", max_slots, max_ports); + info!("xHC max slots: {}, max ports: {}", max_slots, max_ports); (max_slots, max_ports) }; let port_base = op_base + 0x400; let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) }; - println!(" - PORT {:X}", port_base); + debug!("PORT BASE {:X}", port_base); let db_base = address + cap.db_offset.read() as usize; let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut Doorbell, 256) }; - println!(" - DOORBELL {:X}", db_base); + debug!("DOORBELL REGS BASE {:X}", db_base); let run_base = address + cap.rts_offset.read() as usize; let run = unsafe { &mut *(run_base as *mut RuntimeRegs) }; - println!(" - RUNTIME {:X}", run_base); + debug!("RUNTIME REGS BASE {:X}", run_base); // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the // DMA allocation (which is at least a 4k page). @@ -345,42 +337,42 @@ impl Xhci { pub fn init(&mut self, max_slots: u8) -> Result<()> { // Set enabled slots - println!(" - Set enabled slots to {}", max_slots); + debug!("Setting enabled slots to {}.", max_slots); self.op.get_mut().unwrap().config.write(max_slots as u32); - println!(" - Enabled Slots: {}", self.op.get_mut().unwrap().config.read() & 0xFF); + debug!("Enabled Slots: {}", self.op.get_mut().unwrap().config.read() & 0xFF); // Set device context address array pointer let dcbaap = self.dev_ctx.dcbaap(); - println!(" - Write DCBAAP: {:X}", dcbaap); + debug!("Writing DCBAAP: {:X}", dcbaap); self.op.get_mut().unwrap().dcbaap.write(dcbaap as u64); // Set command ring control register let crcr = self.cmd.get_mut().unwrap().register(); assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); - println!(" - Write CRCR: {:X}", crcr); + debug!("Writing CRCR: {:X}", crcr); self.op.get_mut().unwrap().crcr.write(crcr as u64); // Set event ring segment table registers - println!(" - Interrupter 0: {:X}", self.run.get_mut().unwrap().ints.as_ptr() as usize); + debug!("Interrupter 0: {:p}", self.run.get_mut().unwrap().ints.as_ptr()); { let int = &mut self.run.get_mut().unwrap().ints[0]; let erstz = 1; - println!(" - Write ERSTZ: {}", erstz); + debug!("Writing ERSTZ: {}", erstz); int.erstsz.write(erstz); let erdp = self.primary_event_ring.get_mut().unwrap().erdp(); - println!(" - Write ERDP: {:X}", erdp); + debug!("Writing ERDP: {:X}", erdp); int.erdp.write(erdp as u64 | (1 << 3)); let erstba = self.primary_event_ring.get_mut().unwrap().erstba(); - println!(" - Write ERSTBA: {:X}", erstba); + debug!("Writing ERSTBA: {:X}", erstba); int.erstba.write(erstba as u64); - println!(" - Write IMODC and IMODI: {} and {}", 0, 0); + debug!("Writing IMODC and IMODI: {} and {}", 0, 0); int.imod.write(0); - println!(" - Enable interrupts"); + debug!("Enabling Primary Interrupter."); int.iman.writef(1 << 1 | 1, true); } @@ -390,22 +382,20 @@ impl Xhci { self.setup_scratchpads()?; // Set run/stop to 1 - println!(" - Start"); + info!("Starting xHC."); self.op.get_mut().unwrap().usb_cmd.writef(1, true); // Wait until controller is running - println!(" - Wait for running"); + debug!("Waiting for start request to complete."); while self.op.get_mut().unwrap().usb_sts.readf(1) { - println!(" - Waiting for XHCI running"); + trace!("Waiting for XHCI to report running status."); } - println!("IP={}", self.run.get_mut().unwrap().ints[0].iman.readf(1)); - // Ring command doorbell - println!(" - Ring doorbell"); + debug!("Ringing command doorbell."); self.dbs.get_mut().unwrap()[0].write(0); - println!(" - XHCI initialized"); + info!("XHCI initialized."); if self.cap.cic() { self.op.get_mut().unwrap().set_cie(true); @@ -422,6 +412,7 @@ impl Xhci { } let scratchpad_buf_arr = ScratchpadBufferArray::new(self.page_size,buf_count)?; self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; + debug!("Setting up {} scratchpads, at {:#0x}", buf_count, scratchpad_buf_arr.register()); self.scratchpad_buf_arr = Some(scratchpad_buf_arr); Ok(()) @@ -452,7 +443,7 @@ impl Xhci { } pub async fn probe(&self) -> Result<()> { - println!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); + info!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); let port_count = { self.ports.lock().unwrap().len() }; @@ -461,29 +452,26 @@ impl Xhci { let port = &self.ports.lock().unwrap()[i]; (port.read(), port.state(), port.speed(), port.flags()) }; - println!( - " + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", + info!( + "XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags ); if flags.contains(port::PortFlags::PORT_CCS) { - //TODO: Link TRB when running to the end of the ring buffer - - println!(" - Enable slot"); - let slot_ty = self .supported_protocol(i as u8) .expect("Failed to find supported protocol information for port") .proto_slot_ty(); - println!("Got slot type: {}", slot_ty); + debug!("Slot type: {}", slot_ty); + debug!("Enabling slot."); let slot = self.enable_port_slot(slot_ty).await?; - println!(" - Slot {}", slot); + info!("Enabled port {}, which the xHC mapped to {}", i, slot); let mut input = Dma::::zeroed()?; let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; - println!("Addressed device"); + info!("Addressed device"); // TODO: Should the descriptors be cached in PortState, or refetched? @@ -504,9 +492,7 @@ impl Xhci { }; self.port_states.insert(i, port_state); - println!("pre get desc"); let dev_desc = self.get_desc(i, slot).await?; - println!("post get desc"); self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); { @@ -520,7 +506,7 @@ impl Xhci { /*match self.spawn_drivers(i, &mut port_state) { Ok(()) => (), - Err(err) => println!("Failed to spawn driver for port {}: `{}`", i, err), + Err(err) => error!("Failed to spawn driver for port {}: `{}`", i, err), }*/ } @@ -648,14 +634,14 @@ impl Xhci { let input_context_physical = input_context.physical(); - println!("pre_address_device"); let (event_trb, _) = self.execute_command(|trb, cycle| { trb.address_device(slot, input_context_physical, false, cycle) }).await; - println!("post_address_device"); if event_trb.completion_code() != TrbCompletionCode::Success as u8 { - println!("Failed to address device at slot {} (port {})", slot, i); + error!("Failed to address device at slot {} (port {})", slot, i); + self.event_handler_finished(); + return Err(Error::new(EIO)); } self.event_handler_finished(); @@ -690,13 +676,10 @@ impl Xhci { if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. - println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); - println!("MSI-X PB={}", self.msix_info_mut().unwrap().pba(0)); - let mut msix = self.msix_info_mut().unwrap(); - let entry = msix.table_entry_pointer(0); - println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); + trace!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); true } else if runtime_regs.ints[0].iman.readf(1) { + trace!("Successfully received INTx# interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is // a special register to specify whether the IRQ actually came from the xHC. runtime_regs.ints[0].iman.writef(1, true); @@ -734,7 +717,7 @@ impl Xhci { .map(|subclass| subclass == ifdesc.sub_class) .unwrap_or(true) }) { - println!("Loading driver \"{}\"", driver.name); + info!("Loading subdriver\"{}\"", driver.name); let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; let if_proto = ifdesc.protocol; @@ -865,10 +848,10 @@ pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { let receiver = hci.irq_reactor_receiver.clone(); let hci_clone = Arc::clone(&hci); - println!("About to start IRQ reactor"); + debug!("About to start IRQ reactor"); *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { - println!("Started IRQ reactor thread"); + info!("Started IRQ reactor thread"); IrqReactor::new(hci_clone, receiver, irq_file).run() })); } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 3709b18845..c39cf56163 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -4,6 +4,7 @@ use std::sync::atomic; use std::{cmp, io, mem, path, str}; use futures::executor::block_on; +use log::{debug, error, info, warn, trace}; use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; @@ -235,9 +236,7 @@ impl Xhci { self.next_command_completion_event_trb(&*command_ring, command_trb) }; - println!("Ringing doorbell"); self.dbs.lock().unwrap()[0].write(0); - println!("Doorbell rung"); let trbs = next_event.await; let event_trb = trbs.event_trb; @@ -381,14 +380,14 @@ impl Xhci { if event_trb.completion_code() != TrbCompletionCode::ShortPacket as u8 && event_trb.transfer_length() != 0 { - println!( + error!( "Event trb didn't yield a short packet, but some bytes were not transferred" ); return Err(Error::new(EIO)); } // TODO: Handle event data - println!("EVENT DATA: {:?}", event_trb.event_data()); + debug!("EVENT DATA: {:?}", event_trb.event_data()); Ok(event_trb) } @@ -925,41 +924,33 @@ impl Xhci { port_id: usize, slot: u8, ) -> Result { - println!("Checkpoint 1"); let ports = self.ports.lock().unwrap(); let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } - println!("Checkpoint 2"); let raw_dd = self.fetch_dev_desc(port_id, slot).await?; - println!("Checkpoint 3"); let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { - println!("Checkpoint 4a"); Some(self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str).await?) } else { None }, if raw_dd.product_str > 0 { - println!("Checkpoint 4b"); Some(self.fetch_string_desc(port_id, slot, raw_dd.product_str).await?) } else { None }, if raw_dd.serial_str > 0 { - println!("Checkpoint 4c"); Some(self.fetch_string_desc(port_id, slot, raw_dd.serial_str).await?) } else { None }, ); - println!("Checkpoint 5"); let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?; - println!("Checkpoint 6"); let supports_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); @@ -969,9 +960,7 @@ impl Xhci { let mut config_descs = SmallVec::new(); for index in 0..raw_dd.configurations { - println!("Checkpoint 7: {}", index); let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; - println!("Checkpoint 8: {}", index); let extra_length = desc.total_length as usize - mem::size_of_val(&desc); let data = &data[..extra_length]; @@ -2001,7 +1990,7 @@ impl Xhci { /// # Locking /// This function locks `Xhci::run`. pub fn event_handler_finished(&self) { - println!("Event handler finished"); + trace!("Event handler finished"); // write 1 to EHB to clear it self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true); } @@ -2010,7 +1999,7 @@ pub fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Resul if event_trb.completion_code() == TrbCompletionCode::Success as u8 { Ok(()) } else { - println!("{} command (TRB {:?}) failed with event trb {:?}", name, command_trb, event_trb); + error!("{} command (TRB {:?}) failed with event trb {:?}", name, command_trb, event_trb); Err(Error::new(EIO)) } } @@ -2018,7 +2007,7 @@ pub fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb if event_trb.completion_code() == TrbCompletionCode::Success as u8 || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 { Ok(()) } else { - println!("{} transfer (TRB {:?}) failed with event trb {:?}", name, transfer_trb, event_trb); + error!("{} transfer (TRB {:?}) failed with event trb {:?}", name, transfer_trb, event_trb); Err(Error::new(EIO)) } } From f4398854fc34966da9b929b68ba0e727777abc26 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 5 Apr 2020 23:21:24 +0200 Subject: [PATCH 18/22] Add trace debug printlns for opening handles. --- xhcid/src/xhci/scheme.rs | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c39cf56163..9289880953 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,7 +1,8 @@ use std::convert::TryFrom; use std::io::prelude::*; +use std::ops::Deref; use std::sync::atomic; -use std::{cmp, io, mem, path, str}; +use std::{cmp, fmt, io, mem, path, str}; use futures::executor::block_on; use log::{debug, error, info, warn, trace}; @@ -53,6 +54,7 @@ pub enum EndpIfState { } /// Subdirs of an endpoint +#[derive(Debug)] pub enum EndpointHandleTy { /// portX/endpoints/Y/data. Allows clients to read and write data associated with ctl requests. Data, @@ -64,7 +66,7 @@ pub enum EndpointHandleTy { Root(usize, Vec), // offset, content } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum PortTransferState { /// Ready to read or write to do another transfer Ready, @@ -81,6 +83,7 @@ pub enum PortReqState { Tmp, } +#[derive(Debug)] pub enum Handle { TopLevel(usize, Vec), // offset, contents (ports) Port(usize, usize, Vec), // port, offset, contents @@ -92,6 +95,34 @@ pub enum Handle { ConfigureEndpoints(usize), // port } +#[derive(Clone, Copy)] +struct DmaSliceDbg<'a, T>(&'a Dma<[T]>); + +impl<'a, T> fmt::Debug for DmaSliceDbg<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let DmaSliceDbg(dma) = self; + + f.debug_struct("Dma") + .field("phys_ptr", &(dma.physical() as *const u8)) + .field("virt_ptr", &(dma.deref().as_ptr() as *const u8)) + .field("length", &(dma.len() * mem::size_of::())) + .finish() + } +} + +impl fmt::Debug for PortReqState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Init => f.debug_struct("PortReqState::Init").finish(), + Self::WaitingForDeviceBytes(ref dma, setup) => f.debug_tuple("PortReqState::WaitingForDeviceBytes").field(&DmaSliceDbg(dma)).field(&setup).finish(), + Self::WaitingForHostBytes(ref dma, setup) => f.debug_tuple("PortReqState::WaitingForHostBytes").field(&DmaSliceDbg(dma)).field(&setup).finish(), + Self::TmpSetup(setup) => f.debug_tuple("PortReqState::TmpSetup").field(&setup).finish(), + Self::Tmp => f.debug_struct("PortReqState::Init").finish(), + } + } +} + + // TODO: Even though the driver interface descriptors are originally intended for JSON, they should suffice... for // now. @@ -1370,6 +1401,9 @@ impl Scheme for Xhci { }; let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed); + + trace!("OPENED {} to FD={}, handle: {:?}", path_str, fd, handle); + self.handles.insert(fd, handle); Ok(fd) From 0e802e208575b2ceab6c6837c4c958f6625dd328 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 6 Apr 2020 00:54:15 +0200 Subject: [PATCH 19/22] Fix two deadlocks. --- Cargo.lock | 11 +++++----- xhcid/src/driver_interface.rs | 2 +- xhcid/src/main.rs | 2 +- xhcid/src/xhci/scheme.rs | 38 ++++++++++++++++++++--------------- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c56aa7049..d93fb99f01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -839,7 +839,7 @@ dependencies = [ "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1018,10 +1018,11 @@ dependencies = [ [[package]] name = "redox-log" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#2e887e91e34edc90a2341678781e9271e70bc210" +source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#08693d48b2d7b56fcb07a1e62e257bacce749cef" dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1207,7 +1208,7 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1702,7 +1703,7 @@ dependencies = [ "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1837,7 +1838,7 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" "checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" -"checksum serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" +"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 1d0968f402..8b560a5cd1 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -14,7 +14,7 @@ use thiserror::Error; pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK}; -#[derive(Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct ConfigureEndpointsReq { /// Index into the configuration descriptors of the device descriptor. pub config_desc: u8, diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index fedea2b399..f8dfd8c520 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -92,7 +92,7 @@ fn main() { match redox_log::RedoxLogger::new("usb", "host", "xhci.log") { Ok(logger) => match logger.with_stdout_mirror().enable() { - Ok(()) => { + Ok(_) => { println!("xhcid: enabled logger"); log::set_max_level(log::LevelFilter::Trace); } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 9289880953..70ea13db4e 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -288,10 +288,10 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { - let mut port_state = self.port_state_mut(port_num)?; - let slot = port_state.slot; + let (future, slot) = { + let mut port_state = self.port_state_mut(port_num)?; + let slot = port_state.slot; - let future = { let mut endpoint_state = port_state .endpoint_states .get_mut(&0).ok_or(Error::new(EIO))?; @@ -322,7 +322,7 @@ impl Xhci { let ent = false; cmd.status(interrupter, tk == TransferKind::In, ioc, ch, ent, cycle); - self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), ring, &ring.trbs[last_index]) + (self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), ring, &ring.trbs[last_index]), slot) }; self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); @@ -423,6 +423,8 @@ impl Xhci { Ok(event_trb) } async fn device_req_no_data(&self, port: usize, req: usb::Setup) -> Result<()> { + trace!("DEVICE_REQ_NO_DATA port {}, req: {:?}", port, req); + self.execute_control_transfer( port, req, @@ -433,6 +435,7 @@ impl Xhci { Ok(()) } async fn set_configuration(&self, port: usize, config: u8) -> Result<()> { + debug!("Setting configuration value {} to port {}", config, port); self.device_req_no_data(port, usb::Setup::set_configuration(config)).await } async fn set_interface( @@ -441,6 +444,7 @@ impl Xhci { interface_num: u8, alternate_setting: u8, ) -> Result<()> { + debug!("Setting interface value {} (alternate setting {}) to port {}", interface_num, alternate_setting, port); self.device_req_no_data( port, usb::Setup::set_interface(interface_num, alternate_setting), @@ -556,6 +560,8 @@ impl Xhci { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; + debug!("Running configure endpoints command, at port {}, request: {:?}", port, req); + if (!self.cap.cic() || !self.op.lock().unwrap().cie()) && (req.config_desc != 0 || req.interface_desc != None || req.alternate_setting != None) { @@ -623,7 +629,7 @@ impl Xhci { for endp_idx in 0..endp_desc_count as u8 { let endp_num = endp_idx + 1; - let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; let dev_desc = port_state.dev_desc.as_ref().unwrap(); let endpoints = &dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; @@ -683,8 +689,6 @@ impl Xhci { assert_eq!(max_error_count & 0x3, max_error_count); assert_ne!(ep_ty, 0); // 0 means invalid. - let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; - let ring_ptr = if usb_log_max_streams.is_some() { let mut array = StreamContextArray::new(1 << (primary_streams + 1))?; @@ -726,7 +730,6 @@ impl Xhci { }; assert_eq!(primary_streams & 0x1F, primary_streams); - let port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; let mut input_context = port_state.input_context.lock().unwrap(); input_context.add_context.writef(1 << endp_num_xhc, true); @@ -755,16 +758,19 @@ impl Xhci { .write(u32::from(avg_trb_len) | (u32::from(max_esit_payload_lo) << 16)); } - let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let slot = port_state.slot; - let input_context_physical = port_state.input_context.lock().unwrap().physical(); + { + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let slot = port_state.slot; + let input_context_physical = port_state.input_context.lock().unwrap().physical(); - let (event_trb, command_trb) = self.execute_command(|trb, cycle| { - trb.configure_endpoint(slot, input_context_physical, cycle) - }).await; - self.event_handler_finished(); + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { + trb.configure_endpoint(slot, input_context_physical, cycle) + }).await; - handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; + self.event_handler_finished(); + + handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; + } // Tell the device about this configuration. self.set_configuration(port, configuration_value).await?; From 57bde84edb0f5ca1b84d444e63c91807597179c1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 6 Apr 2020 13:58:26 +0200 Subject: [PATCH 20/22] usbscsid works again, AFAICT. --- xhcid/src/xhci/mod.rs | 6 +++--- xhcid/src/xhci/scheme.rs | 34 ++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 6656b78fe9..d8f3348f71 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -330,7 +330,7 @@ impl Xhci { irq_reactor_receiver, }; - xhci.init(max_slots); + xhci.init(max_slots)?; Ok(xhci) } @@ -424,7 +424,7 @@ impl Xhci { let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)).await; - self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb); + self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb)?; self.event_handler_finished(); Ok(event_trb.event_slot()) @@ -432,7 +432,7 @@ impl Xhci { pub async fn disable_port_slot(&self, slot: u8) -> Result<()> { let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)).await; - self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb); + self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb)?; self.event_handler_finished(); Ok(()) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 70ea13db4e..039da4431f 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -352,6 +352,7 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { + let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?; let mut port_state = self.port_state_mut(port_num)?; let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { @@ -359,7 +360,6 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let slot = port_state.slot; let endp_state = port_state @@ -393,7 +393,7 @@ impl Xhci { } }; - let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(cfg_idx)).ok_or(Error::new(EIO))?.interface_descs.get(usize::from(if_idx)).ok_or(Error::new(EIO))?.endpoints.get(usize::from(endp_idx)).ok_or(Error::new(EBADFD))?; self.dbs.lock().unwrap()[usize::from(slot)].write(Self::endp_doorbell( endp_num, @@ -401,6 +401,7 @@ impl Xhci { if has_streams { stream_id } else { 0 }, )); + drop(port_state); let trbs = future.await; let event_trb = trbs.event_trb; let transfer_trb = trbs.src_trb.unwrap(); @@ -575,7 +576,10 @@ impl Xhci { } let (endp_desc_count, new_context_entries, configuration_value) = { - let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; + port_state.cfg_idx = Some(req.config_desc); + port_state.if_idx = Some(req.interface_desc.unwrap_or(0)); + let config_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; let endpoints = &config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; @@ -811,6 +815,8 @@ impl Xhci { let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; dma_buffer.copy_from_slice(sbuf); + trace!("TRANSFER_WRITE port {} ep {}, buffer at {:p}, size {}, dma buffer {:?}", port_num, endp_idx + 1, sbuf.as_ptr(), sbuf.len(), DmaSliceDbg(&dma_buffer)); + let (completion_code, bytes_transferred, _) = self.transfer( port_num, endp_idx, @@ -854,19 +860,24 @@ impl Xhci { // TODO: Check that only readable enpoints are read, etc. let endp_num = endp_idx + 1; - let port_state = self + let mut port_state = self .port_states .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; + let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { + (Some(c), Some(i)) => (c, i), + _ => return Err(Error::new(EIO)), + }; + let endp_desc: &EndpDesc = port_state .dev_desc .as_ref().unwrap() .config_descs - .get(0) + .get(usize::from(cfg_idx)) .ok_or(Error::new(EIO))? .interface_descs - .get(0) + .get(usize::from(if_idx)) .ok_or(Error::new(EIO))? .endpoints .get(endp_idx as usize) @@ -915,6 +926,8 @@ impl Xhci { let mut bytes_left = dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0); + drop(port_state); + let event = self.execute_transfer( port_num, endp_num, @@ -1489,6 +1502,9 @@ impl Scheme for Xhci { fn seek(&self, fd: usize, pos: usize, whence: usize) -> Result { 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) @@ -1522,6 +1538,7 @@ impl Scheme for Xhci { fn read(&self, fd: usize, buf: &mut [u8]) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + trace!("READ fd={}, handle={:?}, buf=(addr {:p}, length {})", fd, guard, buf.as_ptr(), buf.len()); match &mut *guard { Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) @@ -1569,12 +1586,14 @@ impl Scheme for Xhci { } &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); + drop(guard); // release the lock block_on(self.handle_port_req_read(fd, port_num, state, buf)) } } } fn write(&self, fd: usize, buf: &[u8]) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + trace!("WRITE fd={}, handle={:?}, buf=(addr {:p}, length {})", fd, guard, buf.as_ptr(), buf.len()); match &mut *guard { &mut Handle::ConfigureEndpoints(port_num) => { @@ -1588,6 +1607,7 @@ impl Scheme for Xhci { }, &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); + drop(guard); // release the lock block_on(self.handle_port_req_write(fd, port_num, state, buf)) } // TODO: Introduce PortReqState::Waiting, which this write call changes to @@ -1892,6 +1912,7 @@ impl Xhci { if buf.len() > total_bytes_to_transfer as usize - bytes_transferred as usize { return Err(Error::new(EINVAL)); } + drop(port_state); let (completion_code, some_bytes_transferred) = self.transfer_write(port_num, endp_num - 1, buf).await?; let result = Self::transfer_result(completion_code, some_bytes_transferred); @@ -1985,6 +2006,7 @@ impl Xhci { return Err(Error::new(EINVAL)); } + drop(port_state); let (completion_code, some_bytes_transferred) = self.transfer_read(port_num, endp_num - 1, buf).await?; From 81afdb2750b5128b92723c129fe3d6867fca2002 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 12 Apr 2020 11:37:10 +0200 Subject: [PATCH 21/22] Remove two todo comments. --- pcid/src/main.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 63637cb50b..daef5c699a 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -62,8 +62,6 @@ impl DriverHandler { PcidClientRequest::RequestFeatures => { PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability { PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))), - // TODO: For MSI-X to actually be enabled, MSI also has to be enabled. - // How should this be reported to the subdrivers? PciCapability::MsiX(msix) => Some((PciFeature::MsiX, FeatureStatus::enabled(msix.msix_enabled()))), _ => None, }).collect()) @@ -344,9 +342,6 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, func, }; - // TODO: find a better way to pass the header data down to the - // device driver, making passing the capabilities list etc - // posible. let mut args = args.iter(); if let Some(program) = args.next() { let mut command = Command::new(program); From da188109d49955caa12646890e237d08efce862f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 19 Apr 2020 17:11:08 +0200 Subject: [PATCH 22/22] Change the default log level to debug. --- xhcid/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index f8dfd8c520..66a84b2262 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -94,7 +94,7 @@ fn main() { Ok(logger) => match logger.with_stdout_mirror().enable() { Ok(_) => { println!("xhcid: enabled logger"); - log::set_max_level(log::LevelFilter::Trace); + log::set_max_level(log::LevelFilter::Debug); } Err(error) => eprintln!("xhcid: failed to set default logger: {}", error), }