From 012eb46cb97322c420946f52f55a65eee69603c0 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 26 Feb 2024 23:04:51 +0200 Subject: [PATCH] bus/usb: basic xHCI implementation --- Cargo.toml | 5 +- arch/interface/src/lib.rs | 1 + arch/x86_64/src/lib.rs | 12 +- driver/block/ahci/src/lib.rs | 12 +- driver/block/nvme/Cargo.toml | 1 + driver/block/nvme/src/drive.rs | 2 +- driver/block/nvme/src/lib.rs | 2 +- driver/bus/usb/Cargo.toml | 18 + driver/bus/usb/src/bus.rs | 51 ++ driver/bus/usb/src/class_driver/mod.rs | 203 ++++++ driver/bus/usb/src/communication.rs | 92 +++ driver/bus/usb/src/descriptor.rs | 146 ++++ driver/bus/usb/src/device.rs | 191 +++++ driver/bus/usb/src/info.rs | 84 +++ driver/bus/usb/src/lib.rs | 19 + driver/bus/usb/src/pipe/control.rs | 323 +++++++++ driver/bus/usb/src/pipe/interrupt.rs | 32 + driver/bus/usb/src/pipe/mod.rs | 12 + driver/input/Cargo.toml | 11 + .../input.rs => driver/input/src/lib.rs | 13 +- driver/usb/xhci/Cargo.toml | 22 + driver/usb/xhci/src/lib.rs | 484 +++++++++++++ driver/usb/xhci/src/pipe.rs | 88 +++ driver/usb/xhci/src/regs.rs | 240 +++++++ driver/usb/xhci/src/ring.rs | 656 ++++++++++++++++++ lib/vfs/src/lib.rs | 9 +- libk/libk-mm/src/lib.rs | 60 +- libk/libk-thread/src/lib.rs | 13 +- libk/libk-thread/src/sync.rs | 84 ++- libk/src/lib.rs | 16 +- src/arch/x86_64/apic/ioapic.rs | 8 +- src/arch/x86_64/apic/local.rs | 4 +- src/arch/x86_64/mod.rs | 17 +- src/arch/x86_64/peripherals/ps2/mod.rs | 11 +- src/device/mod.rs | 1 - src/init.rs | 5 +- tools/gentables/src/main.rs | 2 - 37 files changed, 2881 insertions(+), 69 deletions(-) create mode 100644 driver/bus/usb/Cargo.toml create mode 100644 driver/bus/usb/src/bus.rs create mode 100644 driver/bus/usb/src/class_driver/mod.rs create mode 100644 driver/bus/usb/src/communication.rs create mode 100644 driver/bus/usb/src/descriptor.rs create mode 100644 driver/bus/usb/src/device.rs create mode 100644 driver/bus/usb/src/info.rs create mode 100644 driver/bus/usb/src/lib.rs create mode 100644 driver/bus/usb/src/pipe/control.rs create mode 100644 driver/bus/usb/src/pipe/interrupt.rs create mode 100644 driver/bus/usb/src/pipe/mod.rs create mode 100644 driver/input/Cargo.toml rename src/device/input.rs => driver/input/src/lib.rs (93%) create mode 100644 driver/usb/xhci/Cargo.toml create mode 100644 driver/usb/xhci/src/lib.rs create mode 100644 driver/usb/xhci/src/pipe.rs create mode 100644 driver/usb/xhci/src/regs.rs create mode 100644 driver/usb/xhci/src/ring.rs diff --git a/Cargo.toml b/Cargo.toml index 4941a6c0..08935458 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,11 +26,14 @@ kernel-arch = { path = "arch" } # Drivers ygg_driver_pci = { path = "driver/bus/pci" } +ygg_driver_usb = { path = "driver/bus/usb" } ygg_driver_block = { path = "driver/block/core" } ygg_driver_net_core = { path = "driver/net/core" } ygg_driver_net_loopback = { path = "driver/net/loopback" } ygg_driver_virtio_net = { path = "driver/virtio/net", features = ["pci"] } ygg_driver_ahci = { path = "driver/block/ahci" } +ygg_driver_usb_xhci = { path = "driver/usb/xhci" } +ygg_driver_input = { path = "driver/input" } kernel-fs = { path = "driver/fs/kernel-fs" } memfs = { path = "driver/fs/memfs" } @@ -64,8 +67,6 @@ yboot-proto = { git = "https://git.alnyan.me/yggdrasil/yboot-proto.git" } aml = { git = "https://github.com/alnyan/acpi.git", branch = "acpi-system" } acpi_lib = { git = "https://github.com/alnyan/acpi.git", package = "acpi", branch = "acpi-system" } acpi-system = { git = "https://github.com/alnyan/acpi-system.git" } -# TODO currently only supported here -xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" } ygg_driver_nvme = { path = "driver/block/nvme" } kernel-arch-x86_64 = { path = "arch/x86_64" } diff --git a/arch/interface/src/lib.rs b/arch/interface/src/lib.rs index 2498437f..2815fed1 100644 --- a/arch/interface/src/lib.rs +++ b/arch/interface/src/lib.rs @@ -29,6 +29,7 @@ pub trait Architecture: Sized { fn idle_task() -> extern "C" fn(usize) -> !; fn cpu_count() -> usize; + fn cpu_index() -> u32; // Interrupt management fn interrupt_mask() -> bool; diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index 4f3a6289..86158492 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -1,5 +1,11 @@ #![no_std] -#![feature(effects, strict_provenance, asm_const, naked_functions)] +#![feature( + effects, + strict_provenance, + asm_const, + naked_functions, + trait_upcasting +)] extern crate alloc; @@ -124,6 +130,10 @@ impl Architecture for ArchitectureImpl { CPU_COUNT.load(Ordering::Acquire) } + fn cpu_index() -> u32 { + CpuImpl::::local().id() + } + fn interrupt_mask() -> bool { let mut flags: u64; unsafe { diff --git a/driver/block/ahci/src/lib.rs b/driver/block/ahci/src/lib.rs index 8f1aa9ad..b3f74369 100644 --- a/driver/block/ahci/src/lib.rs +++ b/driver/block/ahci/src/lib.rs @@ -182,12 +182,14 @@ impl InterruptHandler for AhciController { let is = regs.IS.get(); if is != 0 { - // Clear global interrupt status - regs.IS.set(u32::MAX); + if let Some(ports) = self.ports.try_get() { + // Clear global interrupt status + regs.IS.set(u32::MAX); - for &port in self.ports.get() { - if is & (1 << port.index) != 0 { - port.handle_pending_interrupts(); + for &port in ports { + if is & (1 << port.index) != 0 { + port.handle_pending_interrupts(); + } } } } diff --git a/driver/block/nvme/Cargo.toml b/driver/block/nvme/Cargo.toml index b6c60cd4..611d52a3 100644 --- a/driver/block/nvme/Cargo.toml +++ b/driver/block/nvme/Cargo.toml @@ -9,6 +9,7 @@ authors = ["Mark Poliakov "] [dependencies] yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" } libk-util = { path = "../../../libk/libk-util" } +libk-thread = { path = "../../../libk/libk-thread" } libk-mm = { path = "../../../libk/libk-mm" } device-api = { path = "../../../lib/device-api", features = ["derive"] } vfs = { path = "../../../lib/vfs" } diff --git a/driver/block/nvme/src/drive.rs b/driver/block/nvme/src/drive.rs index c353f2b5..49bb6443 100644 --- a/driver/block/nvme/src/drive.rs +++ b/driver/block/nvme/src/drive.rs @@ -2,8 +2,8 @@ use core::task::Poll; use alloc::{boxed::Box, format}; use kernel_fs::devfs; -use libk::cpu_index; use libk_mm::address::AsPhysicalAddress; +use libk_thread::cpu_index; use libk_util::waker::QueueWaker; use ygg_driver_block::{ probe_partitions, IoOperation, IoRequest, IoSubmissionId, NgBlockDevice, NgBlockDeviceWrapper, diff --git a/driver/block/nvme/src/lib.rs b/driver/block/nvme/src/lib.rs index 08b1e231..56467f78 100644 --- a/driver/block/nvme/src/lib.rs +++ b/driver/block/nvme/src/lib.rs @@ -17,11 +17,11 @@ use device_api::{ Device, }; use drive::NvmeDrive; -use libk::{cpu_count, cpu_index, runtime}; use libk_mm::{ address::{IntoRaw, PhysicalAddress}, device::DeviceMemoryIo, }; +use libk_thread::{cpu_count, cpu_index, runtime}; use libk_util::{ sync::{IrqGuard, IrqSafeSpinlock}, OneTimeInit, diff --git a/driver/bus/usb/Cargo.toml b/driver/bus/usb/Cargo.toml new file mode 100644 index 00000000..b6b70c3a --- /dev/null +++ b/driver/bus/usb/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "ygg_driver_usb" +version = "0.1.0" +edition = "2021" +authors = ["Mark Poliakov "] + +[dependencies] +yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" } +device-api = { path = "../../../lib/device-api", features = ["derive"] } +ygg_driver_input = { path = "../../input" } + +libk-util = { path = "../../../libk/libk-util" } +libk-mm = { path = "../../../libk/libk-mm" } +libk-thread = { path = "../../../libk/libk-thread" } + +log = "0.4.20" +bytemuck = { version = "1.14.0", features = ["derive"] } +futures-util = { version = "0.3.28", default-features = false, features = ["alloc", "async-await"] } diff --git a/driver/bus/usb/src/bus.rs b/driver/bus/usb/src/bus.rs new file mode 100644 index 00000000..e99b69ad --- /dev/null +++ b/driver/bus/usb/src/bus.rs @@ -0,0 +1,51 @@ +use core::sync::atomic::{AtomicU16, Ordering}; + +use alloc::{collections::BTreeMap, sync::Arc}; +use libk_util::{queue::UnboundedMpmcQueue, sync::spin_rwlock::IrqSafeRwLock}; + +use crate::{ + class_driver, + device::{UsbBusAddress, UsbDeviceAccess}, + UsbHostController, +}; + +pub struct UsbBusManager { + busses: IrqSafeRwLock>, + devices: IrqSafeRwLock>>, + + last_bus_address: AtomicU16, +} + +impl UsbBusManager { + pub fn register_bus(hc: &'static dyn UsbHostController) -> u16 { + let i = BUS_MANAGER.last_bus_address.fetch_add(1, Ordering::AcqRel); + BUS_MANAGER.busses.write().insert(i, hc); + i + } + + pub fn register_device(device: Arc) { + BUS_MANAGER + .devices + .write() + .insert(device.bus_address(), device.clone()); + + QUEUE.push_back(device); + } +} + +pub async fn bus_handler() { + loop { + let new_device = QUEUE.pop_front().await; + log::debug!("New device connected: {}", new_device.bus_address()); + + class_driver::spawn_driver(new_device).await.ok(); + } +} + +static BUS_MANAGER: UsbBusManager = UsbBusManager { + busses: IrqSafeRwLock::new(BTreeMap::new()), + devices: IrqSafeRwLock::new(BTreeMap::new()), + + last_bus_address: AtomicU16::new(0), +}; +static QUEUE: UnboundedMpmcQueue> = UnboundedMpmcQueue::new(); diff --git a/driver/bus/usb/src/class_driver/mod.rs b/driver/bus/usb/src/class_driver/mod.rs new file mode 100644 index 00000000..21823a05 --- /dev/null +++ b/driver/bus/usb/src/class_driver/mod.rs @@ -0,0 +1,203 @@ +use core::mem::MaybeUninit; + +use alloc::sync::Arc; +use libk_mm::PageBox; +use libk_thread::runtime; +use yggdrasil_abi::{ + error::Error, + io::{KeyboardKey, KeyboardKeyEvent}, +}; + +use crate::{ + device::UsbDeviceAccess, + info::{UsbDeviceClass, UsbDeviceProtocol}, + UsbDirection, +}; + +pub async fn spawn_driver(device: Arc) -> Result<(), Error> { + // TODO query all configurations? + let device_info = &device.info; + let config_info = device.query_configuration_info(0).await?; + + // Select device class/subclass/protocol based on device/interface + if config_info.interfaces.len() == 1 { + let if_info = &config_info.interfaces[0]; + + let class = if device_info.device_class == UsbDeviceClass::FromInterface { + if_info.interface_class + } else { + device_info.device_class + }; + let subclass = if device_info.device_subclass == 0 { + if_info.interface_subclass + } else { + device_info.device_subclass + }; + let protocol = if device_info.device_protocol == UsbDeviceProtocol::FromInterface { + if_info.interface_protocol + } else { + device_info.device_protocol + }; + + match (class, subclass, protocol) { + (UsbDeviceClass::Hid, 0x01, _) => runtime::spawn(keyboard_driver(device)), + (_, _, _) => Ok(()), + } + } else { + Ok(()) + } +} + +pub async fn keyboard_driver(device: Arc) -> Result<(), Error> { + const MODIFIER_MAP: &[KeyboardKey] = &[ + KeyboardKey::LControl, + KeyboardKey::LShift, + KeyboardKey::LAlt, + KeyboardKey::Unknown, + KeyboardKey::RControl, + KeyboardKey::RShift, + KeyboardKey::RAlt, + KeyboardKey::Unknown, + ]; + + #[derive(Default)] + struct KeyboardState { + state: [u64; 4], + mods: u8, + } + + impl KeyboardState { + pub fn new() -> Self { + Self::default() + } + + pub fn translate_key(k: u8) -> KeyboardKey { + match k { + 4..=29 => KeyboardKey::Char(k - 4 + b'a'), + 30..=38 => KeyboardKey::Char(k - 30 + b'1'), + 39 => KeyboardKey::Char(b'0'), + + 40 => KeyboardKey::Enter, + 41 => KeyboardKey::Escape, + 42 => KeyboardKey::Backspace, + 43 => KeyboardKey::Tab, + 44 => KeyboardKey::Char(b' '), + 45 => KeyboardKey::Char(b'-'), + 46 => KeyboardKey::Char(b'='), + 47 => KeyboardKey::Char(b'['), + 48 => KeyboardKey::Char(b']'), + 49 => KeyboardKey::Char(b'\\'), + 51 => KeyboardKey::Char(b';'), + 52 => KeyboardKey::Char(b'\''), + 53 => KeyboardKey::Char(b'`'), + 54 => KeyboardKey::Char(b','), + 55 => KeyboardKey::Char(b'.'), + 56 => KeyboardKey::Char(b'/'), + + 58..=69 => KeyboardKey::F(k - 58), + + _ => { + log::debug!("Unknown key: {}", k); + KeyboardKey::Unknown + } + } + } + + pub fn retain_modifiers( + &mut self, + m: u8, + events: &mut [MaybeUninit], + ) -> usize { + let mut count = 0; + let released = self.mods & !m; + for i in 0..8 { + if released & (1 << i) != 0 { + events[count].write(KeyboardKeyEvent::Released(MODIFIER_MAP[i])); + count += 1; + } + } + self.mods &= m; + count + } + + pub fn press_modifiers( + &mut self, + m: u8, + events: &mut [MaybeUninit], + ) -> usize { + let mut count = 0; + let pressed = m & !self.mods; + for i in 0..8 { + if pressed & (1 << i) != 0 { + events[count].write(KeyboardKeyEvent::Pressed(MODIFIER_MAP[i])); + count += 1; + } + } + self.mods = m; + count + } + + pub fn retain( + &mut self, + keys: &[u8], + events: &mut [MaybeUninit], + ) -> usize { + let mut count = 0; + for i in 1..256 { + if self.state[i / 64] & (1 << (i % 64)) != 0 { + if !keys.contains(&(i as u8)) { + events[count] + .write(KeyboardKeyEvent::Released(Self::translate_key(i as u8))); + self.state[i / 64] &= !(1 << (i % 64)); + count += 1; + } + } + } + count + } + + pub fn press( + &mut self, + keys: &[u8], + events: &mut [MaybeUninit], + ) -> usize { + let mut count = 0; + for &k in keys { + let index = (k as usize) / 64; + if self.state[index] & (1 << (k % 64)) == 0 { + self.state[index] |= 1 << (k % 64); + events[count].write(KeyboardKeyEvent::Pressed(Self::translate_key(k))); + count += 1; + } + } + count + } + } + + // TODO not sure whether to use boot protocol (easy) or GetReport + let config = device.select_configuration(|_| true).await?.unwrap(); + assert_eq!(config.endpoints.len(), 1); + + let pipe = device.open_interrupt_pipe(1, UsbDirection::In).await?; + + let mut buffer = PageBox::new_slice(0, 8)?; + let mut state = KeyboardState::new(); + let mut events = [MaybeUninit::uninit(); 16]; + + loop { + let mut event_count = 0; + + let data = pipe.listen(&mut buffer).await?; + + event_count += state.retain_modifiers(data[0], &mut events); + event_count += state.press_modifiers(data[0], &mut events[event_count..]); + event_count += state.retain(&data[2..], &mut events[event_count..]); + event_count += state.press(&data[2..], &mut events[event_count..]); + + let events = unsafe { MaybeUninit::slice_assume_init_ref(&events[..event_count]) }; + + for &event in events { + ygg_driver_input::send_event(event); + } + } +} diff --git a/driver/bus/usb/src/communication.rs b/driver/bus/usb/src/communication.rs new file mode 100644 index 00000000..849e7819 --- /dev/null +++ b/driver/bus/usb/src/communication.rs @@ -0,0 +1,92 @@ +use core::{ + future::poll_fn, + sync::atomic::{AtomicU32, Ordering}, + task::{Context, Poll}, +}; + +use alloc::{sync::Arc, vec::Vec}; +use futures_util::task::AtomicWaker; +use libk_mm::address::PhysicalAddress; +use yggdrasil_abi::error::Error; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum UsbDirection { + Out, + In, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct UsbTransferToken(pub u64); + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct UsbTransferResult(pub u32); + +pub struct UsbTransferStatus { + pub result: AtomicU32, + pub notify: AtomicWaker, +} + +pub struct UsbTransfer { + pub id: UsbTransferToken, + pub length: usize, + pub direction: UsbDirection, + pub elements: Vec, + pub status: Arc, +} + +// TODO this is xHCI-specific +impl UsbTransferResult { + pub fn is_success(&self) -> bool { + (self.0 >> 24) & 0xFF == 1 + } + + pub fn sub_length(&self) -> usize { + (self.0 & 0xFFFFFF) as _ + } +} + +impl UsbTransfer { + pub async fn wait(&self) -> Result { + let sub_length = self.status.wait().await?; + Ok(self.length.saturating_sub(sub_length)) + } +} + +impl UsbTransferStatus { + pub fn new() -> Self { + Self { + result: AtomicU32::new(0), + notify: AtomicWaker::new(), + } + } + + pub(crate) async fn wait(&self) -> Result { + poll_fn(|cx| { + self.poll(cx).map(|v| { + if v.is_success() { + Ok(v.sub_length()) + } else { + Err(Error::InvalidOperation) + } + }) + }) + .await + } + + pub fn signal(&self, status: u32) { + self.result.store(status, Ordering::Release); + self.notify.wake(); + } + + pub fn poll(&self, cx: &mut Context<'_>) -> Poll { + self.notify.register(cx.waker()); + let value = self.result.load(Ordering::Acquire); + if value != 0 { + Poll::Ready(UsbTransferResult(value)) + } else { + Poll::Pending + } + } +} diff --git a/driver/bus/usb/src/descriptor.rs b/driver/bus/usb/src/descriptor.rs new file mode 100644 index 00000000..6cc4e276 --- /dev/null +++ b/driver/bus/usb/src/descriptor.rs @@ -0,0 +1,146 @@ +use bytemuck::{Pod, Zeroable}; +use yggdrasil_abi::error::Error; + +use crate::{ + info::{UsbDeviceClass, UsbDeviceProtocol, UsbEndpointType}, + UsbDirection, +}; + +#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct UsbDeviceDescriptor { + pub length: u8, + pub ty: u8, + pub bcd_usb: u16, + pub device_class: u8, + pub device_subclass: u8, + pub device_protocol: u8, + pub max_packet_size_0: u8, + pub id_vendor: u16, + pub id_product: u16, + pub bcd_device: u16, + pub manufacturer_str: u8, + pub product_str: u8, + pub serial_number_str: u8, + pub num_configurations: u8, +} + +#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct UsbConfigurationDescriptor { + pub length: u8, + pub ty: u8, + pub total_length: u16, + pub num_interfaces: u8, + pub config_val: u8, + pub config_str: u8, + pub attributes: u8, + pub max_power: u8, +} + +#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct UsbInterfaceDescriptor { + pub length: u8, + pub ty: u8, + pub interface_number: u8, + pub alternate_setting: u8, + pub num_endpoints: u8, + pub interface_class: u8, + pub interface_subclass: u8, + pub interface_protocol: u8, + pub interface_str: u8, +} + +#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct UsbEndpointDescriptor { + pub length: u8, + pub ty: u8, + pub endpoint_address: u8, + pub attributes: u8, + pub max_packet_size: u16, + pub interval: u8, +} + +#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct UsbDeviceQualifier { + pub length: u8, + pub ty: u8, + pub bcd_usb: u16, + pub device_class: u8, + pub device_subclass: u8, + pub device_protocol: u8, + pub max_packet_size_0: u8, + pub num_configurations: u8, + pub _reserved: u8, +} + +#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct UsbOtherSpeedConfiguration { + pub length: u8, + pub ty: u8, + pub total_length: u16, + pub num_interfaces: u8, + pub config_val: u8, + pub config_str: u8, + pub attributes: u8, + pub max_power: u8, +} + +impl UsbInterfaceDescriptor { + pub fn class(&self) -> UsbDeviceClass { + UsbDeviceClass::try_from(self.interface_class).unwrap_or(UsbDeviceClass::Unknown) + } + + pub fn protocol(&self) -> UsbDeviceProtocol { + UsbDeviceProtocol::try_from(self.interface_protocol).unwrap_or(UsbDeviceProtocol::Unknown) + } +} + +impl UsbEndpointDescriptor { + pub fn direction(&self) -> UsbDirection { + match self.endpoint_address >> 7 { + 1 => UsbDirection::In, + 0 => UsbDirection::Out, + _ => unreachable!(), + } + } + + pub fn number(&self) -> u8 { + assert_ne!(self.endpoint_address & 0xF, 0); + self.endpoint_address & 0xF + } + + pub fn transfer_type(&self) -> UsbEndpointType { + match self.attributes & 0x3 { + 0 => UsbEndpointType::Control, + 1 => UsbEndpointType::Isochronous, + 2 => UsbEndpointType::Bulk, + 3 => UsbEndpointType::Interrupt, + _ => unreachable!(), + } + } +} + +impl UsbDeviceDescriptor { + pub fn class(&self) -> UsbDeviceClass { + UsbDeviceClass::try_from(self.device_class).unwrap_or(UsbDeviceClass::Unknown) + } + + pub fn protocol(&self) -> UsbDeviceProtocol { + UsbDeviceProtocol::try_from(self.device_protocol).unwrap_or(UsbDeviceProtocol::Unknown) + } + + pub fn max_packet_size(&self) -> Result { + match self.max_packet_size_0 { + 8 => Ok(8), + 16 => Ok(16), + 32 => Ok(32), + 64 => Ok(64), + _ => Err(Error::InvalidArgument), + } + } +} diff --git a/driver/bus/usb/src/device.rs b/driver/bus/usb/src/device.rs new file mode 100644 index 00000000..d738d4bc --- /dev/null +++ b/driver/bus/usb/src/device.rs @@ -0,0 +1,191 @@ +use core::{fmt, ops::Deref}; + +use alloc::{boxed::Box, vec::Vec}; +use futures_util::future::BoxFuture; +use libk_mm::PageBox; +use libk_util::sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard}; +use yggdrasil_abi::error::Error; + +use crate::{ + info::{UsbConfigurationInfo, UsbDeviceInfo, UsbEndpointInfo, UsbInterfaceInfo}, + pipe::{ + control::{ConfigurationDescriptorEntry, UsbControlPipeAccess}, + interrupt::UsbInterruptPipeAccess, + }, + UsbDirection, UsbHostController, +}; + +// High-level structures for info provided through descriptors + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct UsbBusAddress { + pub bus: u16, + pub device: u8, +} + +pub struct UsbDeviceAccess { + pub device: Box, + pub info: UsbDeviceInfo, + pub num_configurations: u8, + pub current_configuration: IrqSafeRwLock>, +} + +#[allow(unused)] +pub trait UsbDevice: Send + Sync { + // Endpoint "0" + fn control_pipe(&self) -> Option<&UsbControlPipeAccess>; + + fn open_interrupt_pipe<'a>( + &'a self, + number: u8, + direction: UsbDirection, + ) -> BoxFuture> { + unimplemented!() + } + + fn port_number(&self) -> u8; + fn bus_address(&self) -> UsbBusAddress; + fn controller(&self) -> &'static dyn UsbHostController; + + fn debug(&self) {} +} + +impl UsbDeviceAccess { + /// Expected device state: + /// + /// * Link-layer stuff has been reset and established properly by the HCD + /// * Device is not yet configured + /// * Control pipe for the device has been properly set up + /// * Device has been assigned a bus address + pub async fn setup(raw: Box) -> Result { + let control = raw.control_pipe().ok_or(Error::InvalidOperation)?; + let mut string_buffer = PageBox::new_uninit()?; + + let device_desc = control.query_device_descriptor().await?; + + let manufacturer = control + .query_string(device_desc.manufacturer_str, &mut string_buffer) + .await?; + let product = control + .query_string(device_desc.product_str, &mut string_buffer) + .await?; + + let info = UsbDeviceInfo { + manufacturer, + product, + + id_vendor: device_desc.id_vendor, + id_product: device_desc.id_product, + + device_class: device_desc.class(), + device_subclass: device_desc.device_subclass, + device_protocol: device_desc.protocol(), + + max_packet_size: device_desc.max_packet_size()?, + }; + + Ok(Self { + device: raw, + info, + num_configurations: device_desc.num_configurations, + current_configuration: IrqSafeRwLock::new(None), + }) + } + + pub fn read_current_configuration( + &self, + ) -> IrqSafeRwLockReadGuard> { + self.current_configuration.read() + } + + pub async fn select_configuration bool>( + &self, + predicate: F, + ) -> Result, Error> { + let mut current_config = self.current_configuration.write(); + let control_pipe = self.control_pipe().ok_or(Error::InvalidOperation)?; + + for i in 0..self.num_configurations { + let info = self.query_configuration_info(i).await?; + + if predicate(&info) { + log::debug!("Selected configuration: {:#?}", info); + let config = current_config.insert(info); + + control_pipe + .set_configuration(config.config_value as _) + .await?; + + return Ok(Some(config.clone())); + } + } + + Ok(None) + } + + pub async fn query_configuration_info(&self, index: u8) -> Result { + if index >= self.num_configurations { + return Err(Error::InvalidArgument); + } + let mut string_buffer = PageBox::new_uninit()?; + let control_pipe = self.control_pipe().ok_or(Error::InvalidOperation)?; + let query = control_pipe.query_configuration_descriptor(index).await?; + + let configuration_name = control_pipe + .query_string(query.configuration().config_str, &mut string_buffer) + .await?; + + let mut endpoints = Vec::new(); + let mut interfaces = Vec::new(); + + for desc in query.descriptors() { + match desc { + ConfigurationDescriptorEntry::Endpoint(ep) => { + endpoints.push(UsbEndpointInfo { + number: ep.number(), + direction: ep.direction(), + max_packet_size: ep.max_packet_size as _, + ty: ep.transfer_type(), + }); + } + ConfigurationDescriptorEntry::Interface(iface) => { + let name = control_pipe + .query_string(iface.interface_str, &mut string_buffer) + .await?; + interfaces.push(UsbInterfaceInfo { + name, + number: iface.interface_number, + + interface_class: iface.class(), + interface_subclass: iface.interface_subclass, + interface_protocol: iface.protocol(), + }); + } + _ => (), + } + } + + let info = UsbConfigurationInfo { + name: configuration_name, + config_value: query.configuration().config_val, + interfaces, + endpoints, + }; + + Ok(info) + } +} + +impl Deref for UsbDeviceAccess { + type Target = dyn UsbDevice; + + fn deref(&self) -> &Self::Target { + &*self.device + } +} + +impl fmt::Display for UsbBusAddress { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}:{}", self.bus, self.device) + } +} diff --git a/driver/bus/usb/src/info.rs b/driver/bus/usb/src/info.rs new file mode 100644 index 00000000..8e079bb3 --- /dev/null +++ b/driver/bus/usb/src/info.rs @@ -0,0 +1,84 @@ +use alloc::{string::String, vec::Vec}; +use yggdrasil_abi::primitive_enum; + +use crate::UsbDirection; + +#[derive(Debug, Clone, Copy)] +pub enum UsbEndpointType { + Control, + Isochronous, + Bulk, + Interrupt, +} + +#[derive(Debug, Clone, Copy)] +pub enum UsbSyncType { + NoSync, + Async, + Adaptive, + Sync, +} + +#[derive(Debug)] +pub enum UsbUsageType { + Data, + Feedback, + ImplicitFeedbackData, + Reserved, +} + +primitive_enum! { + pub enum UsbDeviceClass: u8 { + FromInterface = 0x00, + Hid = 0x03, + Unknown = 0xFF, + } +} + +primitive_enum! { + pub enum UsbDeviceProtocol: u8 { + FromInterface = 0x00, + Unknown = 0xFF, + } +} + +#[derive(Debug, Clone)] +pub struct UsbInterfaceInfo { + pub name: String, + pub number: u8, + + pub interface_class: UsbDeviceClass, + pub interface_subclass: u8, + pub interface_protocol: UsbDeviceProtocol, +} + +#[derive(Debug, Clone)] +pub struct UsbEndpointInfo { + pub number: u8, + pub direction: UsbDirection, + pub max_packet_size: usize, + pub ty: UsbEndpointType, +} + +#[derive(Debug, Clone)] +pub struct UsbConfigurationInfo { + pub name: String, + pub config_value: u8, + pub interfaces: Vec, + pub endpoints: Vec, +} + +#[derive(Debug, Clone)] +pub struct UsbDeviceInfo { + pub manufacturer: String, + pub product: String, + + pub id_vendor: u16, + pub id_product: u16, + + pub device_class: UsbDeviceClass, + pub device_subclass: u8, + pub device_protocol: UsbDeviceProtocol, + + pub max_packet_size: usize, +} diff --git a/driver/bus/usb/src/lib.rs b/driver/bus/usb/src/lib.rs new file mode 100644 index 00000000..e51ef978 --- /dev/null +++ b/driver/bus/usb/src/lib.rs @@ -0,0 +1,19 @@ +#![no_std] +#![feature(iter_array_chunks, maybe_uninit_slice)] + +extern crate alloc; + +pub mod bus; +pub mod communication; +pub mod descriptor; +pub mod device; +pub mod info; +pub mod pipe; + +pub mod class_driver; + +pub use communication::{UsbDirection, UsbTransfer, UsbTransferStatus, UsbTransferToken}; + +pub trait UsbEndpoint {} + +pub trait UsbHostController {} diff --git a/driver/bus/usb/src/pipe/control.rs b/driver/bus/usb/src/pipe/control.rs new file mode 100644 index 00000000..2f8a17a5 --- /dev/null +++ b/driver/bus/usb/src/pipe/control.rs @@ -0,0 +1,323 @@ +use core::{ + cmp::Ordering, + mem::{size_of, MaybeUninit}, + ops::Deref, +}; + +use alloc::{boxed::Box, string::String}; +use bytemuck::{Pod, Zeroable}; +use libk_mm::{ + address::{AsPhysicalAddress, PhysicalAddress}, + PageBox, +}; +use yggdrasil_abi::error::Error; + +use crate::{ + descriptor::{ + UsbConfigurationDescriptor, UsbDeviceDescriptor, UsbDeviceQualifier, UsbEndpointDescriptor, + UsbInterfaceDescriptor, UsbOtherSpeedConfiguration, + }, + UsbDirection, UsbTransfer, +}; + +use super::UsbGenericPipe; + +#[derive(Debug)] +pub struct ControlTransferSetup { + pub bm_request_type: u8, + pub b_request: u8, + pub w_value: u16, + pub w_index: u16, + pub w_length: u16, +} + +#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)] +#[repr(C)] +pub struct SetConfiguration; + +pub trait UsbDeviceRequest: Sized + Pod { + const BM_REQUEST_TYPE: u8; + const B_REQUEST: u8; +} + +pub trait UsbDescriptorRequest: UsbDeviceRequest { + const DESCRIPTOR_TYPE: u8; +} + +impl UsbDescriptorRequest for UsbDeviceDescriptor { + const DESCRIPTOR_TYPE: u8 = 1; +} + +impl UsbDescriptorRequest for UsbConfigurationDescriptor { + const DESCRIPTOR_TYPE: u8 = 2; +} + +impl UsbDescriptorRequest for UsbInterfaceDescriptor { + const DESCRIPTOR_TYPE: u8 = 4; +} + +impl UsbDeviceRequest for SetConfiguration { + const BM_REQUEST_TYPE: u8 = 0; + const B_REQUEST: u8 = 0x09; +} + +impl UsbDeviceRequest for U { + const BM_REQUEST_TYPE: u8 = 0b10000000; + const B_REQUEST: u8 = 0x06; +} + +fn decode_usb_string(bytes: &[u8]) -> Result { + if bytes.len() % 2 != 0 { + return Err(Error::InvalidArgument); + } + + char::decode_utf16( + bytes + .into_iter() + .array_chunks::<2>() + .map(|[&a, &b]| u16::from_le_bytes([a, b])), + ) + .collect::>() + .map_err(|_| Error::InvalidArgument) +} + +// Pipe impl + +pub trait UsbControlPipe: UsbGenericPipe + Send + Sync { + fn start_transfer( + &self, + setup: ControlTransferSetup, + data: Option<(PhysicalAddress, usize, UsbDirection)>, + ) -> Result; +} + +pub struct UsbControlPipeAccess(pub Box); + +fn input_buffer( + data: &mut PageBox>, +) -> (PhysicalAddress, usize, UsbDirection) { + ( + unsafe { data.as_physical_address() }, + size_of::(), + UsbDirection::In, + ) +} + +#[derive(Debug)] +pub enum ConfigurationDescriptorEntry<'a> { + Configuration(&'a UsbConfigurationDescriptor), + Interface(&'a UsbInterfaceDescriptor), + Endpoint(&'a UsbEndpointDescriptor), + DeviceQualifier(&'a UsbDeviceQualifier), + OtherSpeed(&'a UsbOtherSpeedConfiguration), + Other, +} + +pub struct ConfigurationDescriptorIter<'a> { + buffer: &'a PageBox<[u8]>, + offset: usize, +} + +pub struct ConfigurationDescriptorQuery { + buffer: PageBox<[u8]>, +} + +impl<'a> Iterator for ConfigurationDescriptorIter<'a> { + type Item = ConfigurationDescriptorEntry<'a>; + + fn next(&mut self) -> Option { + if self.offset + 2 >= self.buffer.len() { + return None; + } + + let desc_len = self.buffer[self.offset] as usize; + let desc_ty = self.buffer[self.offset + 1]; + + if desc_len == 0 { + return None; + } + + let entry = match desc_ty { + 0x02 if desc_len == size_of::() => { + ConfigurationDescriptorEntry::Configuration(bytemuck::from_bytes( + &self.buffer[self.offset..self.offset + desc_len], + )) + } + 0x04 if desc_len == size_of::() => { + ConfigurationDescriptorEntry::Interface(bytemuck::from_bytes( + &self.buffer[self.offset..self.offset + desc_len], + )) + } + 0x05 if desc_len == size_of::() => { + ConfigurationDescriptorEntry::Endpoint(bytemuck::from_bytes( + &self.buffer[self.offset..self.offset + desc_len], + )) + } + 0x07 if desc_len == size_of::() => { + ConfigurationDescriptorEntry::OtherSpeed(bytemuck::from_bytes( + &self.buffer[self.offset..self.offset + desc_len], + )) + } + _ => ConfigurationDescriptorEntry::Other, + }; + + self.offset += desc_len; + + Some(entry) + } +} + +impl ConfigurationDescriptorQuery { + pub fn configuration(&self) -> &UsbConfigurationDescriptor { + bytemuck::from_bytes(&self.buffer[..size_of::()]) + } + + pub fn descriptors(&self) -> ConfigurationDescriptorIter<'_> { + ConfigurationDescriptorIter { + buffer: &self.buffer, + offset: 0, + } + } +} + +impl UsbControlPipeAccess { + pub async fn perform_value_control( + &self, + setup: ControlTransferSetup, + buffer: Option<(PhysicalAddress, usize, UsbDirection)>, + ) -> Result<(), Error> { + let transfer = self.start_transfer(setup, buffer)?; + transfer.status.wait().await?; + self.complete_transfer(transfer); + Ok(()) + } + + async fn fill_configuation_descriptor( + &self, + index: u8, + buffer: &mut PageBox<[MaybeUninit]>, + ) -> Result<(), Error> { + self.perform_value_control( + ControlTransferSetup { + bm_request_type: 0b10000000, + b_request: 0x06, + w_value: 0x200 | (index as u16), + w_index: 0, + w_length: buffer.len().try_into().unwrap(), + }, + Some(( + unsafe { buffer.as_physical_address() }, + buffer.len(), + UsbDirection::In, + )), + ) + .await + } + + pub async fn query_configuration_descriptor( + &self, + index: u8, + ) -> Result { + // First, query the real length of the descriptor + let mut buffer = PageBox::new_uninit_slice(size_of::())?; + self.fill_configuation_descriptor(index, &mut buffer) + .await?; + let buffer = unsafe { PageBox::assume_init_slice(buffer) }; + + let desc: &UsbConfigurationDescriptor = bytemuck::from_bytes(&buffer); + let total_len = desc.total_length as usize; + + // Return if everything's ready at this point + match total_len.cmp(&size_of::()) { + Ordering::Less => todo!(), + Ordering::Equal => return Ok(ConfigurationDescriptorQuery { buffer }), + _ => (), + } + + // Otherwise, query the rest of the data + let mut buffer = PageBox::new_uninit_slice(total_len)?; + self.fill_configuation_descriptor(index, &mut buffer) + .await?; + let buffer = unsafe { PageBox::assume_init_slice(buffer) }; + + let desc: &UsbConfigurationDescriptor = + bytemuck::from_bytes(&buffer[..size_of::()]); + let total_len = desc.total_length as usize; + + if total_len != buffer.len() { + todo!(); + } + + Ok(ConfigurationDescriptorQuery { buffer }) + } + + pub async fn query_device_descriptor(&self) -> Result, Error> { + let mut output = PageBox::new_uninit()?; + self.perform_value_control( + ControlTransferSetup { + bm_request_type: 0b10000000, + b_request: 0x06, + w_value: 0x100, + w_index: 0, + w_length: size_of::() as _, + }, + Some(input_buffer(&mut output)), + ) + .await?; + + Ok(unsafe { output.assume_init() }) + } + + pub async fn query_string( + &self, + index: u8, + buffer: &mut PageBox>, + ) -> Result { + self.perform_value_control( + ControlTransferSetup { + bm_request_type: 0b10000000, + b_request: 0x06, + w_value: 0x300 | (index as u16), + w_index: 0, + w_length: 4096, + }, + Some(input_buffer(buffer)), + ) + .await?; + let data = unsafe { buffer.assume_init_ref() }; + + let len = data[0] as usize; + + decode_usb_string(&data[2..len]) + } + + pub async fn perform_action( + &self, + w_value: u16, + w_index: u16, + ) -> Result<(), Error> { + self.perform_value_control( + ControlTransferSetup { + bm_request_type: D::BM_REQUEST_TYPE, + b_request: D::B_REQUEST, + w_value, + w_index, + w_length: 0, + }, + None, + ) + .await + } + + pub async fn set_configuration(&self, value: u16) -> Result<(), Error> { + self.perform_action::(value, 0).await + } +} + +impl Deref for UsbControlPipeAccess { + type Target = dyn UsbControlPipe; + + fn deref(&self) -> &Self::Target { + &*self.0 + } +} diff --git a/driver/bus/usb/src/pipe/interrupt.rs b/driver/bus/usb/src/pipe/interrupt.rs new file mode 100644 index 00000000..a42d6d36 --- /dev/null +++ b/driver/bus/usb/src/pipe/interrupt.rs @@ -0,0 +1,32 @@ +use core::ops::Deref; + +use alloc::boxed::Box; +use libk_mm::PageBox; +use yggdrasil_abi::error::Error; + +use crate::UsbTransfer; + +use super::UsbGenericPipe; + +pub trait UsbInterruptPipe: UsbGenericPipe + Send + Sync { + fn start_read(&self, buffer: &mut PageBox<[u8]>) -> Result; +} + +pub struct UsbInterruptPipeAccess(pub Box); + +impl UsbInterruptPipeAccess { + // TODO timeout + pub async fn listen<'a>(&self, buffer: &'a mut PageBox<[u8]>) -> Result<&'a [u8], Error> { + let transfer = self.start_read(buffer)?; + let len = transfer.wait().await?; + Ok(&buffer[..len]) + } +} + +impl Deref for UsbInterruptPipeAccess { + type Target = dyn UsbInterruptPipe; + + fn deref(&self) -> &Self::Target { + &*self.0 + } +} diff --git a/driver/bus/usb/src/pipe/mod.rs b/driver/bus/usb/src/pipe/mod.rs new file mode 100644 index 00000000..45fab67b --- /dev/null +++ b/driver/bus/usb/src/pipe/mod.rs @@ -0,0 +1,12 @@ +use super::UsbTransfer; + +pub mod control; +pub mod interrupt; + +pub trait UsbGenericPipe { + fn complete_transfer(&self, transfer: UsbTransfer); +} + +pub enum UsbPipe { + Control(control::UsbControlPipeAccess), +} diff --git a/driver/input/Cargo.toml b/driver/input/Cargo.toml new file mode 100644 index 00000000..abfeffd1 --- /dev/null +++ b/driver/input/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ygg_driver_input" +version = "0.1.0" +edition = "2021" + +[dependencies] +yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" } +libk-util = { path = "../../libk/libk-util" } +libk-thread = { path = "../../libk/libk-thread" } +libk-mm = { path = "../../libk/libk-mm" } +vfs = { path = "../../lib/vfs" } diff --git a/src/device/input.rs b/driver/input/src/lib.rs similarity index 93% rename from src/device/input.rs rename to driver/input/src/lib.rs index a2493b5b..87242944 100644 --- a/src/device/input.rs +++ b/driver/input/src/lib.rs @@ -1,15 +1,16 @@ -// TODO -#![allow(missing_docs)] +#![no_std] + +extern crate alloc; use core::task::{Context, Poll}; -use abi::{ +use libk_thread::block; +use libk_util::ring::LossyRingQueue; +use vfs::{CharDevice, FileReadiness}; +use yggdrasil_abi::{ error::Error, io::{DeviceRequest, KeyboardKeyEvent}, }; -use libk::block; -use libk_util::ring::LossyRingQueue; -use vfs::{CharDevice, FileReadiness}; pub struct KeyboardDevice; diff --git a/driver/usb/xhci/Cargo.toml b/driver/usb/xhci/Cargo.toml new file mode 100644 index 00000000..9c4359f9 --- /dev/null +++ b/driver/usb/xhci/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "ygg_driver_usb_xhci" +version = "0.1.0" +edition = "2021" +authors = ["Mark Poliakov "] + +[dependencies] +yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" } +device-api = { path = "../../../lib/device-api", features = ["derive"] } +ygg_driver_pci = { path = "../../bus/pci" } +ygg_driver_usb = { path = "../../bus/usb" } + +libk-util = { path = "../../../libk/libk-util" } +libk-mm = { path = "../../../libk/libk-mm" } +libk-thread = { path = "../../../libk/libk-thread" } + +xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" } + +log = "0.4.20" +tock-registers = "0.9.0" +bytemuck = { version = "1.14.0", features = ["derive"] } +futures-util = { version = "0.3.28", default-features = false, features = ["alloc", "async-await"] } diff --git a/driver/usb/xhci/src/lib.rs b/driver/usb/xhci/src/lib.rs new file mode 100644 index 00000000..5b778e9f --- /dev/null +++ b/driver/usb/xhci/src/lib.rs @@ -0,0 +1,484 @@ +#![no_std] +#![feature(iter_array_chunks)] + +extern crate alloc; + +use core::{ + future::poll_fn, + sync::atomic::{AtomicBool, Ordering}, + task::{Context, Poll}, + time::Duration, +}; + +use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, vec::Vec}; +use device_api::{ + interrupt::{InterruptAffinity, InterruptHandler}, + Device, +}; +use futures_util::{future::BoxFuture, FutureExt}; +use libk_mm::{ + address::{AsPhysicalAddress, IntoRaw, PhysicalAddress}, + PageBox, +}; +use libk_thread::runtime::{self, FutureTimeout}; +use libk_util::{sync::spin_rwlock::IrqSafeRwLock, waker::QueueWaker, OneTimeInit}; +use pipe::ControlPipe; +use regs::{Mapper, Regs}; +use ring::{CommandExecutor, CommandRing, EventRing}; +use xhci_lib::context::{self, InputHandler}; +use ygg_driver_pci::{ + device::{PciDeviceInfo, PreferredInterruptMode}, + PciCommandRegister, PciConfigurationSpace, +}; +use ygg_driver_usb::{ + bus::UsbBusManager, + device::{UsbBusAddress, UsbDevice, UsbDeviceAccess}, + info::UsbEndpointType, + pipe::{control::UsbControlPipeAccess, interrupt::UsbInterruptPipeAccess}, + UsbDirection, UsbHostController, +}; +use yggdrasil_abi::error::Error; + +use crate::{ + pipe::InterruptPipe, + ring::{Event, EventRingSegmentTable, TransferRing}, +}; + +mod pipe; +mod regs; +mod ring; + +pub struct XhciContext { + pub(crate) input: IrqSafeRwLock>>, + pub(crate) output: PageBox>, +} + +// TODO device context information +pub struct XhciBusDevice { + port_id: u8, + slot_id: u8, + bus_address: UsbBusAddress, + + xhci: &'static Xhci, + + context: Arc>, + control_pipe: UsbControlPipeAccess, +} + +pub struct Xhci { + regs: Regs, + + bus_address: OneTimeInit, + + port_count: usize, + // TODO use to allocate proper contexts + #[allow(unused)] + context_size: usize, + + dcbaa: IrqSafeRwLock>, + endpoints: IrqSafeRwLock>>, + event_ring: EventRing, + command_ring: CommandRing, + + spawned_ports: Vec, + port_reset_notify: QueueWaker, +} + +impl XhciBusDevice { + fn dci(ty: UsbEndpointType, dir: UsbDirection, number: u8) -> usize { + match ty { + UsbEndpointType::Control => (number as usize) * 2 + 1, + _ => { + let off = match dir { + UsbDirection::Out => 0, + UsbDirection::In => 1, + }; + + (number as usize * 2) + off + } + } + } + + async fn setup_endpoint_inner( + &self, + number: u8, + ty: UsbEndpointType, + direction: UsbDirection, + ) -> Result, Error> { + log::debug!("Setup endpoint #{}: {:?} {:?}", number, ty, direction); + + let mut input = self.context.input.write(); + + let ep_type = match (ty, direction) { + (UsbEndpointType::Interrupt, UsbDirection::In) => context::EndpointType::InterruptIn, + _ => todo!(), + }; + // number = 1 + // dci = (number * 2) + IN = 1 * 2 + 1 = 3 + let dci = Self::dci(ty, direction, number); + + let ring = Arc::new(TransferRing::new(self.slot_id, dci as _, 128)?); + + { + let control = input.control_mut(); + + control.set_add_context_flag(0); + control.clear_add_context_flag(1); + control.set_add_context_flag(dci); + } + + { + let slot = input.device_mut().slot_mut(); + + slot.set_context_entries(31); + } + + { + let ep_cx = input.device_mut().endpoint_mut(dci); + + ep_cx.set_tr_dequeue_pointer(ring.dequeue_pointer().into_raw()); + ep_cx.set_dequeue_cycle_state(); + ep_cx.set_endpoint_type(ep_type); + ep_cx.set_error_count(3); + + // TODO get from endpoint info + ep_cx.set_max_packet_size(8); + } + + self.xhci + .command_ring + .configure_endpoint(self.xhci, self.slot_id, &mut input) + .await?; + + self.xhci + .register_endpoint(self.slot_id, dci as _, ring.clone()); + + Ok(ring) + } +} + +impl UsbDevice for XhciBusDevice { + fn control_pipe(&self) -> Option<&UsbControlPipeAccess> { + Some(&self.control_pipe) + } + + fn port_number(&self) -> u8 { + self.port_id + } + + fn bus_address(&self) -> UsbBusAddress { + self.bus_address + } + + fn controller(&self) -> &'static dyn UsbHostController { + self.xhci + } + + fn open_interrupt_pipe<'a>( + &'a self, + number: u8, + direction: UsbDirection, + ) -> BoxFuture> { + async move { + let ring = self + .setup_endpoint_inner(number, UsbEndpointType::Interrupt, direction) + .await?; + + let dci = Self::dci(UsbEndpointType::Interrupt, direction, number) + 1; + let pipe = InterruptPipe::input(self.xhci, self.slot_id, number, dci as _, ring); + + Ok(UsbInterruptPipeAccess(Box::new(pipe))) + } + .boxed() + } + + fn debug(&self) {} +} + +impl UsbHostController for Xhci {} + +impl XhciContext<8> { + pub fn new_32byte() -> Result { + let input = PageBox::new(context::Input::new_32byte())?; + let output = PageBox::new(context::Device::new_32byte())?; + + Ok(Self { + input: IrqSafeRwLock::new(input), + output, + }) + } +} + +impl Xhci { + pub fn new(regs: xhci_lib::Registers) -> Result { + let event_ring = EventRing::new(128)?; + let command_ring = CommandRing::new(128)?; + + let regs = Regs::from(regs); + + let port_count = regs.port_count(); + let slot_count = regs.max_slot_count(); + let context_size = regs.context_size(); + + Ok(Self { + regs, + + bus_address: OneTimeInit::new(), + + port_count, + context_size, + + event_ring, + command_ring, + + dcbaa: IrqSafeRwLock::new(PageBox::new_slice(PhysicalAddress::ZERO, slot_count + 1)?), + endpoints: IrqSafeRwLock::new(BTreeMap::new()), + + spawned_ports: Vec::from_iter((0..port_count).map(|_| AtomicBool::new(false))), + port_reset_notify: QueueWaker::new(), + }) + } + + pub fn register_device_context(&self, slot_id: u8, context: PhysicalAddress) { + self.dcbaa.write()[slot_id as usize] = context; + } + + pub fn register_endpoint(&self, slot_id: u8, endpoint_id: u8, ring: Arc) { + self.endpoints.write().insert((slot_id, endpoint_id), ring); + } + + pub fn notify_transfer( + &self, + slot_id: u8, + endpoint_id: u8, + address: PhysicalAddress, + status: u32, + ) { + if let Some(ep) = self.endpoints.read().get(&(slot_id, endpoint_id)) { + ep.notify(address, status); + } + } + + async fn assign_device( + &'static self, + slot_id: u8, + root_hub_port_number: u8, + ) -> Result, Error> { + let address = 1; + let ring = Arc::new(TransferRing::new(slot_id, 1, 128)?); + + let context = XhciContext::new_32byte()?; + let mut input = context.input.write(); + + // Setup input context + { + let control = input.control_mut(); + + control.set_add_context_flag(0); + control.set_add_context_flag(1); + } + + { + let slot = input.device_mut().slot_mut(); + + slot.set_context_entries(1); + slot.set_interrupter_target(0); + slot.set_usb_device_address(address); + slot.set_root_hub_port_number(root_hub_port_number); + } + + { + let ep0 = input.device_mut().endpoint_mut(1); + + ep0.set_endpoint_type(context::EndpointType::Control); + ep0.set_tr_dequeue_pointer(ring.dequeue_pointer().into_raw()); + ep0.set_dequeue_cycle_state(); + ep0.set_error_count(3); + } + + self.register_device_context(slot_id, unsafe { context.output.as_physical_address() }); + + self.command_ring + .address_device(self, slot_id, &mut input) + .await?; + + self.register_endpoint(slot_id, 1, ring.clone()); + + let pipe = ControlPipe::new(self, slot_id, ring); + + drop(input); + + let bus_address = UsbBusAddress { + bus: *self.bus_address.get(), + device: address, + }; + + let device = XhciBusDevice { + xhci: self, + slot_id, + port_id: root_hub_port_number, + bus_address, + context: Arc::new(context), + control_pipe: UsbControlPipeAccess(Box::new(pipe)), + }; + + Ok(Box::new(device)) + } + + async fn port_task(&'static self, index: usize) -> Result<(), Error> { + log::debug!("Task spawned for port {}", index); + + self.reset_port(index).await?; + + let slot_id = self.command_ring.enable_slot(self).await?; + log::debug!("Enabled slot: {}", slot_id); + + let device = self.assign_device(slot_id, (index + 1) as _).await?; + let device = UsbDeviceAccess::setup(device).await?; + + UsbBusManager::register_device(Arc::new(device)); + + Ok(()) + } + + fn handle_device_attached(&'static self, port: usize) -> Result<(), Error> { + if !self.spawned_ports[port].swap(true, Ordering::Release) { + // Port has not yet been spawned + runtime::spawn(async move { self.port_task(port).await })?; + } + Ok(()) + } + + fn poll_port_reset(&self, cx: &mut Context<'_>, port: usize) -> Poll<()> { + self.port_reset_notify.register(cx.waker()); + if self.regs.ports.read(port).portsc.port_reset_change() { + self.port_reset_notify.remove(cx.waker()); + Poll::Ready(()) + } else { + Poll::Pending + } + } + + async fn reset_port(&self, port: usize) -> Result<(), Error> { + log::debug!("Reset port {}", port); + + self.regs.ports.update(port, |u| { + u.portsc.set_port_reset(); + }); + + // Wait for port reset + let status = runtime::run_with_timeout( + Duration::from_secs(1), + poll_fn(|cx| self.poll_port_reset(cx, port)), + ) + .await; + + match status { + FutureTimeout::Ok(()) => Ok(()), + FutureTimeout::Timeout => Err(Error::TimedOut), + } + } + + fn handle_event(&self) { + while let Some(event) = self.event_ring.try_dequeue() { + match event { + Event::PortChange(_) => { + self.port_reset_notify.wake_one(); + } + Event::CommandCompletion { address, reply } => { + self.command_ring.notify(address, reply); + } + Event::Transfer { + address, + slot_id, + endpoint_id, + status, + } => { + self.notify_transfer(slot_id, endpoint_id, address, status); + } + } + } + + self.regs + .set_interrupter_0_dequeue_pointer(self.event_ring.dequeue_pointer()); + } +} + +impl CommandExecutor for Xhci { + fn ring_doorbell(&self, index: usize, target: u8) { + self.regs.ring_doorbell(index, target); + } +} + +impl Device for Xhci { + unsafe fn init(&'static self) -> Result<(), Error> { + log::info!("Init USB xHCI"); + + self.regs.reset(); + self.regs.set_max_slot_count(); + + let erst = EventRingSegmentTable::for_event_rings(&[&self.event_ring])?; + let dcbaa = self.dcbaa.read(); + + self.regs + .configure(&dcbaa, &self.command_ring, &self.event_ring, &erst); + + let bus = UsbBusManager::register_bus(self); + self.bus_address.init(bus); + + for port in 0..self.port_count { + let p = self.regs.ports.read(port); + if p.portsc.current_connect_status() { + self.handle_device_attached(port).ok(); + } + } + + Ok(()) + } + + unsafe fn init_irq(&'static self) -> Result<(), Error> { + log::info!("Init USB xHCI IRQ"); + Ok(()) + } + + fn display_name(&self) -> &'static str { + "USB xHCI" + } +} + +impl InterruptHandler for Xhci { + fn handle_irq(&self, _vector: Option) -> bool { + if let Some(status) = self.regs.handle_interrupt() { + if status.event_interrupt() { + self.handle_event(); + } + + true + } else { + false + } + } +} + +pub fn probe(info: &PciDeviceInfo) -> Result<&'static dyn Device, Error> { + // TODO Chip Hardware Reset + let bar0 = info + .config_space + .bar(0) + .expect("xHCI doesn't have BAR0 configured") + .as_memory() + .expect("xHCI's BAR0 is not memory-type"); + + let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command()); + cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO); + cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER; + info.config_space.set_command(cmd.bits()); + + let regs = unsafe { xhci_lib::Registers::new(bar0.try_into().unwrap(), Mapper::new()) }; + let xhci = Box::leak(Box::new(Xhci::new(regs)?)); + + info.init_interrupts(PreferredInterruptMode::Msi)?; + info.map_interrupt(InterruptAffinity::Any, xhci)?; + + Ok(xhci) +} diff --git a/driver/usb/xhci/src/pipe.rs b/driver/usb/xhci/src/pipe.rs new file mode 100644 index 00000000..a0102bb7 --- /dev/null +++ b/driver/usb/xhci/src/pipe.rs @@ -0,0 +1,88 @@ +use alloc::sync::Arc; +use libk_mm::{address::PhysicalAddress, PageBox}; +use ygg_driver_usb::{ + pipe::{ + control::{ControlTransferSetup, UsbControlPipe}, + interrupt::UsbInterruptPipe, + UsbGenericPipe, + }, + UsbDirection, UsbTransfer, +}; +use yggdrasil_abi::error::Error; + +use crate::{ring::TransferRing, Xhci}; + +pub struct ControlPipe { + xhci: &'static Xhci, + ring: Arc, +} + +#[allow(unused)] +pub struct InterruptPipe { + xhci: &'static Xhci, + + slot_id: u8, + endpoint_id: u8, + dci: u8, + + input: Option>, + output: Option>, +} + +impl UsbGenericPipe for ControlPipe { + fn complete_transfer(&self, transfer: UsbTransfer) { + self.ring.complete_transfer(transfer) + } +} + +impl UsbControlPipe for ControlPipe { + fn start_transfer( + &self, + setup: ControlTransferSetup, + data: Option<(PhysicalAddress, usize, UsbDirection)>, + ) -> Result { + self.ring.start_control_transfer(self.xhci, setup, data) + } +} + +impl ControlPipe { + pub fn new(xhci: &'static Xhci, _slot_id: u8, ring: Arc) -> Self { + Self { xhci, ring } + } +} + +impl UsbGenericPipe for InterruptPipe { + fn complete_transfer(&self, transfer: UsbTransfer) { + match transfer.direction { + UsbDirection::Out => todo!(), + UsbDirection::In => todo!(), + } + } +} + +impl UsbInterruptPipe for InterruptPipe { + fn start_read(&self, buffer: &mut PageBox<[u8]>) -> Result { + let input = self.input.as_ref().unwrap(); + + input.start_interrupt_in_transfer(self.xhci, buffer) + } +} + +impl InterruptPipe { + pub fn input( + xhci: &'static Xhci, + slot_id: u8, + endpoint_id: u8, + dci: u8, + ring: Arc, + ) -> Self { + Self { + xhci, + slot_id, + endpoint_id, + dci, + input: Some(ring), + output: None, + } + } +} diff --git a/driver/usb/xhci/src/regs.rs b/driver/usb/xhci/src/regs.rs new file mode 100644 index 00000000..55bf11ba --- /dev/null +++ b/driver/usb/xhci/src/regs.rs @@ -0,0 +1,240 @@ +use core::{cell::UnsafeCell, num::NonZeroUsize}; + +use alloc::{sync::Arc, vec::Vec}; +use libk_mm::{ + address::{AsPhysicalAddress, IntoRaw, PhysicalAddress}, + device::RawDeviceMemoryMapping, + PageBox, +}; +use libk_util::sync::spin_rwlock::IrqSafeRwLock; +use xhci_lib::{ + accessor::{array, marker}, + registers::{ + operational::UsbStatusRegister, Capability, Doorbell, InterrupterRegisterSet, Operational, + PortRegisterSet, + }, +}; + +use crate::ring::{CommandRing, EventRing, EventRingSegmentTable, GenericRing}; + +#[derive(Clone)] +pub struct Mapper { + mappings: Vec>, +} + +pub struct LockedArray { + array: UnsafeCell>, + locks: Vec>, +} + +unsafe impl Sync for LockedArray {} +unsafe impl Send for LockedArray {} + +pub struct Regs { + operational: IrqSafeRwLock>, + interrupters: IrqSafeRwLock>, + capability: Capability, + doorbells: LockedArray, + pub ports: LockedArray, +} + +impl LockedArray { + #[inline] + #[allow(clippy::mut_from_ref)] + unsafe fn get_mut(&self) -> &mut array::Generic { + &mut *self.array.get() + } + + pub fn update(&self, index: usize, f: U) { + let _guard = self.locks[index].write(); + unsafe { self.get_mut() }.update_volatile_at(index, f); + } + + pub fn read(&self, index: usize) -> T { + let _guard = self.locks[index].read(); + unsafe { self.get_mut() }.read_volatile_at(index) + } +} + +impl From> for LockedArray { + fn from(value: array::Generic) -> Self { + let locks = Vec::from_iter((0..value.len()).map(|_| IrqSafeRwLock::new(()))); + + Self { + array: UnsafeCell::new(value), + locks, + } + } +} + +impl From> for Regs { + fn from(value: xhci_lib::Registers) -> Self { + Self { + operational: IrqSafeRwLock::new(value.operational), + capability: value.capability, + interrupters: IrqSafeRwLock::new(value.interrupter_register_set), + doorbells: LockedArray::from(value.doorbell), + ports: LockedArray::from(value.port_register_set), + } + } +} + +impl Regs { + pub fn reset(&self) { + let mut o = self.operational.write(); + + // TODO Get ownership from firmware + + // Stop the controller + o.usbcmd.update_volatile(|u| { + u.clear_run_stop(); + }); + + while !o.usbsts.read_volatile().hc_halted() { + core::hint::spin_loop(); + } + + // Reset the controller + o.usbcmd.update_volatile(|u| { + u.set_host_controller_reset(); + }); + while o.usbcmd.read_volatile().host_controller_reset() + || o.usbsts.read_volatile().controller_not_ready() + { + core::hint::spin_loop(); + } + } + + pub fn max_slot_count(&self) -> usize { + self.capability + .hcsparams1 + .read_volatile() + .number_of_device_slots() as _ + } + + pub fn set_max_slot_count(&self) -> usize { + let device_slot_count = self.max_slot_count(); + let mut o = self.operational.write(); + // Set max slots enabled + o.config.update_volatile(|u| { + u.set_max_device_slots_enabled(device_slot_count as _); + }); + + device_slot_count as _ + } + + pub fn context_size(&self) -> usize { + match self.capability.hccparams1.read_volatile().context_size() { + true => 64, + false => 32, + } + } + + pub fn port_count(&self) -> usize { + self.capability.hcsparams1.read_volatile().number_of_ports() as _ + } + + pub fn configure( + &self, + dcbaa: &PageBox<[PhysicalAddress]>, + cmd_ring: &CommandRing, + evt_ring: &EventRing, + erst: &EventRingSegmentTable, + ) { + let mut o = self.operational.write(); + let mut i = self.interrupters.write(); + + o.dcbaap.update_volatile(|u| unsafe { + u.set(dcbaa.as_physical_address().into_raw()); + }); + o.crcr.update_volatile(|u| { + u.set_command_ring_pointer(cmd_ring.base().into_raw()); + u.set_ring_cycle_state(); + }); + + let mut intr0 = i.interrupter_mut(0); + intr0.erstsz.update_volatile(|u| { + u.set(erst.capacity().try_into().unwrap()); + }); + intr0.erdp.update_volatile(|u| { + log::debug!("::: Dequeue Pointer: {:#x}", evt_ring.dequeue_pointer()); + u.set_event_ring_dequeue_pointer(evt_ring.dequeue_pointer().into_raw()); + }); + intr0.erstba.update_volatile(|u| { + u.set(erst.physical_address().into_raw()); + }); + // intr0.imod.update_volatile(|u| { + // u.set_interrupt_moderation_interval(0) + // .set_interrupt_moderation_counter(0); + // }); + intr0.iman.update_volatile(|u| { + u.set_interrupt_enable(); + }); + + o.usbcmd.update_volatile(|u| { + u.set_interrupter_enable().set_run_stop(); + }); + } + + pub fn handle_interrupt(&self) -> Option { + let mut o = self.operational.write(); + let mut i = self.interrupters.write(); + + let status = o.usbsts.read_volatile(); + + if !status.event_interrupt() { + return None; + } + + o.usbsts.write_volatile(status); + + if status.host_system_error() { + return Some(status); + } + + // Acknowledge interrupts + let mut intr0 = i.interrupter_mut(0); + intr0.iman.update_volatile(|u| { + u.set_0_interrupt_pending(); + }); + + Some(status) + } + + pub fn set_interrupter_0_dequeue_pointer(&self, pointer: PhysicalAddress) { + let mut i = self.interrupters.write(); + + i.interrupter_mut(0).erdp.update_volatile(|u| { + u.set_event_ring_dequeue_pointer(pointer.into_raw()); + u.clear_event_handler_busy(); + }); + } + + pub fn ring_doorbell(&self, index: usize, target: u8) { + self.doorbells.update(index, |u| { + u.set_doorbell_target(target); + }); + } +} + +impl Mapper { + pub fn new() -> Self { + Self { + mappings: Vec::new(), + } + } +} + +impl xhci_lib::accessor::Mapper for Mapper { + unsafe fn map(&mut self, phys_start: usize, bytes: usize) -> NonZeroUsize { + let mapping = RawDeviceMemoryMapping::map(phys_start as u64, bytes, Default::default()) + .expect("Could not map an USB xHCI region"); + let address = mapping.address; + self.mappings.push(Arc::new(mapping)); + NonZeroUsize::new_unchecked(address) + } + + fn unmap(&mut self, _virt_start: usize, _bytes: usize) { + // TODO + } +} diff --git a/driver/usb/xhci/src/ring.rs b/driver/usb/xhci/src/ring.rs new file mode 100644 index 00000000..0c781cf9 --- /dev/null +++ b/driver/usb/xhci/src/ring.rs @@ -0,0 +1,656 @@ +use core::{ + future::poll_fn, + mem::{size_of, MaybeUninit}, + sync::atomic::{AtomicU64, Ordering}, + task::Poll, +}; + +use alloc::{collections::BTreeMap, sync::Arc, vec::Vec}; +use libk_mm::{ + address::{AsPhysicalAddress, FromRaw, IntoRaw, PhysicalAddress}, + PageBox, +}; +use libk_util::{ + sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock}, + waker::QueueWaker, +}; +use tock_registers::{ + interfaces::{ReadWriteable, Readable, Writeable}, + register_bitfields, + registers::InMemoryRegister, +}; +use xhci_lib::context::Input; +use ygg_driver_usb::{ + pipe::control::ControlTransferSetup, UsbDirection, UsbTransfer, UsbTransferStatus, + UsbTransferToken, +}; +use yggdrasil_abi::error::Error; + +#[derive(Debug, Clone, Copy)] +pub struct CommandReply { + pub status: u32, + pub slot_id: u8, +} + +impl CommandReply { + pub fn completion_code(&self) -> u8 { + (self.status >> 24) as u8 + } +} + +pub enum Event { + PortChange(usize), + CommandCompletion { + address: PhysicalAddress, + reply: CommandReply, + }, + Transfer { + address: PhysicalAddress, + slot_id: u8, + endpoint_id: u8, + status: u32, + }, +} + +pub trait CommandExecutor { + fn ring_doorbell(&self, index: usize, target: u8); +} + +register_bitfields![ + u32, + pub TrbFlags [ + CYCLE OFFSET(0) NUMBITS(1) [], + LINKSEG OFFSET(1) NUMBITS(1) [], + INTERRUPT_ON_COMPLETION OFFSET(5) NUMBITS(1) [], + IMMEDIATE_DATA OFFSET(6) NUMBITS(1) [], + TYPE OFFSET(10) NUMBITS(6) [ + // Transfer ring types + NORMAL = 1, + SETUP = 2, + DATA = 3, + STATUS = 4, + ISOCH = 5, + LINK = 6, + EVENT = 7, + NOOP = 8, + // Command ring types + COMMAND_ENABLE_SLOT = 9, + COMMAND_DISABLE_SLOT = 10, + COMMAND_ADDRESS_DEVICE = 11, + COMMAND_CONFIGURE_ENDPOINT = 12, + // Event ring types + EVENT_XFER = 32, + EVENT_CMD_COMPLETE = 33, + EVENT_PORT_CHANGE = 34, + EVENT_BW_REQUEST = 35, + EVENT_DOORBELL = 36, + EVENT_HOST_CTRL = 37, + EVENT_DEVICE_NOTIFY = 38, + EVENT_MFINDEX_WRAP = 39 + ], + TRANSFER_TYPE OFFSET(16) NUMBITS(2) [ + OUT = 2, + IN = 3, + ], + TRANSFER_DIRECTION OFFSET(16) NUMBITS(1) [ + OUT = 0, + IN = 1, + ], + ENDPOINT_ID OFFSET(16) NUMBITS(4) [], + SLOT_TYPE OFFSET(16) NUMBITS(4) [], + SLOT_ID OFFSET(24) NUMBITS(8) [], + ], +]; + +#[repr(C, align(16))] +pub struct Trb { + pub address: PhysicalAddress, + pub status: u32, + pub flags: InMemoryRegister, +} + +#[repr(C, align(16))] +pub struct EventRingSegment { + address: PhysicalAddress, + // Number of TRBs supported by the ring segment. Valid values are 16 to 4096 + size: u16, + _0: u16, + _1: u32, +} + +pub struct EventRingSegmentTable { + entries: PageBox<[EventRingSegment]>, +} + +impl EventRingSegmentTable { + pub fn for_event_rings(rings: &[&EventRing]) -> Result { + let entries = PageBox::from_iter_exact(rings.iter().map(|ring| EventRingSegment { + address: ring.base(), + size: ring.capacity().try_into().unwrap(), + _0: 0, + _1: 0, + }))?; + + for entry in entries.iter() { + log::debug!("ERST... = {:#x}", entry.address); + } + + Ok(Self { entries }) + } + + pub fn physical_address(&self) -> PhysicalAddress { + unsafe { self.entries.as_physical_address() } + } + + pub fn capacity(&self) -> usize { + self.entries.len() + } +} + +pub trait GenericRing { + fn capacity(&self) -> usize; + fn base(&self) -> PhysicalAddress; +} + +struct EventRingInner { + trbs: PageBox<[MaybeUninit]>, + dequeue_index: usize, + cycle_bit: bool, +} + +struct CommandRingInner { + trbs: PageBox<[MaybeUninit]>, + enqueue_index: usize, + #[allow(unused)] + dequeue_index: usize, + cycle_bit: bool, +} + +pub struct EventRing { + inner: IrqSafeSpinlock, + capacity: usize, +} + +struct TransferRingInner { + trbs: PageBox<[MaybeUninit]>, + enqueue_index: usize, + dequeue_index: usize, + cycle_bit: bool, +} + +pub struct CommandRing { + inner: IrqSafeSpinlock, + // TODO maybe use Vec of "slots"? + completions: IrqSafeRwLock>, + completion_notify: QueueWaker, + capacity: usize, +} + +impl GenericRing for EventRing { + fn base(&self) -> PhysicalAddress { + unsafe { self.inner.lock().trbs.as_physical_address() } + } + + fn capacity(&self) -> usize { + self.capacity + } +} + +impl EventRingInner { + fn try_dequeue(&mut self) -> Option { + let trb = unsafe { self.trbs[self.dequeue_index].assume_init_ref() }; + + // TRB cannot be consumed -- its cycle bit not toggled + let trb_cycle = trb.flags.matches_all(TrbFlags::CYCLE::SET); + if trb_cycle != self.cycle_bit { + return None; + } + + self.dequeue_index += 1; + + if self.dequeue_index == self.trbs.len() { + self.dequeue_index = 0; + self.cycle_bit = !self.cycle_bit; + } + + match trb.flags.read_as_enum(TrbFlags::TYPE) { + Some(TrbFlags::TYPE::Value::EVENT_PORT_CHANGE) => Some(Event::PortChange( + IntoRaw::::into_raw(trb.address) & 0xFFusize, + )), + Some(TrbFlags::TYPE::Value::EVENT_CMD_COMPLETE) => Some(Event::CommandCompletion { + address: trb.address, + reply: CommandReply { + status: trb.status, + slot_id: trb.flags.read(TrbFlags::SLOT_ID) as _, + }, + }), + Some(TrbFlags::TYPE::Value::EVENT_XFER) => Some(Event::Transfer { + address: trb.address, + slot_id: trb.flags.read(TrbFlags::SLOT_ID) as _, + endpoint_id: trb.flags.read(TrbFlags::ENDPOINT_ID) as _, + status: trb.status, + }), + e => { + log::debug!("Unknown TRB ty: {:?}", e); + None + } + } + } +} + +impl EventRing { + pub fn new(capacity: usize) -> Result { + let trbs = PageBox::new_zeroed_slice(capacity)?; + + Ok(Self { + inner: IrqSafeSpinlock::new(EventRingInner { + trbs, + dequeue_index: 0, + cycle_bit: true, + }), + capacity, + }) + } + + pub fn try_dequeue(&self) -> Option { + self.inner.lock().try_dequeue() + } + + pub fn dequeue_pointer(&self) -> PhysicalAddress { + let i = self.inner.lock(); + unsafe { i.trbs.as_physical_address() }.add(i.dequeue_index * size_of::()) + } +} + +impl GenericRing for CommandRing { + fn base(&self) -> PhysicalAddress { + unsafe { self.inner.lock().trbs.as_physical_address() } + } + + fn capacity(&self) -> usize { + self.capacity + } +} + +impl CommandRingInner { + fn enqueue(&mut self, trb: Trb) -> PhysicalAddress { + trb.flags.modify(TrbFlags::CYCLE.val(self.cycle_bit as _)); + self.trbs[self.enqueue_index].write(trb); + + let address = + unsafe { self.trbs.as_physical_address() }.add(self.enqueue_index * size_of::()); + + // Move to the next TRB slot + self.enqueue_index += 1; + if self.enqueue_index >= self.trbs.len() { + todo!(); + } + + address + } +} + +impl CommandRing { + pub fn new(capacity: usize) -> Result { + let mut trbs = PageBox::new_zeroed_slice(capacity)?; + + let base = unsafe { trbs.as_physical_address() }; + let last: &mut Trb = unsafe { trbs.last_mut().unwrap().assume_init_mut() }; + + last.address = base; + last.flags + .write(TrbFlags::TYPE::LINK + TrbFlags::LINKSEG::SET + TrbFlags::CYCLE::SET); + + Ok(Self { + inner: IrqSafeSpinlock::new(CommandRingInner { + trbs, + enqueue_index: 0, + dequeue_index: 0, + cycle_bit: true, + }), + completions: IrqSafeRwLock::new(BTreeMap::new()), + completion_notify: QueueWaker::new(), + capacity, + }) + } + + pub fn enqueue(&self, trb: Trb) -> PhysicalAddress { + let mut inner = self.inner.lock(); + let address = inner.enqueue(trb); + log::info!("CommandRing::enqueue({:#x})", address); + address + } + + pub async fn address_device( + &self, + executor: &E, + slot_id: u8, + input: &mut PageBox>, + ) -> Result<(), Error> { + let reply = self + .submit_and_wait( + executor, + Trb { + address: unsafe { input.as_physical_address() }, + status: 0, + flags: InMemoryRegister::new( + (TrbFlags::SLOT_ID.val(slot_id as _) + + TrbFlags::TYPE::COMMAND_ADDRESS_DEVICE) + .into(), + ), + }, + ) + .await; + + if reply.completion_code() == 1 { + Ok(()) + } else { + Err(Error::InvalidOperation) + } + } + + pub async fn configure_endpoint( + &self, + executor: &E, + slot_id: u8, + input: &mut PageBox>, + ) -> Result<(), Error> { + let reply = self + .submit_and_wait( + executor, + Trb { + address: unsafe { input.as_physical_address() }, + status: 0, + flags: InMemoryRegister::new( + (TrbFlags::SLOT_ID.val(slot_id as _) + + TrbFlags::TYPE::COMMAND_CONFIGURE_ENDPOINT) + .into(), + ), + }, + ) + .await; + + if reply.completion_code() == 1 { + Ok(()) + } else { + Err(Error::InvalidOperation) + } + } + + pub async fn enable_slot(&self, executor: &E) -> Result { + let reply = self + .submit_and_wait( + executor, + Trb { + address: PhysicalAddress::ZERO, + status: 0, + flags: InMemoryRegister::new( + (TrbFlags::SLOT_TYPE.val(0) + TrbFlags::TYPE::COMMAND_ENABLE_SLOT).into(), + ), + }, + ) + .await; + + if reply.completion_code() == 1 { + Ok(reply.slot_id) + } else { + Err(Error::InvalidOperation) + } + } + + pub async fn submit_and_wait( + &self, + executor: &E, + trb: Trb, + ) -> CommandReply { + let token = self.enqueue(trb); + executor.ring_doorbell(0, 0); + poll_fn(|cx| { + self.completion_notify.register(cx.waker()); + if let Some(status) = self.get_completion(token) { + self.completion_notify.remove(cx.waker()); + Poll::Ready(status) + } else { + Poll::Pending + } + }) + .await + } + + pub fn get_completion(&self, address: PhysicalAddress) -> Option { + self.completions.write().remove(&address) + } + + pub fn notify(&self, address: PhysicalAddress, reply: CommandReply) { + log::info!("CommandRing::notify({:#x}, {:#x?})", address, reply); + self.completions.write().insert(address, reply); + self.completion_notify.wake_all(); + } +} + +impl GenericRing for TransferRing { + fn base(&self) -> PhysicalAddress { + unsafe { self.inner.lock().trbs.as_physical_address() } + } + + fn capacity(&self) -> usize { + self.capacity + } +} + +impl TransferRingInner { + fn enqueue(&mut self, trb: Trb) -> PhysicalAddress { + trb.flags.modify(TrbFlags::CYCLE.val(self.cycle_bit as _)); + self.trbs[self.enqueue_index].write(trb); + + let address = + unsafe { self.trbs.as_physical_address() }.add(self.enqueue_index * size_of::()); + + // Move to the next TRB slot + self.enqueue_index += 1; + if self.enqueue_index >= self.trbs.len() { + todo!(); + } + + address + } +} + +pub struct TransferRing { + inner: IrqSafeSpinlock, + capacity: usize, + + // TODO this is inefficient and ugly + pending_trbs: IrqSafeRwLock>, + completions: IrqSafeRwLock>>, + + slot_id: u8, + ep_id: u8, + + transfer_id: AtomicU64, +} + +impl TransferRing { + pub fn new(slot_id: u8, ep_id: u8, capacity: usize) -> Result { + let mut trbs = PageBox::new_zeroed_slice(capacity)?; + + let base = unsafe { trbs.as_physical_address() }; + let last: &mut Trb = unsafe { trbs.last_mut().unwrap().assume_init_mut() }; + + last.address = base; + last.flags + .write(TrbFlags::TYPE::LINK + TrbFlags::LINKSEG::SET + TrbFlags::CYCLE::SET); + + Ok(Self { + inner: IrqSafeSpinlock::new(TransferRingInner { + trbs, + enqueue_index: 0, + dequeue_index: 0, + cycle_bit: true, + }), + completions: IrqSafeRwLock::new(BTreeMap::new()), + pending_trbs: IrqSafeRwLock::new(BTreeMap::new()), + slot_id, + ep_id, + capacity, + + transfer_id: AtomicU64::new(0), + }) + } + + pub fn enqueue(&self, trb: Trb) -> PhysicalAddress { + let mut inner = self.inner.lock(); + let address = inner.enqueue(trb); + address + } + + pub fn new_transfer(&self) -> UsbTransferToken { + let id = self.transfer_id.fetch_add(1, Ordering::AcqRel); + UsbTransferToken(id) + } + + pub fn complete_transfer(&self, transfer: UsbTransfer) { + let mut pending = self.pending_trbs.write(); + for trb in transfer.elements { + pending.remove(&trb); + } + self.completions.write().remove(&transfer.id); + } + + pub fn enqueue_transfer>( + &self, + trbs: I, + length: usize, + ) -> UsbTransfer { + let mut pending = self.pending_trbs.write(); + let id = self.new_transfer(); + let mut addresses = Vec::new(); + for trb in trbs { + let address = self.enqueue(trb); + addresses.push(address); + pending.insert(address, id); + } + let status = Arc::new(UsbTransferStatus::new()); + let transfer = UsbTransfer { + id, + length, + direction: UsbDirection::In, + elements: addresses, + status: status.clone(), + }; + self.completions.write().insert(id, status); + transfer + } + + fn control_setup_trb(ctl: ControlTransferSetup) -> Trb { + let word0 = (ctl.bm_request_type as u32) + | ((ctl.b_request as u32) << 8) + | ((ctl.w_value as u32) << 16); + let word1 = (ctl.w_index as u32) | ((ctl.w_length as u32) << 16); + + Trb { + address: PhysicalAddress::from_raw((word0 as u64) | ((word1 as u64) << 32)), + status: 8, + flags: InMemoryRegister::new( + (TrbFlags::TYPE::SETUP + + TrbFlags::IMMEDIATE_DATA::SET + + TrbFlags::TRANSFER_TYPE::IN) + .into(), + ), + } + } + + fn data_trb(address: PhysicalAddress, len: usize, direction: UsbDirection) -> Trb { + let dir = match direction { + UsbDirection::Out => TrbFlags::TRANSFER_DIRECTION::OUT, + UsbDirection::In => TrbFlags::TRANSFER_DIRECTION::IN, + }; + Trb { + address, + status: len.try_into().unwrap(), + flags: InMemoryRegister::new((TrbFlags::TYPE::DATA + dir).into()), + } + } + + fn control_status_trb() -> Trb { + Trb { + address: PhysicalAddress::ZERO, + status: 0, + flags: InMemoryRegister::new( + (TrbFlags::TYPE::STATUS + + TrbFlags::TRANSFER_DIRECTION::IN + + TrbFlags::INTERRUPT_ON_COMPLETION::SET) + .into(), + ), + } + } + + pub fn start_interrupt_in_transfer( + &self, + executor: &E, + buffer: &mut PageBox<[u8]>, + ) -> Result { + let data_trb = Trb { + address: unsafe { buffer.as_physical_address() }, + status: buffer.len() as _, + flags: InMemoryRegister::new( + (TrbFlags::TRANSFER_DIRECTION::IN + + TrbFlags::INTERRUPT_ON_COMPLETION::SET + + TrbFlags::TYPE::NORMAL) + .into(), + ), + }; + + let transfer = self.enqueue_transfer(core::iter::once(data_trb), buffer.len()); + + executor.ring_doorbell(self.slot_id as _, self.ep_id); + + Ok(transfer) + } + + pub fn start_control_transfer( + &self, + executor: &E, + setup: ControlTransferSetup, + buffer: Option<(PhysicalAddress, usize, UsbDirection)>, + ) -> Result { + let setup_trb = Self::control_setup_trb(setup); + let data_trb = buffer.map(|(address, len, dir)| Self::data_trb(address, len, dir)); + let status_trb = Self::control_status_trb(); + + let transfer = self.enqueue_transfer( + core::iter::once(setup_trb) + .chain(data_trb) + .chain(core::iter::once(status_trb)), + 0, + ); + + executor.ring_doorbell(self.slot_id as _, self.ep_id); + + Ok(transfer) + } + + pub fn dequeue_pointer(&self) -> PhysicalAddress { + let inner = self.inner.lock(); + unsafe { inner.trbs.as_physical_address() }.add(inner.dequeue_index * size_of::()) + } + + pub fn notify(&self, address: PhysicalAddress, value: u32) { + if value == 0 { + return; + } + + let completions = self.completions.read(); + if let Some(&token) = self.pending_trbs.read().get(&address) { + let Some(status) = completions.get(&token) else { + log::warn!( + "Notification received for non-existent transfer: {:?}", + token + ); + return; + }; + + status.signal(value); + } + } +} diff --git a/lib/vfs/src/lib.rs b/lib/vfs/src/lib.rs index 7a76bb9f..43789c13 100644 --- a/lib/vfs/src/lib.rs +++ b/lib/vfs/src/lib.rs @@ -3,7 +3,14 @@ #![cfg_attr(not(test), no_std)] #![allow(clippy::new_ret_no_self, clippy::new_without_default)] #![deny(missing_docs)] -#![feature(if_let_guard, maybe_uninit_slice, trait_alias, let_chains, new_uninit)] +#![feature( + if_let_guard, + maybe_uninit_slice, + trait_alias, + let_chains, + new_uninit, + trait_upcasting +)] #[cfg(test)] extern crate hosted_tests; diff --git a/libk/libk-mm/src/lib.rs b/libk/libk-mm/src/lib.rs index 106c961f..e40e32ea 100644 --- a/libk/libk-mm/src/lib.rs +++ b/libk/libk-mm/src/lib.rs @@ -4,6 +4,7 @@ slice_ptr_get, step_trait, const_trait_impl, + maybe_uninit_as_bytes, effects )] #![no_std] @@ -66,11 +67,17 @@ pub struct PageBox { impl PageBox { #[inline] - fn alloc_slice(count: usize) -> Result<(PhysicalAddress, usize), Error> { + fn alloc_slice(count: usize, zeroed: bool) -> Result<(PhysicalAddress, usize), Error> { // TODO hardcoded page sizes let layout = Layout::array::(count).unwrap(); let page_count = (layout.size() + L3_PAGE_SIZE - 1) / L3_PAGE_SIZE; - Ok((phys::alloc_pages_contiguous(page_count)?, page_count)) + let base = phys::alloc_pages_contiguous(page_count)?; + if zeroed { + let ptr = base.virtualize() as *mut u8; + let slice = unsafe { core::slice::from_raw_parts_mut(ptr, page_count * L3_PAGE_SIZE) }; + slice.fill(0); + } + Ok((base, page_count)) } #[inline] @@ -96,7 +103,7 @@ impl PageBox { where T: Copy, { - let (base, page_count) = Self::alloc_slice(count)?; + let (base, page_count) = Self::alloc_slice(count, false)?; let base_virt_ptr = base.virtualize() as *mut T; let value = core::ptr::slice_from_raw_parts_mut(base_virt_ptr, count); @@ -130,7 +137,16 @@ impl PageBox { } pub fn new_uninit_slice(count: usize) -> Result]>, Error> { - let (base, page_count) = PageBox::>::alloc_slice(count)?; + let (base, page_count) = PageBox::>::alloc_slice(count, false)?; + let base_virt_ptr = base.virtualize() as *mut MaybeUninit; + let value = core::ptr::slice_from_raw_parts_mut(base_virt_ptr, count); + let result = PageBox { value, page_count }; + result.trace_created(); + Ok(result) + } + + pub fn new_zeroed_slice(count: usize) -> Result]>, Error> { + let (base, page_count) = PageBox::>::alloc_slice(count, true)?; let base_virt_ptr = base.virtualize() as *mut MaybeUninit; let value = core::ptr::slice_from_raw_parts_mut(base_virt_ptr, count); let result = PageBox { value, page_count }; @@ -166,6 +182,21 @@ impl PageBox { } } +impl PageBox<[T]> { + pub fn from_iter_exact>(it: I) -> Result + where + I::IntoIter: ExactSizeIterator, + { + let it = it.into_iter(); + let mut slice = PageBox::new_uninit_slice(it.len())?; + for (i, item) in it.enumerate() { + slice[i].write(item); + } + let slice = unsafe { slice.assume_init_slice() }; + Ok(slice) + } +} + impl PageBox> { /// Consumes the [PageBox], returning a new one with [MaybeUninit] removed. /// @@ -184,6 +215,15 @@ impl PageBox> { PageBox { value, page_count } } + + pub unsafe fn into_byte_slice(self) -> PageBox<[u8]> { + let page_count = self.page_count; + let value = MaybeUninit::slice_assume_init_mut(MaybeUninit::as_bytes_mut(&mut *self.value)); + + core::mem::forget(self); + + PageBox { value, page_count } + } } impl PageBox<[MaybeUninit]> { @@ -221,6 +261,18 @@ impl PageBox<[MaybeUninit]> { pub unsafe fn assume_init_slice_mut(&mut self) -> &mut [T] { MaybeUninit::slice_assume_init_mut(self.deref_mut()) } + + /// Fills a slice of MaybeUninit with zeroes. + /// + /// # Safety + /// + /// Unsafe: will not drop possibly previously written data. Only meant for [Copy] and other + /// trivial types. + pub unsafe fn zero(p: &mut Self) { + let ptr = p.as_mut_ptr() as *mut u8; + let slice = core::slice::from_raw_parts_mut(ptr, p.page_count * L3_PAGE_SIZE); + slice.fill(0); + } } impl AsPhysicalAddress for PageBox { diff --git a/libk/libk-thread/src/lib.rs b/libk/libk-thread/src/lib.rs index ec92f2e8..6360d83e 100644 --- a/libk/libk-thread/src/lib.rs +++ b/libk/libk-thread/src/lib.rs @@ -12,7 +12,7 @@ extern crate alloc; use api::__signal_process_group; -use kernel_arch::KernelTableManagerImpl; +use kernel_arch::{Architecture, ArchitectureImpl, KernelTableManagerImpl}; use libk_mm::phys::GlobalPhysicalAllocator; pub(crate) mod api { @@ -38,10 +38,21 @@ pub mod types; pub type TaskContextImpl = kernel_arch::TaskContextImpl; +use sched::CpuQueue; pub use types::{AtomicThreadState, ThreadAffinity, ThreadId, ThreadState}; use yggdrasil_abi::process::Signal; +/// Returns local CPU index +#[inline] +pub fn cpu_index() -> u32 { + ArchitectureImpl::cpu_index::() +} + +pub fn cpu_count() -> usize { + ArchitectureImpl::cpu_count() +} + pub fn signal_process_group(group_id: u32, signal: Signal) { unsafe { __signal_process_group(group_id, signal) } } diff --git a/libk/libk-thread/src/sync.rs b/libk/libk-thread/src/sync.rs index dc85dec3..175be23a 100644 --- a/libk/libk-thread/src/sync.rs +++ b/libk/libk-thread/src/sync.rs @@ -1,13 +1,15 @@ use core::{ cell::UnsafeCell, + future::poll_fn, ops::{Deref, DerefMut}, - sync::atomic::{AtomicU32, Ordering}, + sync::atomic::{AtomicBool, AtomicU32, Ordering}, + task::{Context, Poll}, }; use alloc::sync::Arc; use crossbeam_queue::ArrayQueue; use kernel_arch::task::Scheduler; -use libk_util::sync::LockMethod; +use libk_util::{sync::LockMethod, waker::QueueWaker}; use yggdrasil_abi::error::Error; use crate::{sched::CpuQueue, thread::Thread}; @@ -17,6 +19,16 @@ struct ThreadedMutexInner { lock: AtomicU32, } +pub struct AsyncMutex { + value: UnsafeCell, + waker: QueueWaker, + lock: AtomicBool, +} + +pub struct AsyncMutexGuard<'a, T> { + mutex: &'a AsyncMutex, +} + pub struct Mutex { value: UnsafeCell, lock: ThreadedMutexInner, @@ -27,6 +39,74 @@ pub struct MutexGuard<'a, T> { lock: &'a ThreadedMutexInner, } +impl AsyncMutex { + pub fn new(value: T) -> Self { + Self { + value: UnsafeCell::new(value), + waker: QueueWaker::new(), + lock: AtomicBool::new(false), + } + } + + pub fn try_lock(&self) -> bool { + self.lock + .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) + .is_ok() + } + + pub fn poll_lock(&self, cx: &mut Context<'_>) -> Poll> { + self.waker.register(cx.waker()); + + if self.try_lock() { + self.waker.remove(cx.waker()); + return Poll::Ready(AsyncMutexGuard { mutex: self }); + } + + Poll::Pending + } + + pub async fn lock(&self) -> AsyncMutexGuard { + poll_fn(|cx| self.poll_lock(cx)).await + } + + pub unsafe fn force_unlock(&self) { + self.lock.store(false, Ordering::Release); + self.waker.wake_one(); + } + + #[inline] + pub fn get(&self) -> *mut T { + self.value.get() + } +} + +unsafe impl Sync for AsyncMutex {} + +unsafe impl<'a, T> Send for AsyncMutexGuard<'a, T> {} +unsafe impl<'a, T> Sync for AsyncMutexGuard<'a, T> {} + +impl<'a, T> Deref for AsyncMutexGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.mutex.get() } + } +} + +impl<'a, T> DerefMut for AsyncMutexGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.mutex.get() } + } +} + +impl<'a, T> Drop for AsyncMutexGuard<'a, T> { + fn drop(&mut self) { + unsafe { + self.mutex.force_unlock(); + } + } +} + impl ThreadedMutexInner { const UNLOCKED: u32 = 0; const LOCKED: u32 = 1; diff --git a/libk/src/lib.rs b/libk/src/lib.rs index c035bb55..4c65d5ed 100644 --- a/libk/src/lib.rs +++ b/libk/src/lib.rs @@ -16,12 +16,9 @@ trait_alias )] -use arch::Cpu; -use kernel_arch::{Architecture, ArchitectureImpl, CpuImpl}; - extern crate alloc; -pub use libk_thread::{block, runtime}; +pub use libk_thread::{block, cpu_count, cpu_index, runtime}; pub mod arch; @@ -29,17 +26,6 @@ pub mod device { pub use libk_device::*; } -#[inline] -pub fn cpu_count() -> usize { - ArchitectureImpl::cpu_count() -} - -/// Returns local CPU index -#[inline] -pub fn cpu_index() -> u32 { - Cpu::try_local().as_deref().map(CpuImpl::id).unwrap_or(0) -} - #[repr(C)] pub struct AlignedTo { pub align: [Align; 0], diff --git a/src/arch/x86_64/apic/ioapic.rs b/src/arch/x86_64/apic/ioapic.rs index 1861a0cc..80f4f1ad 100644 --- a/src/arch/x86_64/apic/ioapic.rs +++ b/src/arch/x86_64/apic/ioapic.rs @@ -198,14 +198,10 @@ impl ExternalInterruptController for IoApic { ) } else { // Directly mapped to a GSI - ( - (irq - ISA_IRQ_OFFSET) as u32, - options.level, - options.trigger, - ) + (irq - ISA_IRQ_OFFSET, options.level, options.trigger) } } - Irq::External(irq) => (irq as u32, options.level, options.trigger), + Irq::External(irq) => (irq, options.level, options.trigger), Irq::Private(_) => unimplemented!(), }; diff --git a/src/arch/x86_64/apic/local.rs b/src/arch/x86_64/apic/local.rs index ddc93fd4..0ce7443a 100644 --- a/src/arch/x86_64/apic/local.rs +++ b/src/arch/x86_64/apic/local.rs @@ -225,9 +225,7 @@ impl MessageInterruptController for LocalApic { }; drop(table); - if handler.handle_irq(Some(vector)) { - break; - } + handler.handle_irq(Some(vector)); i += 1; } diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index 673a195d..db5dc6f9 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -4,10 +4,7 @@ use core::{mem::size_of, ops::DerefMut, ptr::null_mut, sync::atomic::Ordering}; use abi::error::Error; use acpi_lib::{mcfg::Mcfg, AcpiTables, InterruptModel}; use alloc::boxed::Box; -use device_api::{ - interrupt::{Irq, MessageInterruptController}, - Device, -}; +use device_api::{interrupt::Irq, Device}; use git_version::git_version; use kernel_arch_x86_64::{ mem::{ @@ -305,6 +302,13 @@ impl X86_64 { Some(0x01), ygg_driver_ahci::probe, ); + ygg_driver_pci::register_class_driver( + "USB xHCI", + 0x0C, + Some(0x03), + Some(0x30), + ygg_driver_usb_xhci::probe, + ); ygg_driver_pci::register_vendor_driver( "Virtio PCI Network Device", 0x1AF4, @@ -487,8 +491,3 @@ impl X86_64 { pic_slave_cmd.write(0x20); } } - -#[no_mangle] -fn __message_interrupt_controller() -> &'static dyn MessageInterruptController { - Cpu::local().local_apic -} diff --git a/src/arch/x86_64/peripherals/ps2/mod.rs b/src/arch/x86_64/peripherals/ps2/mod.rs index b70005a9..cf9315c3 100644 --- a/src/arch/x86_64/peripherals/ps2/mod.rs +++ b/src/arch/x86_64/peripherals/ps2/mod.rs @@ -10,12 +10,9 @@ use device_api::{ use libk::device::external_interrupt_controller; use libk_util::sync::IrqSafeSpinlock; -use crate::{ - arch::x86_64::{ - intrinsics::{IoPort, IoPortAccess}, - peripherals::ps2::codeset::{CODE_SET_1_00, CODE_SET_1_E0}, - }, - device::input, +use crate::arch::x86_64::{ + intrinsics::{IoPort, IoPortAccess}, + peripherals::ps2::codeset::{CODE_SET_1_00, CODE_SET_1_E0}, }; mod codeset; @@ -102,7 +99,7 @@ impl InterruptHandler for PS2Controller { KeyboardKeyEvent::Pressed(key) }; - input::send_event(event); + ygg_driver_input::send_event(event); } count != 0 diff --git a/src/device/mod.rs b/src/device/mod.rs index 7046c1c3..6fd64d9e 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -6,7 +6,6 @@ use libk_util::sync::{IrqSafeSpinlock, IrqSafeSpinlockGuard}; pub mod bus; pub mod display; -pub mod input; pub mod power; pub mod serial; pub mod timer; diff --git a/src/init.rs b/src/init.rs index 2855261d..74c744e2 100644 --- a/src/init.rs +++ b/src/init.rs @@ -8,7 +8,6 @@ use memfs::MemoryFilesystem; use vfs::{IoContext, NodeRef}; use crate::{ - device::input, fs::{FileBlockAllocator, INITRD_DATA}, proc::{self, random}, }; @@ -28,6 +27,8 @@ fn setup_root() -> Result { pub fn kinit() -> Result<(), Error> { infoln!("In main"); + runtime::spawn(ygg_driver_usb::bus::bus_handler())?; + ygg_driver_net_loopback::init(); ygg_driver_net_core::start_network_tasks()?; @@ -41,7 +42,7 @@ pub fn kinit() -> Result<(), Error> { } // Add keyboard device - devfs::add_named_char_device(&input::KEYBOARD_DEVICE, "kbd".to_owned())?; + devfs::add_named_char_device(&ygg_driver_input::KEYBOARD_DEVICE, "kbd".to_owned())?; random::init(); diff --git a/tools/gentables/src/main.rs b/tools/gentables/src/main.rs index 7edfcd9c..3ec366ff 100644 --- a/tools/gentables/src/main.rs +++ b/tools/gentables/src/main.rs @@ -1,5 +1,3 @@ -#![feature(offset_of)] - use std::{ fs::OpenOptions, io::{Read, Seek, SeekFrom, Write},