diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 33e3fc5..f20f302 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + [[package]] name = "bitfield-struct" version = "0.8.0" @@ -13,17 +19,6 @@ dependencies = [ "syn", ] -[[package]] -name = "bitfield-struct" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8769c4854c5ada2852ddf6fd09d15cf43d4c2aaeccb4de6432f5402f08a6003b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "convert_case" version = "0.6.0" @@ -37,7 +32,7 @@ dependencies = [ name = "denali" version = "0.1.0" dependencies = [ - "bitfield-struct 0.8.0", + "bitfield-struct", "mammoth", "pci", "yellowstone-yunq", @@ -74,10 +69,11 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.14" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ + "autocfg", "scopeguard", ] @@ -92,15 +88,15 @@ dependencies = [ name = "pci" version = "0.1.0" dependencies = [ - "bitfield-struct 0.8.0", + "bitfield-struct", "mammoth", ] [[package]] name = "prettyplease" -version = "0.2.37" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", "syn", @@ -108,18 +104,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -141,9 +137,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.111" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -165,21 +161,21 @@ version = "0.1.0" dependencies = [ "mammoth", "victoriafalls", - "voyageurs_client", + "voyageurs", "yellowstone-yunq", ] [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "victoriafalls" @@ -193,26 +189,9 @@ dependencies = [ "yunqc", ] -[[package]] -name = "volatile" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8ca9a5d4debca0633e697c88269395493cebf2e10db21ca2dbde37c1356452" - [[package]] name = "voyageurs" version = "0.1.0" -dependencies = [ - "bitfield-struct 0.12.1", - "mammoth", - "pci", - "volatile", - "yellowstone-yunq", -] - -[[package]] -name = "voyageurs_client" -version = "0.1.0" dependencies = [ "mammoth", "yellowstone-yunq", @@ -227,6 +206,7 @@ dependencies = [ "denali_client", "mammoth", "victoriafalls", + "voyageurs", "yellowstone-yunq", "yunq", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index b31a682..f1886f6 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,19 +1,16 @@ [workspace] members = [ - "lib/client/denali_client", - "lib/client/voyageurs_client", - "lib/fs/ext2", - "lib/mammoth", - "lib/pci", - "lib/yellowstone", - "lib/yunq", - "lib/yunq-test", - "sys/denali", - "sys/teton", - "sys/victoriafalls", - "sys/voyageurs", - "sys/yellowstone", - "usr/testbed", + "lib/client/denali_client", "lib/fs/ext2", + "lib/mammoth", "lib/pci", + "lib/voyageurs", + "lib/yellowstone", + "lib/yunq", + "lib/yunq-test", + "sys/denali", + "sys/teton", + "sys/victoriafalls", + "sys/yellowstone", + "usr/testbed", ] resolver = "2" diff --git a/rust/lib/client/voyageurs_client/Cargo.toml b/rust/lib/client/voyageurs_client/Cargo.toml deleted file mode 100644 index e3e432c..0000000 --- a/rust/lib/client/voyageurs_client/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "voyageurs_client" -version = "0.1.0" -edition = "2021" - -[dependencies] -mammoth = { path = "../../mammoth" } -yellowstone-yunq = { path = "../../yellowstone" } -yunq = { path = "../../yunq" } - -[build-dependencies] -yunqc = { path = "../../../../yunq/rust" } diff --git a/rust/lib/mammoth/src/elf.rs b/rust/lib/mammoth/src/elf.rs index 28b636f..96807d2 100644 --- a/rust/lib/mammoth/src/elf.rs +++ b/rust/lib/mammoth/src/elf.rs @@ -238,7 +238,9 @@ fn load_program_segment( let mut mem_object = crate::mem::MemoryRegion::new(mem_size)?; - mem_object.zero_region(); + for i in mem_object.mut_slice() { + *i = 0; + } let file_start = prog_header.offset as usize; let file_end = file_start + prog_header.file_size as usize; diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index ce4f915..2058a6b 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -13,7 +13,6 @@ mod cap_syscall; pub mod elf; pub mod init; pub mod mem; -pub mod physical_box; pub mod port; pub mod sync; pub mod syscall; diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index d10e65d..90183ec 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -3,7 +3,7 @@ use crate::syscall; use crate::zion::ZError; use alloc::slice; use core::fmt::Debug; -use core::ptr::{addr_of, addr_of_mut, read_volatile, write_volatile, NonNull}; +use core::ptr::{addr_of, addr_of_mut}; #[cfg(feature = "hosted")] use linked_list_allocator::LockedHeap; @@ -29,7 +29,6 @@ pub fn init_heap() { pub struct MemoryRegion { mem_cap: Capability, virt_addr: u64, - // TODO: This should be a usize probably. size: u64, } @@ -77,10 +76,6 @@ impl MemoryRegion { }) } - pub fn vaddr(&self) -> usize { - self.virt_addr as usize - } - pub fn slice(&self) -> &[T] { unsafe { slice::from_raw_parts( @@ -99,52 +94,13 @@ impl MemoryRegion { } } - pub fn zero_region(&mut self) { - for i in self.mut_slice() { - *i = 0; - } - } - pub fn raw_ptr_at_offset(&self, offset: u64) -> *const T { + // TODO: Come up with a better safety check here. + // We can't use the size of T because it might not be sized. assert!(offset + size_of::() as u64 <= self.size); (self.virt_addr + offset) as *const T } - pub fn mut_ptr_at_offset(&self, offset: usize) -> *mut T { - assert!(offset + size_of::() <= self.size as usize); - (self.virt_addr as usize + offset) as *mut T - } - - /// Creates a reference from a given offset. - /// - /// # Safety - /// - Caller must ensure that the memory pointed to by this - /// pointer must not get mutated while the reference exists. - pub unsafe fn as_ref_at_offset(&self, offset: usize) -> &T { - let ptr: *const T = self.raw_ptr_at_offset(offset as u64); - assert!(ptr.is_aligned(), ""); - // SAFETY: - // - We checked alignment. - // - self.vaddr + offset can't be null. - // - It is dereferenceable because it is entirely within this memory region. - &*self.raw_ptr_at_offset::(offset as u64) - } - - /// Creates a reference from a given offset. - /// - /// # Safety - /// - Caller must ensure that this is the only reference to the memory pointed - /// to by this pointer. - pub unsafe fn as_mut_ref_at_offset(&mut self, offset: usize) -> &mut T { - let ptr: *const T = self.raw_ptr_at_offset(offset as u64); - assert!(ptr.is_aligned(), ""); - // SAFETY: - // - We checked alignment. - // - self.vaddr + offset can't be null. - // - It is dereferenceable because it is entirely within this memory region. - &mut *self.mut_ptr_at_offset::(offset) - } - pub fn cap(&self) -> &Capability { &self.mem_cap } @@ -181,22 +137,28 @@ impl Drop for MemoryRegion { } } -#[repr(transparent)] -pub struct Volatile(T); +pub struct Volatile { + /// TODO: This should maybe be MaybeUninit. + data: T, +} -impl Volatile { - pub fn read(&self) -> T { - unsafe { read_volatile(addr_of!(self.0)) } +impl Volatile { + pub fn read(&self) -> T + where + T: Copy, + { + unsafe { addr_of!(self.data).cast::().read_volatile() } } pub fn write(&mut self, data: T) { unsafe { - write_volatile(addr_of_mut!(self.0), data); + addr_of_mut!(self.data).cast::().write_volatile(data); } } pub fn update(&mut self, func: F) where + T: Copy, F: Fn(&mut T), { let mut data = self.read(); @@ -214,49 +176,17 @@ where } } -#[macro_export] -macro_rules! read_unaligned_volatile { - ($struct_ptr:expr, $field:ident) => { - unsafe { - let field_ptr = core::ptr::addr_of!((*$struct_ptr).$field); - core::ptr::read_volatile(field_ptr as *const _) - } - }; -} - -#[macro_export] -macro_rules! write_unaligned_volatile { - ($struct_ptr:expr, $field:ident, $value:expr) => { - unsafe { - let field_ptr = core::ptr::addr_of!((*$struct_ptr).$field); - core::ptr::write_volatile(field_ptr as *mut _, $value); - } - }; -} - -#[macro_export] -macro_rules! map_unaligned_volatile { - ($struct_ptr:expr, $field:ident, $func:expr) => { - unsafe { - let field_ptr = core::ptr::addr_of!((*$struct_ptr).$field); - let value = core::ptr::read_volatile(field_ptr as *const _); - core::ptr::write_volatile(field_ptr as *mut _, ($func)(value)); - } - }; -} - pub fn map_cap_and_leak(mem_cap: Capability) -> u64 { let vaddr = syscall::address_space_map(&mem_cap).unwrap(); mem_cap.release(); vaddr } -pub fn map_direct_physical_and_leak(paddr: usize, size: usize) -> NonNull { - let mem_cap = syscall::memory_object_direct_physical(paddr as u64, size as u64).unwrap(); +pub fn map_direct_physical_and_leak(paddr: u64, size: u64) -> u64 { + let mem_cap = syscall::memory_object_direct_physical(paddr, size).unwrap(); let vaddr = syscall::address_space_map(&mem_cap).unwrap(); mem_cap.release(); - // UNWRAP: The kernel guarantees this is valid. - NonNull::new(vaddr as *mut T).unwrap() + vaddr } pub fn map_physical_and_leak(size: u64) -> (u64, u64) { diff --git a/rust/lib/mammoth/src/physical_box.rs b/rust/lib/mammoth/src/physical_box.rs deleted file mode 100644 index af68cba..0000000 --- a/rust/lib/mammoth/src/physical_box.rs +++ /dev/null @@ -1,159 +0,0 @@ -use core::{ - marker::PhantomData, - ops::{Deref, DerefMut, Index, IndexMut}, - ptr::NonNull, -}; - -use alloc::{boxed::Box, slice, vec::Vec}; - -use crate::mem::MemoryRegion; - -pub struct PhysicalBox { - data: NonNull, - #[allow(dead_code)] - region: MemoryRegion, - physical_address: usize, - _marker: PhantomData, -} - -impl PhysicalBox { - pub fn new(data: T) -> Self { - let (memory_region, paddr) = - MemoryRegion::contiguous_physical(size_of::() as u64).expect("Failed to allocate"); - // UNWRAP: We know this isn't null. - let ptr = NonNull::new(memory_region.mut_ptr_at_offset(0)).unwrap(); - unsafe { ptr.write(data) }; - Self { - data: ptr, - region: memory_region, - physical_address: paddr as usize, - _marker: PhantomData, - } - } -} - -impl PhysicalBox { - pub fn physical_address(&self) -> usize { - self.physical_address - } -} - -impl Deref for PhysicalBox { - type Target = T; - - fn deref(&self) -> &Self::Target { - // SAFETY: - // - Alignment: This is page aligned. - // - Dereferenceable: Guaranteed in same allocation. - // - Aliasing: The borrow rules ensure this - unsafe { self.data.as_ref() } - } -} - -impl DerefMut for PhysicalBox { - fn deref_mut(&mut self) -> &mut Self::Target { - // SAFETY: - // - Alignment: This is page aligned. - // - Dereferenceable: Guaranteed in same allocation. - // - Aliasing: The borrow rules ensure this - unsafe { self.data.as_mut() } - } -} - -impl PhysicalBox<[T]> { - pub fn default_with_count(default: T, len: usize) -> Self - where - T: Clone, - { - let layout = core::alloc::Layout::array::(len).expect("Layout overflow"); - - // TODO: Implement a function like alloc that takes a layout. - let (memory_region, paddr) = - MemoryRegion::contiguous_physical(layout.size() as u64).expect("Failed to allocate"); - - let ptr: *mut T = memory_region.mut_ptr_at_offset(0); - for i in 0..len { - unsafe { - ptr.add(i).write(default.clone()); - } - } - - let slice_ptr = core::ptr::slice_from_raw_parts_mut(ptr, len); - - Self { - // UNWRAP: We know this isn't null. - data: NonNull::new(slice_ptr).unwrap(), - region: memory_region, - physical_address: paddr as usize, - _marker: PhantomData, - } - } - - pub fn from_vec(vec: Vec) -> Self { - let len = vec.len(); - let layout = core::alloc::Layout::array::(len).expect("Layout overflow"); - - // TODO: Implement a function like alloc that takes a layout. - let (memory_region, paddr) = - MemoryRegion::contiguous_physical(layout.size() as u64).expect("Failed to allocate"); - - let ptr: *mut T = memory_region.mut_ptr_at_offset(0); - for (i, item) in vec.into_iter().enumerate() { - unsafe { - ptr.add(i).write(item); - } - } - - let slice_ptr = core::ptr::slice_from_raw_parts_mut(ptr, len); - - Self { - // UNWRAP: We know this isn't null. - data: NonNull::new(slice_ptr).unwrap(), - region: memory_region, - physical_address: paddr as usize, - _marker: PhantomData, - } - } - pub fn len(&self) -> usize { - (**self).len() - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -impl Index for PhysicalBox<[T]> -where - I: slice::SliceIndex<[T]>, -{ - type Output = I::Output; - - fn index(&self, index: I) -> &Self::Output { - &(**self)[index] - } -} - -impl IndexMut for PhysicalBox<[T]> -where - I: slice::SliceIndex<[T]>, -{ - fn index_mut(&mut self, index: I) -> &mut Self::Output { - &mut (**self)[index] - } -} - -/// SAFETY: We are the only owner of this pointer. -unsafe impl Send for PhysicalBox where Box: Send {} - -/// SAFETY: You must have a mutable reference to this -/// type to modify the data at the pointer. -unsafe impl Sync for PhysicalBox where Box: Sync {} - -impl Drop for PhysicalBox { - fn drop(&mut self) { - // SAFETY: - // - We own this data. - unsafe { core::ptr::drop_in_place(self.data.as_ptr()) } - } -} diff --git a/rust/lib/mammoth/src/task/mod.rs b/rust/lib/mammoth/src/task/mod.rs index fee1a9d..ec25afa 100644 --- a/rust/lib/mammoth/src/task/mod.rs +++ b/rust/lib/mammoth/src/task/mod.rs @@ -122,7 +122,6 @@ impl Executor { } } -#[derive(Clone)] pub struct Spawner { tasks: Arc>>, task_queue: Arc>>, diff --git a/rust/lib/pci/src/device.rs b/rust/lib/pci/src/device.rs index d74cb82..e65e3da 100644 --- a/rust/lib/pci/src/device.rs +++ b/rust/lib/pci/src/device.rs @@ -71,15 +71,15 @@ impl PciDevice { control.capable_address_64(), "We don't handle the non-64bit case for MSI yet." ); - - if control.multi_message_capable() != 0 { - mammoth::debug!("WARN: We don't yet handle multi-message capable devices."); - } + assert!( + control.multi_message_capable() == 0, + "We don't yet handle multi-message capable devices." + ); // FIXME: These probably need to be volatile writes. let header: &mut PciDeviceHeader = self.memory_region.as_mut(); header.command = header.command.with_interrupt_disable(true); - msi_cap.msi_control = control.with_msi_enable(true).with_multi_message_enable(0); + msi_cap.msi_control = control.with_msi_enable(true); // For setting addr and data field, see intel ref // Vol 3. Section 11.11 diff --git a/rust/lib/voyageurs/Cargo.toml b/rust/lib/voyageurs/Cargo.toml new file mode 100644 index 0000000..e011e0c --- /dev/null +++ b/rust/lib/voyageurs/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "voyageurs" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../mammoth" } +yellowstone-yunq = { path = "../yellowstone" } +yunq = {path = "../yunq"} + +[build-dependencies] +yunqc = {path = "../../../yunq/rust"} + diff --git a/rust/lib/client/voyageurs_client/build.rs b/rust/lib/voyageurs/build.rs similarity index 82% rename from rust/lib/client/voyageurs_client/build.rs rename to rust/lib/voyageurs/build.rs index f6f76ad..52b5dfc 100644 --- a/rust/lib/client/voyageurs_client/build.rs +++ b/rust/lib/voyageurs/build.rs @@ -1,7 +1,7 @@ use std::fs; fn main() { - let input_file = "../../../../sys/voyageurs/lib/voyageurs/voyageurs.yunq"; + let input_file = "../../../sys/voyageurs/lib/voyageurs/voyageurs.yunq"; println!("cargo::rerun-if-changed={input_file}"); diff --git a/rust/lib/client/voyageurs_client/src/lib.rs b/rust/lib/voyageurs/src/lib.rs similarity index 100% rename from rust/lib/client/voyageurs_client/src/lib.rs rename to rust/lib/voyageurs/src/lib.rs diff --git a/rust/lib/client/voyageurs_client/src/listener.rs b/rust/lib/voyageurs/src/listener.rs similarity index 100% rename from rust/lib/client/voyageurs_client/src/listener.rs rename to rust/lib/voyageurs/src/listener.rs diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index dd51807..2a402f0 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -1,5 +1,3 @@ -use core::ffi::c_void; - use alloc::sync::Arc; use mammoth::{ cap::Capability, @@ -28,11 +26,8 @@ impl AhciController { pub fn new(pci_memory: Capability) -> Self { let pci_device = PciDevice::from_cap(pci_memory).unwrap(); - let hba_vaddr = mem::map_direct_physical_and_leak::( - pci_device.header().bars[5] as usize, - 0x1100, - ) - .as_ptr() as u64; + let hba_vaddr = + mem::map_direct_physical_and_leak(pci_device.header().bars[5] as u64, 0x1100); let hba = unsafe { (hba_vaddr as *mut AhciHba).as_mut().unwrap() }; let mut controller = Self { pci_device: Mutex::new(pci_device), diff --git a/rust/sys/teton/Cargo.toml b/rust/sys/teton/Cargo.toml index 3df98f4..baa787a 100644 --- a/rust/sys/teton/Cargo.toml +++ b/rust/sys/teton/Cargo.toml @@ -6,5 +6,5 @@ edition = "2021" [dependencies] mammoth = { path = "../../lib/mammoth" } victoriafalls = { path = "../victoriafalls" } -voyageurs_client = { path = "../../lib/client/voyageurs_client/" } +voyageurs = { path = "../../lib/voyageurs" } yellowstone-yunq = { path = "../../lib/yellowstone" } diff --git a/rust/sys/teton/src/main.rs b/rust/sys/teton/src/main.rs index b44dff6..982beb7 100644 --- a/rust/sys/teton/src/main.rs +++ b/rust/sys/teton/src/main.rs @@ -9,7 +9,7 @@ mod psf; mod terminal; use mammoth::{debug, define_entry, zion::z_err_t}; -use voyageurs_client::listener; +use voyageurs::listener; define_entry!(); diff --git a/rust/sys/teton/src/terminal.rs b/rust/sys/teton/src/terminal.rs index 20b7ee0..f8a9e0f 100644 --- a/rust/sys/teton/src/terminal.rs +++ b/rust/sys/teton/src/terminal.rs @@ -6,7 +6,7 @@ use alloc::{ string::{String, ToString}, }; use victoriafalls::dir; -use voyageurs_client::listener::KeyboardHandler; +use voyageurs::listener::KeyboardHandler; pub struct Terminal { console: Console, diff --git a/rust/sys/voyageurs/Cargo.toml b/rust/sys/voyageurs/Cargo.toml deleted file mode 100644 index bd65fff..0000000 --- a/rust/sys/voyageurs/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "voyageurs" -version = "0.1.0" -edition = "2024" - -[dependencies] -bitfield-struct = "0.12" -mammoth = { path = "../../lib/mammoth/" } -pci = { path = "../../lib/pci" } -volatile = "0.6.1" -yellowstone-yunq = { version = "0.1.0", path = "../../lib/yellowstone" } - -[features] -default = ["debug"] -debug = [] diff --git a/rust/sys/voyageurs/src/main.rs b/rust/sys/voyageurs/src/main.rs deleted file mode 100644 index 92a3ee1..0000000 --- a/rust/sys/voyageurs/src/main.rs +++ /dev/null @@ -1,51 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; - -mod xhci; - -use alloc::sync::Arc; -use mammoth::{ - cap::Capability, - debug, define_entry, - sync::Mutex, - task::{Executor, Task}, - zion::z_err_t, -}; -use pci::PciDevice; -use xhci::driver::XHCIDriver; - -define_entry!(); - -#[unsafe(no_mangle)] -extern "C" fn main() -> z_err_t { - #[cfg(feature = "debug")] - debug!("Voyageurs Starting."); - - let yellowstone = yellowstone_yunq::from_init_endpoint(); - - let xhci_info = yellowstone - .get_xhci_info() - .expect("Failed to get XHCI info from yellowstone."); - - let pci_device = PciDevice::from_cap(Capability::take(xhci_info.xhci_region)).unwrap(); - - let xhci_driver = Arc::new(XHCIDriver::from_pci_device(pci_device)); - - let executor = Arc::new(Mutex::new(Executor::new())); - - let driver_clone = xhci_driver.clone(); - let spawner = executor.clone().lock().new_spawner(); - let interrupt_thread = mammoth::thread::spawn(move || driver_clone.interrupt_loop(spawner)); - - executor - .clone() - .lock() - .spawn(Task::new(async move { xhci_driver.startup().await })); - - executor.clone().lock().run(); - interrupt_thread.join().unwrap(); - - 0 -} diff --git a/rust/sys/voyageurs/src/xhci/data_structures/command_trb.rs b/rust/sys/voyageurs/src/xhci/data_structures/command_trb.rs deleted file mode 100644 index d55b85a..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/command_trb.rs +++ /dev/null @@ -1,71 +0,0 @@ -use bitfield_struct::bitfield; - -use crate::xhci::data_structures::{TransferRequestBlock, TrbType}; - -pub struct EnableSlotTrb {} - -#[bitfield(u128)] -pub struct EnableSlotCommand { - __: u64, - __: u32, - #[bits(10)] - __: u16, - #[bits(6, default=TrbType::EnableSlotCommand)] - trb_type: TrbType, - #[bits(5)] - slot_type: u8, - #[bits(11)] - __: u16, -} - -impl From for CommandTrb { - fn from(value: EnableSlotCommand) -> Self { - Self(value.into_bits().into()) - } -} - -#[bitfield(u128)] -pub struct AddressDeviceCommand { - pub input_context_pointer: u64, - __: u32, - #[bits(9)] - __: u16, - pub block_set_address_request: bool, - #[bits(6, default=TrbType::AddressDeviceCommand)] - trb_typ: TrbType, - __: u8, - pub slot_id: u8, -} - -impl From for CommandTrb { - fn from(value: AddressDeviceCommand) -> Self { - Self(value.into_bits().into()) - } -} - -#[bitfield(u128)] -pub struct NoOpCommand { - __: u64, - __: u32, - cycle: bool, - #[bits(9)] - __: u16, - #[bits(6, default = TrbType::NoOpCommand)] - trb_type: TrbType, - __: u16, -} - -impl From for CommandTrb { - fn from(value: NoOpCommand) -> Self { - Self(value.into_bits().into()) - } -} - -/// Simple type to ensure we are only sending commands to command rings. -pub struct CommandTrb(TransferRequestBlock); - -impl From for TransferRequestBlock { - fn from(value: CommandTrb) -> Self { - value.0 - } -} diff --git a/rust/sys/voyageurs/src/xhci/data_structures/device_context.rs b/rust/sys/voyageurs/src/xhci/data_structures/device_context.rs deleted file mode 100644 index 2d2946b..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/device_context.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::xhci::data_structures::{EndpointContext, SlotContext}; - -#[repr(C, align(64))] -#[derive(Default)] -pub struct DeviceContext { - slot_context: SlotContext, - endpoint_context_0: EndpointContext, - endpoint_contexts: [EndpointContext; 30], -} - -const _: () = assert!(size_of::() == 0x400); diff --git a/rust/sys/voyageurs/src/xhci/data_structures/endpoint_context.rs b/rust/sys/voyageurs/src/xhci/data_structures/endpoint_context.rs deleted file mode 100644 index c013c87..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/endpoint_context.rs +++ /dev/null @@ -1,206 +0,0 @@ -use bitfield_struct::{bitenum, bitfield}; - -#[repr(u8)] -#[bitenum] -#[derive(Debug)] -pub enum EndpointState { - /// The endpoint is not operationa. - Disabled = 0, - /// The endpoint is operational, either waiting for a doorbell ring or processing TDs. - Running = 1, - /// The endpoint is halted due to a Halt condition detected on the USB. SW shall issue - /// Reset Endpoint Command to recover from the Halt condition and transition to the Stopped - /// state. SW may manipulate the Transfer Ring while in this state - Halted = 2, - /// The endpoint is not running due to a Stop Endpoint Command or recovering - /// from a Halt condition. SW may manipulate the Transfer Ring while in this state. - Stopped = 3, - /// The endpoint is not running due to a TRB Error. SW may manipulate the Transfer - /// Ring while in this state. - Error = 4, - #[fallback] - Unknown = 5, -} - -#[repr(u8)] -#[bitenum] -#[derive(Debug)] -pub enum EndpointType { - #[fallback] - NotValid = 0, - IsochOut = 1, - BulkOut = 2, - InterruptOut = 3, - Control = 4, - IsochIn = 5, - BulkIn = 6, - InterruptIn = 7, -} - -#[bitfield(u64)] -pub struct EndpointContextFields { - /// Endpoint State (EP State). The Endpoint State identifies the current operational state of the - /// endpoint. - /// - /// As Output, a Running to Halted transition is forced by the xHC if a STALL condition is detected - /// on the endpoint. A Running to Error transition is forced by the xHC if a TRB Error condition is - /// detected. - /// - /// As Input, this field is initialized to ‘0’ by software. - /// - /// Refer to section 4.8.3 for more information on Endpoint State. - #[bits(3)] - pub endpoint_state: EndpointState, - #[bits(5)] - __: u8, - /// Mult. If LEC = ‘0’, then this field indicates the maximum number of bursts within an Interval that - /// this endpoint supports. Mult is a “zero-based” value, where 0 to 3 represents 1 to 4 bursts, - /// respectively. The valid range of values is ‘0’ to ‘2’.111 This field shall be ‘0’ for all endpoint types - /// except for SS Isochronous. - /// - /// If LEC = ‘1’, then this field shall be RsvdZ and Mult is calculated as: - /// ROUNDUP(Max ESIT Payload / Max Packet Size / (Max Burst Size + 1)) - 1 - #[bits(2)] - pub mult: u8, - /// Max Primary Streams (MaxPStreams). This field identifies the maximum number of Primary - /// Stream IDs this endpoint supports. Valid values are defined below. If the value of this field is ‘0’, - /// then the TR Dequeue Pointer field shall point to a Transfer Ring. If this field is > '0' then the TR - /// Dequeue Pointer field shall point to a Primary Stream Context Array. Refer to section 4.12 for - /// more information. - /// - /// A value of ‘0’ indicates that Streams are not supported by this endpoint and the Endpoint - /// Context TR Dequeue Pointer field references a Transfer Ring. - /// - /// A value of ‘1’ to ‘15’ indicates that the Primary Stream ID Width is MaxPstreams+1 and the - /// Primary Stream Array contains 2MaxPStreams+1 entries. - /// - /// For SS Bulk endpoints, the range of valid values for this field is defined by the MaxPSASize field - /// in the HCCPARAMS1 register (refer to Table 5-13). - /// - /// This field shall be '0' for all SS Control, Isoch, and Interrupt endpoints, and for all non-SS - /// endpoints. - #[bits(5)] - pub max_primary_streams: u8, - /// Linear Stream Array (LSA). This field identifies how a Stream ID shall be interpreted. - /// Setting this bit to a value of ‘1’ shall disable Secondary Stream Arrays and a Stream ID shall be - /// interpreted as a linear index into the Primary Stream Array, where valid values for MaxPStreams - /// are ‘1’ to ‘15’. - /// - /// A value of ‘0’ shall enable Secondary Stream Arrays, where the low order (MaxPStreams+1) bits - /// of a Stream ID shall be interpreted as a linear index into the Primary Stream Array, where valid - /// values for MaxPStreams are ‘1’ to ‘7’. And the high order bits of a Stream ID shall be interpreted - /// as a linear index into the Secondary Stream Array. - /// - /// If MaxPStreams = ‘0’, this field RsvdZ. - /// - /// Refer to section 4.12.2 for more information - pub linear_stream_array: bool, - /// Interval. The period between consecutive requests to a USB endpoint to send or receive data. - /// Expressed in 125 μs. increments. The period is calculated as 125 μs. * 2Interval; e.g., an Interval - /// value of 0 means a period of 125 μs. (20 = 1 * 125 μs.), a value of 1 means a period of 250 μs. (21 - /// = 2 * 125 μs.), a value of 4 means a period of 2 ms. (24 = 16 * 125 μs.), etc. Refer to Table 6-12 - /// for legal Interval field values. See further discussion of this field below. Refer to section 6.2.3.6 - /// for more information. - pub interval: u8, - /// Max Endpoint Service Time Interval Payload High (Max ESIT Payload Hi). If LEC = '1', then this - /// field indicates the high order 8 bits of the Max ESIT Payload value. If LEC = '0', then this field - /// shall be RsvdZ. Refer to section 6.2.3.8 for more information. - pub max_esit_payload_hi: u8, - __: bool, - /// Error Count (CErr)112. This field defines a 2-bit down count, which identifies the number of - /// consecutive USB Bus Errors allowed while executing a TD. If this field is programmed with a - /// non-zero value when the Endpoint Context is initialized, the xHC loads this value into an internal - /// Bus Error Counter before executing a USB transaction and decrements it if the transaction fails. - /// If the Bus Error Counter counts from ‘1’ to ‘0’, the xHC ceases execution of the TRB, sets the - /// endpoint to the Halted state, and generates a USB Transaction Error Event for the TRB that - /// caused the internal Bus Error Counter to decrement to ‘0’. If system software programs this field - /// to ‘0’, the xHC shall not count errors for TRBs on the Endpoint’s Transfer Ring and there shall be - /// no limit on the number of TRB retries. Refer to section 4.10.2.7 for more information on the - /// operation of the Bus Error Counter. - /// - /// Note: CErr does not apply to Isoch endpoints and shall be set to ‘0’ if EP Type = Isoch Out ('1') or - /// Isoch In ('5'). - #[bits(2)] - pub error_count: u8, - /// Endpoint Type (EP Type). This field identifies whether an Endpoint Context is Valid, and if so, - /// what type of endpoint the context defines. - #[bits(3)] - pub endpoint_type: EndpointType, - __: bool, - /// Host Initiate Disable (HID). This field affects Stream enabled endpoints, allowing the Host - /// Initiated Stream selection feature to be disabled for the endpoint. Setting this bit to a value of - /// ‘1’ shall disable the Host Initiated Stream selection feature. A value of ‘0’ will enable normal - /// Stream operation. Refer to section 4.12.1.1 for more information. - pub host_initiate_disable: bool, - /// Max Burst Size. This field indicates to the xHC the maximum number of consecutive USB - /// transactions that should be executed per scheduling opportunity. This is a “zero-based” value, - /// where 0 to 15 represents burst sizes of 1 to 16, respectively. Refer to section 6.2.3.4 for more - /// information. - pub max_burst_size: u8, - /// Max Packet Size. This field indicates the maximum packet size in bytes that this endpoint is - /// capable of sending or receiving when configured. Refer to section 6.2.3.5 for more information - pub max_packet_size: u16, -} - -#[bitfield(u64)] -pub struct TRDequeuePointer { - /// Dequeue Cycle State (DCS). This bit identifies the value of the xHC Consumer Cycle State (CCS) - /// flag for the TRB referenced by the TR Dequeue Pointer. Refer to section 4.9.2 for more - /// information. This field shall be ‘0’ if MaxPStreams > ‘0’ - pub dequeue_cycle_state: bool, - #[bits(3)] - __: u8, - /// TR Dequeue Pointer. As Input, this field represents the high order bits of the 64-bit base - /// address of a Transfer Ring or a Stream Context Array associated with this endpoint. If - /// MaxPStreams = '0' then this field shall point to a Transfer Ring. If MaxPStreams > '0' then this - /// field shall point to a Stream Context Array. - /// - /// As Output, if MaxPStreams = ‘0’ this field shall be used by the xHC to store the value of the - /// Dequeue Pointer when the endpoint enters the Halted or Stopped states, and the value of the - /// this field shall be undefined when the endpoint is not in the Halted or Stopped states. if - /// MaxPStreams > ‘0’ then this field shall point to a Stream Context Array. - /// The memory structure referenced by this physical memory pointer shall be aligned to a 16-byte - /// boundary. - #[bits(60)] - tr_deque_pointer: u64, -} - -impl TRDequeuePointer { - pub fn pointer(self) -> u64 { - self.tr_deque_pointer() << 4 - } - - pub fn set_pointer(&mut self, tr_deque_pointer: u64) { - self.set_tr_deque_pointer(tr_deque_pointer >> 4) - } - - pub fn with_pointer(self, tr_deque_pointer: u64) -> Self { - self.with_tr_deque_pointer(tr_deque_pointer >> 4) - } -} - -#[bitfield(u64)] -struct AdditionalFields { - /// Average TRB Length. This field represents the average Length of the TRBs executed by this - /// endpoint. The value of this field shall be greater than ‘0’. Refer to section 4.14.1.1 and the - /// implementation note TRB Lengths and System Bus Bandwidth for more information. - /// The xHC shall use this parameter to calculate system bus bandwidth requirements - pub average_trb_length: u16, - /// Max Endpoint Service Time Interval Payload Low (Max ESIT Payload Lo). This field indicates - /// the low order 16 bits of the Max ESIT Payload. The Max ESIT Payload represents the total - /// number of bytes this endpoint will transfer during an ESIT. This field is only valid for periodic - /// endpoints. Refer to section 6.2.3.8 for more information. - pub max_esit_payload_lo: u16, - __: u32, -} - -#[repr(C)] -#[derive(Default)] -pub struct EndpointContext { - pub fields: EndpointContextFields, - pub tr_deque_pointer: TRDequeuePointer, - additional_fields: AdditionalFields, - __: u64, -} - -const _: () = assert!(size_of::() == 0x20); diff --git a/rust/sys/voyageurs/src/xhci/data_structures/event_ring_segment_table.rs b/rust/sys/voyageurs/src/xhci/data_structures/event_ring_segment_table.rs deleted file mode 100644 index 4902da2..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/event_ring_segment_table.rs +++ /dev/null @@ -1,67 +0,0 @@ -use core::ops::{Index, IndexMut}; - -use mammoth::physical_box::PhysicalBox; - -use crate::xhci::data_structures::TrbRingSegment; - -#[repr(align(64))] -#[derive(Default, Clone)] -pub struct EventRingSegmentTableEntry { - /// Ring Segment Base Address Hi and Lo. These fields represent the high order bits of the 64-bit - /// base address of the Event Ring Segment. - /// The memory structure referenced by this physical memory pointer shall begin on a 64-byte - /// address boundary. - pub ring_segment_base_address: u64, - /// Ring Segment Size. This field defines the number of TRBs supported by the ring segment, Valid - /// values for this field are 16 to 4096, i.e. an Event Ring segment shall contain at least 16 entries - pub ring_segment_size: u64, -} - -impl EventRingSegmentTableEntry { - pub fn update_from_trb_ring(&mut self, trb_ring: &TrbRingSegment) { - mammoth::debug!("RSTE: {:0x}", self as *const _ as usize); - self.ring_segment_base_address = trb_ring.physical_address() as u64; - assert!(self.ring_segment_base_address.is_multiple_of(64)); - unsafe { - core::ptr::write_volatile( - &mut self.ring_segment_size as *mut u64, - trb_ring.len() as u64, - ) - }; - assert!(self.ring_segment_size >= 16); - assert!(self.ring_segment_size <= 4096); - } -} - -pub struct EventRingSegmentTable(PhysicalBox<[EventRingSegmentTableEntry]>); - -impl EventRingSegmentTable { - pub fn new(size: usize) -> Self { - Self(PhysicalBox::default_with_count( - EventRingSegmentTableEntry::default(), - size, - )) - } - - pub fn physical_address(&self) -> usize { - self.0.physical_address() - } - - pub fn len(&self) -> usize { - self.0.len() - } -} - -impl Index for EventRingSegmentTable { - type Output = EventRingSegmentTableEntry; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut for EventRingSegmentTable { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.0[index] - } -} diff --git a/rust/sys/voyageurs/src/xhci/data_structures/event_trb.rs b/rust/sys/voyageurs/src/xhci/data_structures/event_trb.rs deleted file mode 100644 index c37e22c..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/event_trb.rs +++ /dev/null @@ -1,155 +0,0 @@ -use bitfield_struct::{bitenum, bitfield}; - -use crate::xhci::data_structures::{TransferRequestBlock, TrbType}; - -#[bitenum] -#[repr(u8)] -#[derive(Debug, Eq, PartialEq)] -pub enum CommandCompletionCode { - #[fallback] - #[allow(dead_code)] - Invalid = 0, - Success = 1, - DataBufferError = 2, - BabbleDetectedError = 3, - UsbTransactionError = 4, - TrbError = 5, - StallError = 6, - ResourceError = 7, - BandwidthError = 8, - NoSlotsAvailable = 9, - InvalidStreamType = 10, - SlotNotEnabled = 11, - EndpointNotEnabled = 12, - ShortPacket = 13, - RingUnderrun = 14, - RingOverrun = 15, - VFEventRingFull = 16, - ParameterError = 17, -} - -#[bitfield(u128)] -pub struct TransferEvent { - pub transfer_trb_pointer: u64, - - #[bits(24)] - pub trb_transfer_lenght: u32, - - /// Completion Code. This field encodes the completion status of the command that generated the - /// event. Refer to the respective command definition for a list of the possible Completion Codes - /// associated with the command. Refer to section 6.4.5 for an enumerated list of possible error - /// conditions. - #[bits(8)] - pub completion_code: CommandCompletionCode, - #[bits(10)] - __: u16, - /// TRB Type. This field identifies the type of the TRB. Refer to Table 6-91 for the definition of the - /// Command Completion Event TRB type ID - #[bits(6, default=TrbType::TransferEvent)] - pub trb_type: TrbType, - - #[bits(5)] - pub endpoint_id: u8, - #[bits(3)] - __: u8, - - pub slot_id: u8, -} - -#[bitfield(u128)] -pub struct CommandCompletionEvent { - /// Command TRB Pointer Hi and Lo. This field represents the high order bits of the 64-bit address - /// of the Command TRB that generated this event. Note that this field is not valid for some - /// Completion Code values. Refer to Table 6-90 for specific cases. - /// - /// The memory structure referenced by this physical memory pointer shall be aligned on a 16-byte - /// address boundary. - pub command_trb_pointer: u64, - /// Command Completion Parameter. This field may optionally be set by a command. Refer to - /// section 4.6.6.1 for specific usage. If a command does not utilize this field it shall be treated as - /// RsvdZ. - #[bits(24)] - pub command_completion_parameter: u64, - /// Completion Code. This field encodes the completion status of the command that generated the - /// event. Refer to the respective command definition for a list of the possible Completion Codes - /// associated with the command. Refer to section 6.4.5 for an enumerated list of possible error - /// conditions. - #[bits(8)] - pub completion_code: CommandCompletionCode, - /// Cycle bit (C). This bit is used to mark the Dequeue Pointer of an Event Ring - pub cycle_bit: bool, - #[bits(9)] - __: u16, - /// TRB Type. This field identifies the type of the TRB. Refer to Table 6-91 for the definition of the - /// Command Completion Event TRB type ID - #[bits(6, default=TrbType::CommandCompletionEvent)] - pub trb_type: TrbType, - /// VF ID. The ID of the Virtual Function that generated the event. Note that this field is valid only if - /// Virtual Functions are enabled. If they are not enabled this field shall be cleared to ‘0’. - pub vf_id: u8, - /// Slot ID. The Slot ID field shall be updated by the xHC to reflect the slot associated with the - /// command that generated the event, with the following exceptions: - /// - /// - The Slot ID shall be cleared to ‘0’ for No Op, Set Latency Tolerance Value, Get Port Bandwidth, - /// and Force Event Commands. - /// - /// - The Slot ID shall be set to the ID of the newly allocated Device Slot for the Enable Slot - /// Command. - /// - /// - The value of Slot ID shall be vendor defined when generated by a vendor defined command. - /// - /// This value is used as an index in the Device Context Base Address Array to select the Device - /// Context of the source device. If this Event is due to a Host Controller Command, then this field - /// shall be cleared to ‘0’. - pub slot_id: u8, -} - -#[bitfield(u128)] -pub struct PortStatusChangeEvent { - #[bits(24)] - __: u32, - pub port_id: u8, - __: u32, - #[bits(24)] - __: u32, - #[bits(8)] - pub completion_code: CommandCompletionCode, - #[bits(10)] - __: u16, - #[bits(6, default=TrbType::PortStatusChangeEvent)] - trb_type: TrbType, - __: u16, -} - -pub enum EventTrb { - Transfer(TransferEvent), - CommandCompletion(CommandCompletionEvent), - PortStatusChange(PortStatusChangeEvent), - BandwidthRequest(TransferRequestBlock), - Doorbell(TransferRequestBlock), - HostController(TransferRequestBlock), - DeviceNotification(TransferRequestBlock), - MFINDEXWrap(TransferRequestBlock), -} - -impl From for EventTrb { - fn from(value: TransferRequestBlock) -> Self { - match value.trb_type() { - TrbType::TransferEvent => { - EventTrb::Transfer(TransferEvent::from_bits(value.into_bits())) - } - TrbType::CommandCompletionEvent => { - EventTrb::CommandCompletion(CommandCompletionEvent::from_bits(value.into_bits())) - } - TrbType::PortStatusChangeEvent => { - EventTrb::PortStatusChange(PortStatusChangeEvent::from_bits(value.into_bits())) - } - TrbType::BandwidthRequestEvent => EventTrb::BandwidthRequest(value), - TrbType::DoorbellEvent => EventTrb::Doorbell(value), - TrbType::HostControllerEvent => EventTrb::HostController(value), - TrbType::DeviceNotificationEvent => EventTrb::DeviceNotification(value), - TrbType::MFINDEXWrapEvent => EventTrb::MFINDEXWrap(value), - t => panic!("Unknown trb type on event ring: {:?}", t), - } - } -} diff --git a/rust/sys/voyageurs/src/xhci/data_structures/input_context.rs b/rust/sys/voyageurs/src/xhci/data_structures/input_context.rs deleted file mode 100644 index 2e9bbb3..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/input_context.rs +++ /dev/null @@ -1,33 +0,0 @@ -use bitfield_struct::bitfield; - -use crate::xhci::data_structures::{EndpointContext, SlotContext}; - -#[bitfield(u32)] -pub struct InputControlContextSettings { - pub configuration_value: u8, - pub interface_number: u8, - pub alternate_setting: u8, - __: u8, -} - -#[repr(C)] -#[derive(Default)] -pub struct InputControlContext { - pub drop_context_flags: u32, - pub add_context_flags: u32, - __: [u32; 5], - pub settings: InputControlContextSettings, -} - -const _: () = assert!(size_of::() == 0x20); - -#[repr(C)] -#[derive(Default)] -pub struct InputContext { - pub input_control_context: InputControlContext, - pub slot_context: SlotContext, - pub endpoint_context_0: EndpointContext, - pub endpoint_contexts: [EndpointContext; 30], -} - -const _: () = assert!(size_of::() == 0x420); diff --git a/rust/sys/voyageurs/src/xhci/data_structures/mod.rs b/rust/sys/voyageurs/src/xhci/data_structures/mod.rs deleted file mode 100644 index 01fa766..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -mod command_trb; -mod device_context; -mod endpoint_context; -mod event_ring_segment_table; -mod event_trb; -mod input_context; -mod slot_context; -mod transfer_trb; -mod trb; -mod trb_ring_segment; - -pub use command_trb::*; -pub use device_context::*; -pub use endpoint_context::*; -pub use event_ring_segment_table::*; -pub use event_trb::*; -pub use input_context::*; -pub use slot_context::*; -pub use transfer_trb::*; -pub use trb::*; -pub use trb_ring_segment::*; diff --git a/rust/sys/voyageurs/src/xhci/data_structures/slot_context.rs b/rust/sys/voyageurs/src/xhci/data_structures/slot_context.rs deleted file mode 100644 index d9f953c..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/slot_context.rs +++ /dev/null @@ -1,134 +0,0 @@ -use bitfield_struct::bitfield; - -#[bitfield(u128)] -pub struct SlotContextFields { - /// Route String. This field is used by hubs to route packets to the correct downstream port. The - /// format of the Route String is defined in section 8.9 the USB3 specification. - /// As Input, this field shall be set for all USB devices, irrespective of their speed, to indicate their - /// location in the USB topology. - #[bits(20)] - pub route_string: u32, - /// Speed. This field is deprecated in this version of the specification and shall be Reserved. - /// This field indicates the speed of the device. Refer to the PORTSC Port Speed field in Table 5-27 - /// for the definition of the valid values - #[bits(4)] - pub speed: u8, - __: bool, - /// Multi-TT (MTT). This flag is set to '1' by software if this is a High-speed hub that supports - /// Multiple TTs and the Multiple TT Interface has been enabled by software, or if this is a Low- - /// /Full-speed device or Full-speed hub and connected to the xHC through a parent108 High-speed - /// hub that supports Multiple TTs and the Multiple TT Interface of the parent hub has been - /// enabled by software, or ‘0’ if not. - pub multi_tt: bool, - /// Hub. This flag is set to '1' by software if this device is a USB hub, or '0' if it is a USB function - pub hub: bool, - /// Context Entries. This field identifies the index of the last valid Endpoint Context within this - /// Device Context structure. The value of ‘0’ is Reserved and is not a valid entry for this field. Valid - /// entries for this field shall be in the range of 1-31. This field indicates the size of the Device - /// Context structure. For example, ((Context Entries+1) * 32 bytes) = Total bytes for this structure. - /// - /// Note, Output Context Entries values are written by the xHC, and Input Context Entries values are - /// written by software. - #[bits(5)] - pub context_entries: u8, - /// Max Exit Latency. The Maximum Exit Latency is in microseconds, and indicates the worst case - /// time it takes to wake up all the links in the path to the device, given the current USB link level - /// power management settings. - /// - /// Refer to section 4.23.5.2 for more information on the use of this field. - pub max_exit_latency: u16, - /// Root Hub Port Number. This field identifies the Root Hub Port Number used to access the USB - /// device. Refer to section 4.19.7 for port numbering information. - /// - /// Note: Ports are numbered from 1 to MaxPorts - pub root_hub_port_number: u8, - /// Number of Ports. If this device is a hub (Hub = ‘1’), then this field is set by software to identify - /// the number of downstream facing ports supported by the hub. Refer to the bNbrPorts field - /// description in the Hub Descriptor (Table 11-13) of the USB2 spec. If this device is not a hub (Hub - /// = ‘0’), then this field shall be ‘0 - pub number_of_ports: u8, - /// Parent Hub Slot ID. If this device is Low-/Full-speed and connected through a High-speed hub, - /// then this field shall contain the Slot ID of the parent High-speed hub109. - /// - /// For SS and SSP bus instance, if this device is connected through a higher rank hub110 then this - /// field shall contain the Slot ID of the parent hub. For example, a Gen1 x1 connected behind a - /// Gen1 x2 hub, or Gen1 x2 device connected behind Gen2 x2 hub. - /// - /// This field shall be ‘0’ if any of the following are true: - /// Device is attached to a Root Hub port - /// Device is a High-Speed device - /// Device is the highest rank SS/SSP device supported by xHCI - pub parent_hub_slot_id: u8, - /// Parent Port Number. If this device is Low-/Full-speed and connected through a High-speed - /// hub, then this field shall contain the number of the downstream facing port of the parent High- - /// speed hub109. - /// For SS and SSP bus instance, if this device is connected through a higher rank hub110 then this - /// field shall contain the number of the downstream facing port of the parent hub. For example, a - /// Gen1 x1 connected behind a Gen1 x2 hub, or Gen1 x2 device connected behind Gen2 x2 hub. - /// This field shall be ‘0’ if any of the following are true: - /// Device is attached to a Root Hub port - /// Device is a High-Speed device - /// Device is the highest rank SS/SSP device supported by xH - pub parent_port_number: u8, - /// TT Think Time (TTT). If this is a High-speed hub (Hub = ‘1’ and Speed = High-Speed), then this - /// field shall be set by software to identify the time the TT of the hub requires to proceed to the - /// next full-/low-speed transaction. - /// Value Think Time - /// 0 TT requires at most 8 FS bit times of inter-transaction gap on a full-/low-speed - /// downstream bus. - /// 1 TT requires at most 16 FS bit times. - /// 2 TT requires at most 24 FS bit times. - /// 3 TT requires at most 32 FS bit times. - /// Refer to the TT Think Time sub-field of the wHubCharacteristics field description in the Hub - /// Descriptor (Table 11-13) and section 11.18.2 of the USB2 spec for more information on TT - /// Think Time. If this device is not a High-speed hub (Hub = ‘0’ or Speed != High-speed), then this - /// field shall be ‘0’. - #[bits(2)] - pub tt_think_time: u8, - #[bits(4)] - __: u8, - /// Interrupter Target. This field defines the index of the Interrupter that will receive Bandwidth - /// Request Events and Device Notification Events generated by this slot, or when a Ring Underrun - /// or Ring Overrun condition is reported (refer to section 4.10.3.1). Valid values are between 0 and - /// MaxIntrs-1 - #[bits(10)] - pub interrupter_target: u16, - /// USB Device Address. This field identifies the address assigned to the USB device by the xHC, - /// and is set upon the successful completion of a Set Address Command. Refer to the USB2 spec - /// for a more detailed description. - /// - /// As Output, this field is invalid if the Slot State = Disabled or Default. - /// As Input, software shall initialize the field to ‘0’. - pub usb_device_address: u8, - - #[bits(19)] - __: u32, - - /// Slot State. This field is updated by the xHC when a Device Slot transitions from one state to - /// another. - /// Value Slot State - /// 0 Disabled/Enabled - /// 1 Default - /// 2 Addressed - /// 3 Configured - /// 31-4 Reserved - /// - /// Slot States are defined in section 4.5.3. - /// - /// As Output, since software initializes all fields of the Device Context data structure to ‘0’, this field - /// shall initially indicate the Disabled state. - /// - /// As Input, software shall initialize the field to ‘0’. - /// Refer to section 4.5.3 for more information on Slot State. - #[bits(5)] - pub slot_state: u8, -} - -#[repr(C)] -#[derive(Default)] -pub struct SlotContext { - pub fields: SlotContextFields, - __: u128, -} - -const _: () = assert!(size_of::() == 0x20); diff --git a/rust/sys/voyageurs/src/xhci/data_structures/transfer_trb.rs b/rust/sys/voyageurs/src/xhci/data_structures/transfer_trb.rs deleted file mode 100644 index 3d8055c..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/transfer_trb.rs +++ /dev/null @@ -1,304 +0,0 @@ -use bitfield_struct::{bitenum, bitfield}; - -use crate::xhci::data_structures::{TransferRequestBlock, TrbType}; - -#[bitfield(u128)] -pub struct NormalTransfer { - /// Data Buffer Pointer Hi and Lo. These fields represent the 64-bit address of the TRB data area - /// for this transaction or 8 bytes of immediate data. The Immediate Data (IDT) control flag selects - /// this option for each Normal TRB. - /// - /// The memory structure referenced by this physical memory pointer is allowed to begin on a byte - /// address boundary. However, user may find other alignments, such as 64-byte or 128-byte - /// alignments, to be more efficient and provide better performance - data_buffer_pointer: u64, - /// TRB Transfer Length. For an OUT, this field defines the number of data bytes the xHC shall - /// send during the execution of this TRB. If the value of this field is ‘0’ when the xHC fetches this - /// TRB, the xHC shall execute a zero-length transaction. - /// - /// Note: If a zero-length transfer is specified, the Data Buffer Pointer field is ignored by the xHC, - /// irrespective of the state of the IDT flag. Refer to section 4.9.1 for more information on zero- - /// length Transfer TRB handling. - /// - /// For an IN, the value of the field identifies the size of the data buffer referenced by the Data - /// Buffer Pointer, i.e. the number of bytes the host expects the endpoint to deliver. - /// - /// Valid values are 0 to 64K. - #[bits(17)] - trb_transfer_length: u32, - /// TD Size. This field provides an indicator of the number of packets remaining in the TD. Refer to - /// section 4.10.2.4 for how this value is calculated - #[bits(5)] - td_size: u8, - /// Interrupter Target. This field defines the index of the Interrupter that will receive events - /// generated by this TRB. Valid values are between 0 and MaxIntrs-1. - #[bits(10)] - interrupter_target: u16, - /// Cycle bit (C). This bit is used to mark the Enqueue Pointer of the Transfer ring. - cycle: bool, - /// Evaluate Next TRB (ENT). If this flag is ‘1’ the xHC shall fetch and evaluate the next TRB before - /// saving the endpoint state. Refer to section 4.12.3 for more information - evaluate_next: bool, - /// Interrupt-on Short Packet (ISP). If this flag is ‘1’ and a Short Packet is encountered for this TRB - /// (i.e., less than the amount specified in TRB Transfer Length), then a Transfer Event TRB shall be - /// generated with its Completion Code set to Short Packet. The TRB Transfer Length field in the - /// Transfer Event TRB shall reflect the residual number of bytes not transferred into the associated - /// data buffer. In either case, when a Short Packet is encountered, the TRB shall be retired without - /// error and the xHC shall advance to the next Transfer Descriptor (TD). - /// - /// Note that if the ISP and IOC flags are both ‘1’ and a Short Packet is detected, then only one - /// Transfer Event TRB shall be queued to the Event Ring. Also refer to section 4.10.1.1 - interrupt_on_short_packet: bool, - /// No Snoop (NS). When set to ‘1’, the xHC is permitted to set the No Snoop bit in the Requester - /// Attributes of the PCIe transactions it initiates if the PCIe configuration Enable No Snoop flag is - /// also set. When cleared to ‘0’, the xHC is not permitted to set PCIe packet No Snoop Requester - /// Attribute. Refer to section 4.18.1 for more information. - /// - /// NOTE: If software sets this bit, then it is responsible for maintaining cache consistency - no_snoop: bool, - /// Chain bit (CH). Set to ‘1’ by software to associate this TRB with the next TRB on the Ring. A - /// Transfer Descriptor (TD) is defined as one or more TRBs. The Chain bit is used to identify the - /// TRBs that comprise a TD. The Chain bit is always ‘0’ in the last TRB of a TD - chain: bool, - /// Interrupt On Completion (IOC). If this bit is set to ‘1’, it specifies that when this TRB completes, - /// the Host Controller shall notify the system of the completion by placing an Transfer Event TRB - /// on the Event ring and asserting an interrupt to the host at the next interrupt threshold. Note that - /// the interrupt assertion may be blocked for the Transfer Event by BEI. Refer to sections 4.10.4 - /// and 4.17.5. - interrupt_on_completion: bool, - /// Immediate Data (IDT). If this bit is set to ‘1’, it specifies that the Data Buffer Pointer field of this - /// TRB contains data, not a pointer, and the Length field shall contain a value between ‘0’ and ‘8’ to - /// indicate the number of valid bytes from offset 0 in the TRB that should be used as data. - /// - /// Note: If the IDT flag is set in one Transfer TRB of a TD, then it shall be the only Transfer TRB of - /// the TD. An Event Data TRB may be included in the TD. Failure to follow this rule may result in - /// undefined xHC operation. - /// - /// Note: IDT shall not be set (‘1’) for TRBs on endpoints that define a Max Packet Size < 8 bytes, or - /// on IN endpoints. - immediate_data: bool, - __: bool, - __: bool, - /// Block Event Interrupt (BEI). If this bit is set to ‘1’ and IOC = ‘1’, then the Transfer Event - /// generated by IOC shall not assert an interrupt to the host at the next interrupt threshold. Refer - /// to section 4.17.5. - block_event_interrupt: bool, - /// TRB Type. This shall be set to Normal TRB type. Refer to Table 6-91 for the definition of the - /// valid Transfer TRB type IDs - #[bits(6, default=TrbType::Normal)] - trb_type: TrbType, - __: u16, -} - -impl From for TransferTrb { - fn from(value: NormalTransfer) -> Self { - TransferTrb(TransferRequestBlock::from_bits(value.into_bits())) - } -} - -#[bitenum] -#[repr(u8)] -#[derive(Debug)] -pub enum TransferType { - NoDataStage = 0, - #[fallback] - Reserved = 1, - OutDataStage = 2, - InDataStage = 3, -} - -#[bitfield(u128)] -pub struct SetupStage { - /// These 5 fields are specified in Table 9-3. Format of Setup Data. - pub request_type: u8, - pub request: u8, - pub value: u16, - pub index: u16, - pub length: u16, - /// TRB Transfer Length. Always 8. - #[bits(17, default=8, access=RO)] - trb_transfer_length: u32, - #[bits(5)] - __: u8, - /// Interrupter Target. This field defines the index of the Interrupter that will receive events - /// generated by this TRB. Valid values are between 0 and MaxIntrs-1. - #[bits(10)] - pub interrupter_target: u16, - /// Cycle bit (C). This bit is used to mark the Enqueue point of a Transfer ring. - cycle: bool, - #[bits(4)] - __: u8, - /// Interrupt On Completion (IOC). If this bit is set to ‘1’, it specifies that when this TRB completes, - /// the Host Controller shall notify the system of the completion by placing an Event TRB on the - /// Event ring and sending an interrupt at the next interrupt threshold. Refer to section 4.10.4 - #[bits(default=false, access=RO)] - interrupt_on_completion: bool, - /// Immediate Data (IDT). This bit shall be set to ‘1’ in a Setup Stage TRB. It specifies that the - /// Parameter component of this TRB contains Setup Data. - #[bits(default=true, access=RO)] - immediate_data: bool, - #[bits(3)] - __: u8, - /// TRB Type. This shall be set to Normal TRB type. Refer to Table 6-91 for the definition of the - /// valid Transfer TRB type IDs - #[bits(6, default=TrbType::SetupStage, access=RO)] - trb_type: TrbType, - #[bits(2)] - pub transfer_type: TransferType, - #[bits(14)] - __: u16, -} - -impl From for TransferTrb { - fn from(value: SetupStage) -> Self { - TransferTrb(TransferRequestBlock::from_bits(value.into_bits())) - } -} - -#[bitfield(u128)] -pub struct DataStage { - /// Data Buffer Pointer Hi and Lo. These fields represent the 64-bit address of the TRB data area - /// for this transaction. - /// - /// The memory structure referenced by this physical memory pointer is allowed to begin on a byte - /// address boundary. However, user may find other alignments, such as 64-byte or 128-byte - /// alignments, to be more efficient and provide better performance - pub data_buffer_pointer: u64, - /// TRB Transfer Length. For an OUT, this field is the number of data bytes the xHC will send - /// during the execution of this TRB. - /// - /// For an IN, the initial value of the field identifies the size of the data buffer referenced by the Data - /// Buffer Pointer, i.e. the number of bytes the host expects the endpoint to deliver. - /// - /// Valid values are 1 to 64K. - #[bits(17)] - pub trb_transfer_length: u32, - /// TD Size. This field provides an indicator of the number of packets remaining in the TD. Refer to - /// section 4.10.2.4 for how this value is calculated - #[bits(5)] - pub td_size: u8, - /// Interrupter Target. This field defines the index of the Interrupter that will receive events - /// generated by this TRB. Valid values are between 0 and MaxIntrs-1. - #[bits(10)] - pub interrupter_target: u16, - /// Cycle bit (C). This bit is used to mark the Enqueue Pointer of the Transfer ring. - cycle: bool, - /// Evaluate Next TRB (ENT). If this flag is ‘1’ the xHC shall fetch and evaluate the next TRB before - /// saving the endpoint state. Refer to section 4.12.3 for more information - pub evaluate_next: bool, - /// Interrupt-on Short Packet (ISP). If this flag is ‘1’ and a Short Packet is encountered for this TRB - /// (i.e., less than the amount specified in TRB Transfer Length), then a Transfer Event TRB shall be - /// generated with its Completion Code set to Short Packet. The TRB Transfer Length field in the - /// Transfer Event TRB shall reflect the residual number of bytes not transferred into the associated - /// data buffer. In either case, when a Short Packet is encountered, the TRB shall be retired without - /// error and the xHC shall advance to the next Transfer Descriptor (TD). - /// - /// Note that if the ISP and IOC flags are both ‘1’ and a Short Packet is detected, then only one - /// Transfer Event TRB shall be queued to the Event Ring. Also refer to section 4.10.1.1 - interrupt_on_short_packet: bool, - /// No Snoop (NS). When set to ‘1’, the xHC is permitted to set the No Snoop bit in the Requester - /// Attributes of the PCIe transactions it initiates if the PCIe configuration Enable No Snoop flag is - /// also set. When cleared to ‘0’, the xHC is not permitted to set PCIe packet No Snoop Requester - /// Attribute. Refer to section 4.18.1 for more information. - /// - /// NOTE: If software sets this bit, then it is responsible for maintaining cache consistency - no_snoop: bool, - /// Chain bit (CH). Set to ‘1’ by software to associate this TRB with the next TRB on the Ring. A - /// Transfer Descriptor (TD) is defined as one or more TRBs. The Chain bit is used to identify the - /// TRBs that comprise a TD. The Chain bit is always ‘0’ in the last TRB of a TD - chain: bool, - /// Interrupt On Completion (IOC). If this bit is set to ‘1’, it specifies that when this TRB completes, - /// the Host Controller shall notify the system of the completion by placing an Transfer Event TRB - /// on the Event ring and asserting an interrupt to the host at the next interrupt threshold. Note that - /// the interrupt assertion may be blocked for the Transfer Event by BEI. Refer to sections 4.10.4 - /// and 4.17.5. - #[bits(default=false, access=RO)] - interrupt_on_completion: bool, - /// Immediate Data (IDT). If this bit is set to ‘1’, it specifies that the Data Buffer Pointer field of this - /// TRB contains data, not a pointer. If IDT = ‘1’, the Length field shall contain a value between 1 and - /// 8 to indicate the number of valid bytes from offset 0 in the TRB that should be used as data. - /// - /// Note: If the IDT flag is set in one Data Stage TRB of a TD, then it shall be the only Transfer TRB of - /// the TD. An Event Data TRB may also be included in the TD. Failure to follow this rule may result - /// in undefined xHC operation. - pub immediate_data: bool, - __: bool, - __: bool, - /// Block Event Interrupt (BEI). If this bit is set to ‘1’ and IOC = ‘1’, then the Transfer Event - /// generated by IOC shall not assert an interrupt to the host at the next interrupt threshold. Refer - /// to section 4.17.5. - block_event_interrupt: bool, - /// TRB Type. This shall be set to Normal TRB type. Refer to Table 6-91 for the definition of the - /// valid Transfer TRB type IDs - #[bits(6, default=TrbType::DataStage, access=RO)] - trb_type: TrbType, - /// Direction (DIR). This bit indicates the direction of the data transfer as defined in the Data State - /// TRB Direction column of Table 7. If cleared to ‘0’, the data stage transfer direction is OUT (Write - /// Data). If set to ‘1’, the data stage transfer direction is IN (Read Data). Refer to section 4.11.2.2 for - /// more information on the use of DIR. - pub direction: bool, - #[bits(15)] - __: u16, -} - -impl From for TransferTrb { - fn from(value: DataStage) -> Self { - TransferTrb(TransferRequestBlock::from_bits(value.into_bits())) - } -} - -#[bitfield(u128)] -pub struct StatusStage { - __: u64, - #[bits(22)] - __: u32, - /// Interrupter Target. This field defines the index of the Interrupter that will receive events - /// generated by this TRB. Valid values are between 0 and MaxIntrs-1. - #[bits(10)] - pub interrupter_target: u16, - /// Cycle bit (C). This bit is used to mark the Enqueue Pointer of the Transfer ring. - cycle: bool, - /// Evaluate Next TRB (ENT). If this flag is ‘1’ the xHC shall fetch and evaluate the next TRB before - /// saving the endpoint state. Refer to section 4.12.3 for more information - evaluate_next: bool, - #[bits(2)] - __: u8, - /// Chain bit (CH). Set to ‘1’ by software to associate this TRB with the next TRB on the Ring. A - /// Transfer Descriptor (TD) is defined as one or more TRBs. The Chain bit is used to identify the - /// TRBs that comprise a TD. The Chain bit is always ‘0’ in the last TRB of a TD - chain: bool, - /// Interrupt On Completion (IOC). If this bit is set to ‘1’, it specifies that when this TRB completes, - /// the Host Controller shall notify the system of the completion by placing an Transfer Event TRB - /// on the Event ring and asserting an interrupt to the host at the next interrupt threshold. Note that - /// the interrupt assertion may be blocked for the Transfer Event by BEI. Refer to sections 4.10.4 - /// and 4.17.5. - pub interrupt_on_completion: bool, - #[bits(4)] - __: u8, - /// TRB Type. This shall be set to Normal TRB type. Refer to Table 6-91 for the definition of the - /// valid Transfer TRB type IDs - #[bits(6, default=TrbType::StatusStage, access=RO)] - trb_type: TrbType, - /// Direction (DIR). This bit indicates the direction of the data transfer as defined in the Status State - /// TRB Direction column of Table 7. If cleared to ‘0’, the status stage transfer direction is OUT - /// (Host-to-device). If set to ‘1’, the status stage transfer direction is IN (Device-to-host). Refer to - /// section 4.11.2.2 for more information on the use of DIR. - pub direction: bool, - #[bits(15)] - __: u16, -} - -impl From for TransferTrb { - fn from(value: StatusStage) -> Self { - TransferTrb(TransferRequestBlock::from_bits(value.into_bits())) - } -} - -#[derive(Clone)] -pub struct TransferTrb(TransferRequestBlock); - -impl From for TransferRequestBlock { - fn from(value: TransferTrb) -> Self { - value.0 - } -} diff --git a/rust/sys/voyageurs/src/xhci/data_structures/trb.rs b/rust/sys/voyageurs/src/xhci/data_structures/trb.rs deleted file mode 100644 index 7cb0338..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/trb.rs +++ /dev/null @@ -1,120 +0,0 @@ -use bitfield_struct::{bitenum, bitfield}; - -#[bitenum] -#[repr(u8)] -#[derive(Debug, Eq, PartialEq)] -pub enum TrbType { - #[fallback] - Reserved = 0, - Normal = 1, - SetupStage = 2, - DataStage = 3, - StatusStage = 4, - Isoch = 5, - Link = 6, - EventData = 7, - NoOp = 8, - EnableSlotCommand = 9, - DisableSlotCommand = 10, - AddressDeviceCommand = 11, - ConfigureEndpointCommand = 12, - EvaluateContextCommand = 13, - ResetEndpointCommand = 14, - StopEndpointCommand = 15, - SetTRDequeuePointerCommand = 16, - ResetDeviceCommand = 17, - ForceEventCommand = 18, - NegotiateBandwidthCommand = 19, - SetLatencyToleranceValueCommand = 20, - GetPortBandwidthCommand = 21, - ForceHeaderCommand = 22, - NoOpCommand = 23, - GetExtendedPropertyCommand = 24, - SetExtendedPropertyCommand = 25, - TransferEvent = 32, - CommandCompletionEvent = 33, - PortStatusChangeEvent = 34, - BandwidthRequestEvent = 35, - DoorbellEvent = 36, - HostControllerEvent = 37, - DeviceNotificationEvent = 38, - MFINDEXWrapEvent = 39, -} - -#[bitfield(u128)] -pub struct TransferRequestBlock { - pub parameter: u64, - pub status: u32, - pub cycle: bool, - evaluate_next: bool, - flag_2: bool, - flag_3: bool, - flag_4: bool, - flag_5: bool, - flag_6: bool, - flag_7: bool, - flag_8: bool, - flag_9: bool, - #[bits(6)] - pub trb_type: TrbType, - control: u16, -} - -impl TransferRequestBlock {} - -pub trait TypedTrb -where - Self: Into + From + Copy, -{ - fn from_trb(trb: TransferRequestBlock) -> Self { - trb.into_bits().into() - } - - fn to_trb(self) -> TransferRequestBlock { - Into::::into(self).into() - } -} - -#[bitfield(u128)] -pub struct TrbLink { - /// Ring Segment Pointer Hi and Lo. These fields represent the high order bits of the 64-bit base - /// address of the next Ring Segment. - /// The memory structure referenced by this physical memory pointer shall begin on a 16-byte - /// address boundary. - pub ring_segment_pointer: u64, - #[bits(22)] - __: u32, - /// Interrupter Target. This field defines the index of the Interrupter that will receive Transfer - /// Events generated by this TRB. Valid values are between 0 and MaxIntrs-1. - /// This field is ignored by the xHC on Command Rings. - #[bits(10)] - pub interrupter_target: u16, - /// Cycle bit (C). This bit is used to mark the Enqueue Pointer location of a Transfer or Command - /// Ring. - pub cycle: bool, - /// Toggle Cycle (TC). When set to ‘1’, the xHC shall toggle its interpretation of the Cycle bit. When - /// cleared to ‘0’, the xHC shall continue to the next segment using its current interpretation of the - /// Cycle bit. - pub toggle_cycle: bool, - __: bool, - __: bool, - /// Chain bit (CH). Set to ‘1’ by software to associate this TRB with the next TRB on the Ring. A - /// Transfer Descriptor (TD) is defined as one or more TRBs. The Chain bit is used to identify the - /// TRBs that comprise a TD. Refer to section 4.11.7 for more information on Link TRB placement - /// within a TD. On a Command Ring this bit is ignored by the xHC. - #[bits(default = true)] - chain: bool, - /// Interrupt On Completion (IOC). If this bit is set to ‘1’, it specifies that when this TRB completes, - /// the Host Controller shall notify the system of the completion by placing an Event TRB on the - /// Event ring and sending an interrupt at the next interrupt threshold. - pub interrupt_on_completion: bool, - #[bits(4)] - __: u8, - /// TRB Type. This field is set to Link TRB type. Refer to Table 6-91 for the definition of the Type - /// TRB IDs. - #[bits(6, default = TrbType::Link)] - trb_type: TrbType, - __: u16, -} - -impl TypedTrb for TrbLink {} diff --git a/rust/sys/voyageurs/src/xhci/data_structures/trb_ring_segment.rs b/rust/sys/voyageurs/src/xhci/data_structures/trb_ring_segment.rs deleted file mode 100644 index 6ac6093..0000000 --- a/rust/sys/voyageurs/src/xhci/data_structures/trb_ring_segment.rs +++ /dev/null @@ -1,48 +0,0 @@ -use core::{ - ops::{Index, IndexMut}, - slice::SliceIndex, -}; - -use mammoth::physical_box::PhysicalBox; - -use crate::xhci::data_structures::TransferRequestBlock; - -#[repr(transparent)] -pub struct TrbRingSegment(PhysicalBox<[TransferRequestBlock]>); - -impl TrbRingSegment { - pub fn new(size: usize) -> Self { - Self(PhysicalBox::default_with_count( - TransferRequestBlock::default(), - size, - )) - } - - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn physical_address(&self) -> usize { - self.0.physical_address() - } -} - -impl Index for TrbRingSegment -where - I: SliceIndex<[TransferRequestBlock]>, -{ - type Output = I::Output; - - fn index(&self, index: I) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut for TrbRingSegment -where - I: SliceIndex<[TransferRequestBlock]>, -{ - fn index_mut(&mut self, index: I) -> &mut Self::Output { - &mut self.0[index] - } -} diff --git a/rust/sys/voyageurs/src/xhci/device_context_base_array.rs b/rust/sys/voyageurs/src/xhci/device_context_base_array.rs deleted file mode 100644 index 50ed814..0000000 --- a/rust/sys/voyageurs/src/xhci/device_context_base_array.rs +++ /dev/null @@ -1,240 +0,0 @@ -use alloc::boxed::Box; -use mammoth::{mem::MemoryRegion, physical_box::PhysicalBox}; - -use crate::xhci::{ - data_structures::{ - DataStage, DeviceContext, EndpointContextFields, EndpointState, EndpointType, InputContext, - InputControlContextSettings, SetupStage, StatusStage, TRDequeuePointer, TransferEvent, - TransferTrb, TransferType, - }, - registers::DoorbellPointer, - trb_ring::{TrbFuture, TrbRing}, - usb::{Configuration, DeviceDescriptor}, -}; - -struct DeviceContextBaseArray(PhysicalBox<[u64]>); - -impl DeviceContextBaseArray { - pub fn new(max_slots: u8) -> Self { - Self(PhysicalBox::default_with_count(0, max_slots as usize + 1)) - } -} - -pub struct DeviceSlot { - device_context: PhysicalBox, - input_context: PhysicalBox, - endpoint_0_transfer_ring: TrbRing, - doorbell: DoorbellPointer, -} - -impl DeviceSlot { - fn new(doorbell: DoorbellPointer) -> Self { - Self { - device_context: PhysicalBox::new(DeviceContext::default()), - input_context: PhysicalBox::new(InputContext::default()), - endpoint_0_transfer_ring: TrbRing::new(), - doorbell, - } - } - pub fn send_control_command(&mut self, trbs: &[TransferTrb]) -> TrbFuture { - let td_len = trbs.len(); - - for trb in trbs.iter().take(td_len - 1) { - self.endpoint_0_transfer_ring - .enqueue_trb(trb.clone().into()); - } - let fut = self - .endpoint_0_transfer_ring - .enqueue_trb_expect_interrupt(trbs[td_len - 1].clone().into()); - self.doorbell.ring(1); - fut - } - - pub fn read_device_descriptor( - &mut self, - ) -> (TrbFuture, PhysicalBox) { - let setup_stage = SetupStage::new() - .with_request_type(0b10000000) - .with_request(6) - .with_value(0x1 << 8) - .with_length(size_of::() as u16) - .with_index(0) - .with_transfer_type(TransferType::InDataStage); - - let descriptor = PhysicalBox::new(DeviceDescriptor::default()); - let data_stage = DataStage::new() - .with_data_buffer_pointer(descriptor.physical_address() as u64) - .with_trb_transfer_length(size_of::() as u32) - .with_direction(true); - let status_stage = StatusStage::new() - .with_interrupter_target(0) - .with_interrupt_on_completion(true) - .with_direction(false); - - let fut = self.send_control_command(&[ - setup_stage.into(), - data_stage.into(), - status_stage.into(), - ]); - - (fut, descriptor) - } - - pub fn read_configuration_descriptor( - &mut self, - config_index: u8, - ) -> (TrbFuture, MemoryRegion) { - // TODO: How should we size this. - const REGION_SIZE: u16 = 0x1000; - let (region, paddr) = MemoryRegion::contiguous_physical(REGION_SIZE as u64).unwrap(); - let setup_stage = SetupStage::new() - .with_request_type(0b10000000) - .with_request(6) - .with_value(0x2 << 8 | config_index as u16) - .with_length(region.size() as u16) - .with_index(0) - .with_transfer_type(TransferType::InDataStage); - let data_stage = DataStage::new() - .with_data_buffer_pointer(paddr) - .with_trb_transfer_length(region.size() as u32) - .with_direction(true); - let status_stage = StatusStage::new() - .with_interrupter_target(0) - .with_interrupt_on_completion(true) - .with_direction(false); - - let fut = self.send_control_command(&[ - setup_stage.into(), - data_stage.into(), - status_stage.into(), - ]); - - (fut, region) - } - - pub fn prep_configure_endpoint( - &mut self, - configuration: &Configuration, - configuration_information_enable: bool, - ) -> usize { - // TODO: Handle multiple. - let endpoint = configuration.interfaces[0].endpoints[0]; - - let endpoint_index = endpoint.endpoint_index(); - - self.input_context.input_control_context.add_context_flags = 1 | 1 << endpoint_index; - self.input_context.input_control_context.drop_context_flags = 0; - - self.input_context.input_control_context.settings = if configuration_information_enable { - InputControlContextSettings::new() - .with_configuration_value(configuration.configuration.configuration_value) - } else { - InputControlContextSettings::new() - }; - - self.input_context - .slot_context - .fields - .set_context_entries(endpoint_index + 1); - - let ep_context = &mut self.input_context.endpoint_contexts[endpoint_index as usize - 1]; - ep_context.fields = EndpointContextFields::new() - .with_interval(endpoint.interval) - .with_endpoint_type(endpoint.endpoint_type()) - .with_max_packet_size(endpoint.max_packet_size); - - // TODO: Prep Event Ring. - - self.input_context.physical_address() - } - - pub fn handle_completion(&mut self, trb: TransferEvent) { - if trb.endpoint_id() != 0x1 { - mammoth::debug!("Unhandled endpoint id {}", trb.endpoint_id()); - return; - } - self.endpoint_0_transfer_ring - .handle_completion(trb, trb.transfer_trb_pointer() as usize); - } -} - -pub struct DeviceSlotManager { - device_context_base_array: DeviceContextBaseArray, - slots: Box<[Option]>, - doorbells: Box<[Option]>, -} - -impl DeviceSlotManager { - pub fn new(max_slots: u8, doorbells: Box<[DoorbellPointer]>) -> Self { - assert!( - doorbells.len() == max_slots as usize, - "Got an incorrect doorbell slice size." - ); - Self { - device_context_base_array: DeviceContextBaseArray::new(max_slots), - slots: core::iter::repeat_with(|| None) - .take(max_slots as usize) - .collect(), - doorbells: doorbells.into_iter().map(Some).collect(), - } - } - - pub fn device_context_base_array_physical_address(&self) -> usize { - self.device_context_base_array.0.physical_address() - } - - /// Prepares a slot and an input context for an address device command. - /// - /// Follows section 4.6.5 of the XHCI spec. - pub fn prep_slot_for_address_device(&mut self, slot_id: u8, port_number: u8) -> usize { - // TODO: Ensure alignment - let mut device_slot = DeviceSlot::new( - self.doorbells[(slot_id - 1) as usize] - .take() - .expect("Slot already allocated."), - ); - - // The Add Context flags for the Slot Context and the Endpoint 0 Context shall be set to ‘1’. - device_slot - .input_context - .input_control_context - .add_context_flags = 0x3; - - // See XHCI 4.5.2 for information - device_slot.input_context.slot_context.fields = device_slot - .input_context - .slot_context - .fields - .with_root_hub_port_number(port_number) - .with_route_string(0) - .with_context_entries(1) - .with_interrupter_target(0); - - // The Endpoint 0 Context data structure in the - // Input Context shall define valid values for the TR Dequeue Pointer, EP Type, Error - // Count (CErr), and Max Packet Size fields. The MaxPStreams, Max Burst Size, and - // EP State values shall be cleared to '0' - device_slot - .input_context - .endpoint_context_0 - .tr_deque_pointer = TRDequeuePointer::new() - .with_pointer(device_slot.endpoint_0_transfer_ring.physical_base_address() as u64) - .with_dequeue_cycle_state(true); - - device_slot.input_context.endpoint_context_0.fields = EndpointContextFields::new() - .with_endpoint_type(EndpointType::Control) - .with_max_primary_streams(0) - .with_max_burst_size(0) - .with_endpoint_state(EndpointState::Disabled); - - self.device_context_base_array.0[slot_id as usize] = - device_slot.device_context.physical_address() as u64; - let paddr = device_slot.input_context.physical_address(); - self.slots[slot_id as usize - 1] = Some(device_slot); - paddr - } - - pub fn slot_at(&mut self, slot_id: u8) -> &mut DeviceSlot { - self.slots[slot_id as usize - 1].as_mut().unwrap() - } -} diff --git a/rust/sys/voyageurs/src/xhci/driver.rs b/rust/sys/voyageurs/src/xhci/driver.rs deleted file mode 100644 index 3214d33..0000000 --- a/rust/sys/voyageurs/src/xhci/driver.rs +++ /dev/null @@ -1,369 +0,0 @@ -use alloc::sync::Arc; -use mammoth::sync::Mutex; -use mammoth::task::Spawner; -use mammoth::task::Task; - -use super::registers::{self}; -use crate::xhci::data_structures::AddressDeviceCommand; -use crate::xhci::data_structures::CommandCompletionCode; -use crate::xhci::data_structures::CommandCompletionEvent; -use crate::xhci::data_structures::CommandTrb; -use crate::xhci::data_structures::EnableSlotCommand; -use crate::xhci::data_structures::EventTrb; -use crate::xhci::data_structures::NoOpCommand; -use crate::xhci::data_structures::PortStatusChangeEvent; -use crate::xhci::device_context_base_array::DeviceSlotManager; -use crate::xhci::interrupter::Interrupter; -use crate::xhci::registers::DoorbellPointer; -use crate::xhci::registers::HostControllerOperationalWrapper; -use crate::xhci::registers::InterrupterRegisterSet; -use crate::xhci::registers::PortStatusAndControl; -use crate::xhci::trb_ring::CommandRing; -use crate::xhci::usb::Configuration; -use crate::xhci::usb::EndpointDescriptor; - -pub struct XHCIDriver { - #[allow(dead_code)] - pci_device: pci::PciDevice, - capabilities: registers::HostControllerCapabilities, - operational: HostControllerOperationalWrapper, - command_ring: Mutex, - // TODO: Add multiple interrupters. - interrupter: Mutex, - device_slot_manager: Mutex, -} - -impl XHCIDriver { - pub fn from_pci_device(mut pci_device: pci::PciDevice) -> Self { - let address = - ((pci_device.header().bars[1] as usize) << 32) | (pci_device.header().bars[0] as usize); - let irq_port_cap = pci_device.register_msi().unwrap(); - - let (operational, capabilities) = HostControllerOperationalWrapper::new(address); - - let max_slots = capabilities.params_1.max_device_slots(); - let doorbell_physical = address + capabilities.doorbell_offset as usize; - let (command_doorbell, slot_doorbells) = - DoorbellPointer::create_command_and_slots(doorbell_physical, max_slots); - - // Offset to skip the mfindex register. - let interrupter_registers = mammoth::mem::map_direct_physical_and_leak( - address + capabilities.runtime_register_space_offset as usize, - size_of::() * 2, - ); - let interrupter_registers = unsafe { interrupter_registers.add(1) }; - - let mut driver = Self { - pci_device, - capabilities, - operational, - command_ring: Mutex::new(CommandRing::new(command_doorbell)), - interrupter: Mutex::new(Interrupter::new(interrupter_registers, irq_port_cap)), - device_slot_manager: Mutex::new(DeviceSlotManager::new(max_slots, slot_doorbells)), - }; - driver.initialize(); - driver - } - - fn initialize(&mut self) { - #[cfg(feature = "debug")] - mammoth::debug!("Stopping XHCI Controller."); - - // Stop the host controller. - self.operational - .update_command(|cmd| cmd.with_run_stop(false)); - - #[cfg(feature = "debug")] - mammoth::debug!("Waiting for controller to halt."); - - // Sleep until the controller is halted. - let mut status = self.operational.read_status(); - while !status.host_controller_halted() { - // TODO: Sleep for how long? - mammoth::syscall::thread_sleep(50).unwrap(); - status = self.operational.read_status(); - } - - #[cfg(feature = "debug")] - mammoth::debug!("Resetting Controller."); - - self.operational - .update_command(|cmd| cmd.with_host_controller_reset(true)); - - let mut command: registers::UsbCommand = self.operational.read_command(); - while command.host_controller_reset() { - // TODO: Sleep for how long? - mammoth::syscall::thread_sleep(50).unwrap(); - command = self.operational.read_command(); - } - - #[cfg(feature = "debug")] - mammoth::debug!("XHCI Controller Reset, waiting ready."); - - let mut status = self.operational.read_status(); - while status.controller_not_ready() { - // TODO: Sleep for how long? - mammoth::syscall::thread_sleep(50).unwrap(); - status = self.operational.read_status(); - } - - #[cfg(feature = "debug")] - mammoth::debug!("XHCI Controller Ready."); - - #[cfg(feature = "debug")] - mammoth::debug!("Setting Command Ring"); - - self.operational.set_command_ring_dequeue_pointer( - self.command_ring.lock().trb_ring.physical_base_address(), - true, - ); - - #[cfg(feature = "debug")] - mammoth::debug!("Setting DCBA."); - - self.operational - .set_device_context_base_address_array_pointer( - self.device_slot_manager - .lock() - .device_context_base_array_physical_address(), - ); - // We tell the controller that we can support as many slots as it does because - // we allocate a full 4K page to the DCBA, which is 256 entries and the max - // slots are 255. - self.operational.update_configure(|cfg| { - cfg.with_max_device_slots_enabled(self.capabilities.params_1.max_device_slots()) - .with_configuration_information_enable( - self.capabilities - .cap_params_2 - .configuration_information_capability(), - ) - }); - - assert!( - self.capabilities.params_2.max_scratchpad_buffers() == 0, - "Unsupported scratchpad buffers." - ); - - #[cfg(feature = "debug")] - mammoth::debug!("Resetting event ring."); - // SAFETY: The HC is stopped. - unsafe { self.interrupter.lock().reset() }; - - self.operational - .update_command(|cmd| cmd.with_run_stop(true).with_interrupter_enable(true)); - - #[cfg(feature = "debug")] - mammoth::debug!("Enabled interrupts and controller."); - } - - pub fn interrupt_loop(self: Arc, spawner: Spawner) { - let completion_handler = |trb| { - self.clone().handle_completion(spawner.clone(), trb); - }; - - self.interrupter.lock().interrupt_loop(completion_handler); - } - - fn handle_completion(self: Arc, spawner: Spawner, trb: EventTrb) { - match trb { - EventTrb::Transfer(trb) => { - if trb.completion_code() != CommandCompletionCode::Success { - mammoth::debug!( - "Got a transfer event with a bad completion code: {:?}", - trb.completion_code() - ) - } - // TODO: make this not panic if we don't have the slot. - self.device_slot_manager - .lock() - .slot_at(trb.slot_id()) - .handle_completion(trb); - } - EventTrb::CommandCompletion(trb) => { - self.command_ring - .lock() - .trb_ring - .handle_completion(trb, trb.command_trb_pointer() as usize); - } - EventTrb::PortStatusChange(trb) => { - let self_clone = self.clone(); - spawner.spawn(Task::new(async move { - self_clone.port_status_change(trb).await - })); - } - EventTrb::BandwidthRequest(trb) => { - mammoth::debug!("Unhandled bandwidth request event: {:?}", trb); - } - EventTrb::Doorbell(trb) => { - mammoth::debug!("Unhandled doorbell event: {:?}", trb); - } - EventTrb::HostController(trb) => { - mammoth::debug!("Unhandled host controller event: {:?}", trb); - } - EventTrb::DeviceNotification(trb) => { - mammoth::debug!("Unhandled device notification event: {:?}", trb); - } - EventTrb::MFINDEXWrap(trb) => { - mammoth::debug!("Unhandled MFINDEX wrap event: {:?}", trb); - } - } - } - - async fn send_command(&self, trb: CommandTrb) -> CommandCompletionEvent { - // Split the future and the await so the lock is dropped before we await. - let future = { self.command_ring.lock().enqueue_command(trb) }; - future.await - } - - pub async fn startup(&self) { - #[cfg(feature = "debug")] - mammoth::debug!("Sending no op command."); - - let result = self.send_command(NoOpCommand::new().into()).await; - - assert_eq!(result.completion_code(), CommandCompletionCode::Success); - - #[cfg(feature = "debug")] - mammoth::debug!("Successfully tested no op command."); - - #[cfg(feature = "debug")] - mammoth::debug!("Resetting all connected ports."); - for port_index in 0..self.operational.num_ports() { - self.operational - .update_port_status(port_index, |p| p.clear_change_bits()); - } - - for port_index in 0..self.operational.num_ports() { - let status = self.operational.get_port(port_index).status_and_control; - if status.port_power() && status.current_connect_status() { - mammoth::debug!("Resetting port {}", port_index); - self.operational.update_port_status(port_index, |_| { - PortStatusAndControl::new() - .with_port_reset(true) - .with_port_power(true) - }); - } - } - } - - async fn port_status_change(self: Arc, status_change: PortStatusChangeEvent) { - // Ports are indexed from 1. - let port_id = status_change.port_id(); - let port_index = (port_id - 1) as usize; - - let port_status = self.operational.get_port(port_index).status_and_control; - - #[cfg(feature = "debug")] - mammoth::debug!("Port status change for port {}", port_id); - - if !port_status.port_reset_change() { - mammoth::debug!( - "Unknown port status event, not handling. status= {:?}", - port_status - ); - return; - } - - self.operational - .update_port_status(port_index, |s| s.clear_change_bits()); - - #[cfg(feature = "debug")] - mammoth::debug!("Enabling slot."); - - let resp = self.send_command(EnableSlotCommand::new().into()).await; - assert_eq!(resp.completion_code(), CommandCompletionCode::Success); - - let slot = resp.slot_id(); - - #[cfg(feature = "debug")] - mammoth::debug!("Creating slot data structures in slot {}.", slot); - - let input_context_address = self - .device_slot_manager - .lock() - .prep_slot_for_address_device(slot, port_id); - - #[cfg(feature = "debug")] - mammoth::debug!("Sending address device."); - - let resp = self - .send_command( - AddressDeviceCommand::new() - .with_slot_id(slot) - .with_input_context_pointer(input_context_address as u64) - .into(), - ) - .await; - assert_eq!(resp.completion_code(), CommandCompletionCode::Success); - - #[cfg(feature = "debug")] - mammoth::debug!("Reading device descriptor"); - - let (fut, descriptor) = self - .device_slot_manager - .lock() - .slot_at(slot) - .read_device_descriptor(); - let resp = fut.await; - assert_eq!(resp.completion_code(), CommandCompletionCode::Success); - - #[cfg(feature = "debug")] - mammoth::debug!("Descriptor: {:0x?}", *descriptor); - assert!(descriptor.num_configurations >= 1); - - #[cfg(feature = "debug")] - mammoth::debug!("Reading configuration descriptor"); - - let (fut, region) = self - .device_slot_manager - .lock() - .slot_at(slot) - .read_configuration_descriptor(0); - let resp = fut.await; - assert_eq!(resp.completion_code(), CommandCompletionCode::Success); - - #[cfg(feature = "debug")] - let config = Configuration::from(region); - mammoth::debug!("Configuration: {:#x?}", config.configuration); - - for int in &config.interfaces { - #[cfg(feature = "debug")] - mammoth::debug!( - "\tInterface {:#x}: {:#?}", - int.interface.interface_number, - int.interface - ); - - for end in &int.endpoints { - #[cfg(feature = "debug")] - mammoth::debug!("\t\tEndpoint {:#x}: {:#x?}", end.endpoint_address, end); - } - } - - assert_eq!( - 1, - config.interfaces.len(), - "TODO: Handle multiple interfaces." - ); - - // TODO: Handle non Keyboard devices. - let int0 = &config.interfaces[0]; - assert_eq!(int0.interface.class, 0x3); - assert_eq!(int0.interface.subclass, 0x1); - assert_eq!(int0.interface.protocol, 0x1); - - assert_eq!(1, int0.endpoints.len(), "TODO: Handle multiple endpoints"); - - // TODO: Configure Endpoint Command. - let paddr = self - .device_slot_manager - .lock() - .slot_at(slot) - .prep_configure_endpoint( - &config, - self.capabilities - .cap_params_2 - .configuration_information_capability(), - ); - } -} diff --git a/rust/sys/voyageurs/src/xhci/event_ring.rs b/rust/sys/voyageurs/src/xhci/event_ring.rs deleted file mode 100644 index 116f27e..0000000 --- a/rust/sys/voyageurs/src/xhci/event_ring.rs +++ /dev/null @@ -1,70 +0,0 @@ -use alloc::vec::Vec; - -use crate::xhci::{ - data_structures::{EventRingSegmentTable, EventTrb, TransferRequestBlock, TrbRingSegment}, - trb_ring::TrbPointer, -}; - -pub struct EventRing { - segment_table: EventRingSegmentTable, - segments: Vec, - cycle_bit: bool, - trb_pointer: TrbPointer, -} - -impl EventRing { - pub fn new() -> Self { - // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it - // to ‘1’... - let cycle_bit = true; - let mut event_ring = Self { - segment_table: EventRingSegmentTable::new(1), - segments: [TrbRingSegment::new(100)].into(), - cycle_bit, - trb_pointer: TrbPointer::default(), - }; - - event_ring.segment_table[0].update_from_trb_ring(&event_ring.segments[0]); - - event_ring - } - - pub fn segment_table(&self) -> &EventRingSegmentTable { - &self.segment_table - } - - pub fn erdp_physical_address(&self) -> usize { - self.segments[self.trb_pointer.segment_index].physical_address() - + self.trb_pointer.segment_physical_offset() - } - - fn current_trb(&self) -> TransferRequestBlock { - // TODO: These should be volatile reads. - self.segments[self.trb_pointer.segment_index][self.trb_pointer.segment_offset] - } - - fn increment_pointer(&mut self) { - self.trb_pointer.segment_offset += 1; - - if self.trb_pointer.segment_offset == self.segments[self.trb_pointer.segment_index].len() { - self.trb_pointer.segment_index += 1; - self.trb_pointer.segment_offset = 0; - - if self.trb_pointer.segment_index == self.segments.len() { - // Wrap around to front. - self.trb_pointer.segment_index = 0; - self.cycle_bit = !self.cycle_bit; - } - } - } - - pub fn get_next(&mut self) -> Option { - let curr = self.current_trb(); - if curr.cycle() != self.cycle_bit { - None - } else { - self.increment_pointer(); - Some(curr.into()) - } - } -} diff --git a/rust/sys/voyageurs/src/xhci/interrupter.rs b/rust/sys/voyageurs/src/xhci/interrupter.rs deleted file mode 100644 index 05fca51..0000000 --- a/rust/sys/voyageurs/src/xhci/interrupter.rs +++ /dev/null @@ -1,60 +0,0 @@ -use core::ptr::NonNull; - -use mammoth::cap::Capability; - -use crate::xhci::{ - data_structures::{EventTrb, TransferRequestBlock}, - event_ring::EventRing, - registers::{InterrupterModeration, InterrupterRegisterSet, InterrupterRegisters}, -}; - -pub struct Interrupter { - event_ring: EventRing, - register_set: InterrupterRegisters, - irq_port_cap: Capability, -} - -impl Interrupter { - pub fn new( - interrupter_register_set: NonNull, - irq_port_cap: Capability, - ) -> Self { - Self { - event_ring: EventRing::new(), - register_set: InterrupterRegisters::new(interrupter_register_set), - irq_port_cap, - } - } - - // SAFETY: - // - HC Must be halted for interrupter 0. - pub unsafe fn reset(&mut self) { - // SAFETY: - // - THe segment table is size 1. - unsafe { - self.register_set.set_event_ring( - self.event_ring.segment_table(), - self.event_ring.erdp_physical_address(), - ); - } - - self.register_set.set_moderation( - InterrupterModeration::new() - .with_interrupt_moderation_interval(4000) - .with_interrupt_moderation_counter(0), - ); - - self.register_set.enable_interrupts(); - } - - pub fn interrupt_loop(&mut self, completion_handler: impl Fn(EventTrb)) { - loop { - let _ = mammoth::syscall::port_recv(&self.irq_port_cap, &mut [], &mut []).unwrap(); - while let Some(trb) = self.event_ring.get_next() { - completion_handler(trb); - } - self.register_set - .update_dequeue_pointer_clearing_busy(self.event_ring.erdp_physical_address()); - } - } -} diff --git a/rust/sys/voyageurs/src/xhci/mod.rs b/rust/sys/voyageurs/src/xhci/mod.rs deleted file mode 100644 index d2f37a5..0000000 --- a/rust/sys/voyageurs/src/xhci/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod data_structures; -mod device_context_base_array; -pub mod driver; -mod event_ring; -mod interrupter; -mod registers; -mod trb_ring; -mod usb; diff --git a/rust/sys/voyageurs/src/xhci/registers/capabilities.rs b/rust/sys/voyageurs/src/xhci/registers/capabilities.rs deleted file mode 100644 index d9bfed2..0000000 --- a/rust/sys/voyageurs/src/xhci/registers/capabilities.rs +++ /dev/null @@ -1,344 +0,0 @@ -use bitfield_struct::bitfield; - -#[bitfield(u32)] -pub struct HostControllerCapabilitiesLengthAndVersion { - /// This register is used as an offset to add to register base to find the beginning of - /// the Operational Register Space. - #[bits(access=RO)] - pub cap_length: u8, - __: u8, - /// This is a two-byte register containing a BCD encoding of the xHCI specification - /// revision number supported by this host controller. The most significant byte of - /// this register represents a major revision and the least significant byte contains - /// the minor revision extensions. e.g. 0100h corresponds to xHCI version 1.0.0, or - /// 0110h corresponds to xHCI version 1.1.0, etc - #[bits(access=RO)] - pub hci_version: u16, -} - -#[bitfield(u32)] -pub struct HCSParams1 { - /// Number of Device Slots (MaxSlots). This field specifies the maximum number of Device - /// Context Structures and Doorbell Array entries this host controller can support. Valid values are - /// in the range of 1 to 255. The value of ‘0’ is reserved. - #[bits(access=RO)] - pub max_device_slots: u8, - - /// Number of Interrupters (MaxIntrs). This field specifies the number of Interrupters implemented - /// on this host controller. Each Interrupter may be allocated to a MSI or MSI-X vector and controls - /// its generation and moderation. - /// - /// The value of this field determines how many Interrupter Register Sets are addressable in the - /// Runtime Register Space (refer to section 5.5). Valid values are in the range of 1h to 400h. A ‘0’ in - /// this field is undefined. - #[bits(11, access=RO)] - pub max_interrupters: u16, - - #[bits(5)] - __: u8, - /// Number of Ports (MaxPorts). This field specifies the maximum Port Number value, i.e. the - /// highest numbered Port Register Set that are addressable in the Operational Register Space - /// (refer to Table 5-18). Valid values are in the range of 1h to FFh. - /// - /// The value in this field shall reflect the maximum Port Number value assigned by an xHCI - /// Supported Protocol Capability, described in section 7.2. Software shall refer to these capabilities - /// to identify whether a specific Port Number is valid, and the protocol supported by the - /// associated Port Register Set. - #[bits(access=RO)] - pub max_ports: u8, -} - -#[bitfield(u32)] -pub struct HCSParams2 { - /// Isochronous Scheduling Threshold (IST). Default = implementation dependent. The value in - /// this field indicates to system software the minimum distance (in time) that it is required to stay - /// ahead of the host controller while adding TRBs, in order to have the host controller process - /// them at the correct time. The value shall be specified in terms of number of - /// frames/microframes. - /// - /// If bit [3] of IST is cleared to '0', software can add a TRB no later than IST[2:0] Microframes - /// before that TRB is scheduled to be executed. - /// - /// If bit [3] of IST is set to '1', software can add a TRB no later than IST[2:0] Frames before that TRB - /// is scheduled to be executed. - /// - /// Refer to Section 4.14.2 for details on how software uses this information for scheduling - /// isochronous transfers. - #[bits(4, access=RO)] - pub isochronous_scheduling_threshold: u8, - /// Event Ring Segment Table Max (ERST Max). Default = implementation dependent. Valid values - /// are 0 – 15. This field determines the maximum value supported the Event Ring Segment Table - /// Base Size registers (5.5.2.3.1), where: - /// - /// The maximum number of Event Ring Segment Table entries = 2 ERST Max. - /// e.g. if the ERST Max = 7, then the xHC Event Ring Segment Table(s) supports up to 128 entries, - /// 15 then 32K entries, etc. - #[bits(4, access=RO)] - pub event_ring_segment_table_max: u8, - - #[bits(13)] - __: u16, - - /// Max Scratchpad Buffers (Max Scratchpad Bufs Hi). Default = implementation dependent. This - /// field indicates the high order 5 bits of the number of Scratchpad Buffers system software shall - /// reserve for the xHC. Refer to section 4.20 for more information. - #[bits(5, access=RO)] - max_scratchpad_buffers_hi: u16, - - /// Scratchpad Restore (SPR). Default = implementation dependent. If Max Scratchpad Buffers is > - /// ‘0’ then this flag indicates whether the xHC uses the Scratchpad Buffers for saving state when - /// executing Save and Restore State operations. If Max Scratchpad Buffers is = ‘0’ then this flag - /// shall be ‘0’. Refer to section 4.23.2 for more information. - /// - /// A value of ‘1’ indicates that the xHC requires the integrity of the Scratchpad Buffer space to be - /// maintained across power events. - /// - /// A value of ‘0’ indicates that the Scratchpad Buffer space may be freed and reallocated between - /// power events. - #[bits(access=RO)] - pub scratchpad_restore: bool, - - /// Max Scratchpad Buffers (Max Scratchpad Bufs Lo). Default = implementation dependent. Valid - /// values for Max Scratchpad Buffers (Hi and Lo) are 0-1023. This field indicates the low order 5 - /// bits of the number of Scratchpad Buffers system software shall reserve for the xHC. Refer to - /// section 4.20 for more information - #[bits(5, access=RO)] - max_scratchpad_buffers_lo: u16, -} - -impl HCSParams2 { - pub fn max_scratchpad_buffers(&self) -> u16 { - (self.max_scratchpad_buffers_hi()) << 5 | self.max_scratchpad_buffers_lo() - } -} - -#[bitfield(u32)] -pub struct HCSParams3 { - /// U1 Device Exit Latency. Worst case latency to transition a root hub Port Link State (PLS) from - /// U1 to U0. Applies to all root hub ports. - /// The following are permissible values: - /// - /// Value Description - /// 00h Zero - /// 01h Less than 1 μs - /// 02h Less than 2 μs. - /// … - /// 0Ah Less than 10 μs - #[bits(access=RO)] - pub u1_device_exit_latency: u8, - /// U2 Device Exit Latency. Worst case latency to transition from U2 to U0. Applies to all root hub - /// ports. - /// The following are permissible values: - /// Value Description - /// 0000h Zero - /// 0001h Less than 1 μs. - /// 0002h Less than 2 μs. - /// … - /// 07FFh Less than 2047 μs. - /// 0800-FFFFh Reserved - #[bits(access=RO)] - pub u2_device_exit_latency: u8, - __: u16, -} - -#[bitfield(u32)] -pub struct HCCParams1 { - /// 64-bit Addressing Capability (AC64). This flag documents the addressing range capability of - /// this implementation. The value of this flag determines whether the xHC has implemented the - /// high order 32 bits of 64 bit register and data structure pointer fields. Values for this flag have the - /// following interpretation: - /// - /// Value Description - /// 0 32-bit address memory pointers implemented - /// 1 64-bit address memory pointers implemented - /// - /// If 32-bit address memory pointers are implemented, the xHC shall ignore the high order 32 bits - /// of 64 bit data structure pointer fields, and system software shall ignore the high order 32 bits of - /// 64 bit xHC registers. - #[bits(access=RO)] - pub supports_64_bit: bool, - /// BW Negotiation Capability (BNC). This flag identifies whether the xHC has implemented the - /// Bandwidth Negotiation. Values for this flag have the following interpretation: - /// - /// Value Description - /// 0 BW Negotiation not implemented - /// 1 BW Negotiation implemented - /// - /// Refer to section 4.16 for more information on Bandwidth Negotiation. - #[bits(access=RO)] - pub bandwidth_negotiation: bool, - /// Context Size (CSZ). If this bit is set to ‘1’, then the xHC uses 64 byte Context data structures. If - /// this bit is cleared to ‘0’, then the xHC uses 32 byte Context data structures. - /// Note: This flag does not apply to Stream Contexts. - #[bits(access=RO)] - pub context_size: bool, - /// Port Power Control (PPC). This flag indicates whether the host controller implementation - /// includes port power control. A ‘1’ in this bit indicates the ports have port power switches. A ‘0’ in - /// this bit indicates the port do not have port power switches. The value of this flag affects the - /// functionality of the PP flag in each port status and control register (refer to Section 5.4.8) - #[bits(access=RO)] - pub port_power_control: bool, - /// Port Indicators (PIND). This bit indicates whether the xHC root hub ports support port indicator - /// control. When this bit is a ‘1’, the port status and control registers include a read/writeable field - /// for controlling the state of the port indicator. Refer to Section 5.4.8 for definition of the Port - /// Indicator Control field. - #[bits(access=RO)] - pub port_indicators: bool, - /// Light HC Reset Capability (LHRC). This flag indicates whether the host controller implementation - /// supports a Light Host Controller Reset. A ‘1’ in this bit indicates that Light Host Controller Reset is - /// supported. A ‘0’ in this bit indicates that Light Host Controller Reset is not supported. The value - /// of this flag affects the functionality of the Light Host Controller Reset (LHCRST) flag in the - /// USBCMD register (refer to Section 5.4.1). - #[bits(access=RO)] - pub light_hc_reset_capability: bool, - /// Latency Tolerance Messaging Capability (LTC). This flag indicates whether the host controller - /// implementation supports Latency Tolerance Messaging (LTM). A ‘1’ in this bit indicates that LTM - /// is supported. A ‘0’ in this bit indicates that LTM is not supported. Refer to section 4.13.1 for more - /// information on LTM - #[bits(access=RO)] - pub latency_tolerance_messaging_capability: bool, - /// No Secondary SID Support (NSS). This flag indicates whether the host controller - /// implementation supports Secondary Stream IDs. A ‘1’ in this bit indicates that Secondary Stream - /// ID decoding is not supported. A ‘0’ in this bit indicates that Secondary Stream ID decoding is - /// supported. (refer to Sections 4.12.2 and 6.2.3) - #[bits(access=RO)] - pub no_secondary_sid_support: bool, - /// Parse All Event Data (PAE). This flag indicates whether the host controller implementation - /// Parses all Event Data TRBs while advancing to the next TD after a Short Packet, or it skips all but - /// the first Event Data TRB. A ‘1’ in this bit indicates that all Event Data TRBs are parsed. A ‘0’ in this - /// bit indicates that only the first Event Data TRB is parsed (refer to section 4.10.1.1). - #[bits(access=RO)] - pub parse_all_event_data: bool, - /// Stopped - Short Packet Capability (SPC). This flag indicates that the host controller - /// implementation is capable of generating a Stopped - Short Packet Completion Code. Refer to - /// section 4.6.9 for more information - #[bits(access=RO)] - pub stopped_short_packet_capability: bool, - /// Stopped EDTLA Capability (SEC). This flag indicates that the host controller implementation - /// Stream Context support a Stopped EDTLA field. Refer to sections 4.6.9, 4.12, and 6.4.4.1 for more - /// information. - /// Stopped EDTLA Capability support (i.e. SEC = '1') shall be mandatory for all xHCI 1.1 and xHCI 1.2 - /// compliant xHCs. - #[bits(access=RO)] - pub stopped_edtla_capability: bool, - /// Contiguous Frame ID Capability (CFC). This flag indicates that the host controller - /// implementation is capable of matching the Frame ID of consecutive Isoch TDs. Refer to section - /// 4.11.2.5 for more information. - #[bits(access=RO)] - pub contiguous_frame_id_capability: bool, - /// Maximum Primary Stream Array Size (MaxPSASize). This fields identifies the maximum size - /// Primary Stream Array that the xHC supports. The Primary Stream Array size = 2MaxPSASize+1. Valid - /// MaxPSASize values are 0 to 15, where ‘0’ indicates that Streams are not supported - #[bits(4, access=RO)] - pub maximum_primary_stream_array_size: u8, - /// xHCI Extended Capabilities Pointer (xECP). This field indicates the existence of a capabilities list. - /// The value of this field indicates a relative offset, in 32-bit words, from Base to the beginning of - /// the first extended capability. - /// - /// For example, using the offset of Base is 1000h and the xECP value of 0068h, we can calculated - /// the following effective address of the first extended capability: - /// 1000h + (0068h << 2) -> 1000h + 01A0h -> 11A0h - #[bits(access=RO)] - pub xhci_extended_capabilities_pointer: u16, -} - -#[bitfield(u32)] -pub struct HCCParams2 { - /// U3 Entry Capability (U3C) - RO. This bit indicates whether the xHC Root Hub ports support port - /// Suspend Complete notification. When this bit is '1', PLC shall be asserted on any transition of - /// PLS to the U3 State. Refer to section 4.15.1 for more information. - #[bits(access=RO)] - pub u3_entry_capability: bool, - /// Configure Endpoint Command Max Exit Latency Too Large Capability (CMC) - RO. This bit - /// indicates whether a Configure Endpoint Command is capable of generating a Max Exit Latency - /// Too Large Capability Error. When this bit is '1', a Max Exit Latency Too Large Capability Error - /// may be returned by a Configure Endpoint Command. When this bit is '0', a Max Exit Latency Too - /// Large Capability Error shall not be returned by a Configure Endpoint Command. This capability - /// is enabled by the CME flag in the USBCMD register. Refer to sections 4.23.5.2 and 5.4.1 for more - /// information. - #[bits(access=RO)] - pub configure_endpoint_command_max_exit_latency_too_large_capability: bool, - /// Force Save Context Capability (FSC) - RO. This bit indicates whether the xHC supports the - /// Force Save Context Capability. When this bit is '1', the Save State operation shall save any - /// cached Slot, Endpoint, Stream or other Context information to memory. Refer to - /// Implementation Note “FSC and Context handling by Save and Restore”, and sections 4.23.2 and - /// 5.4.1 for more information. - #[bits(access=RO)] - pub force_save_context_capability: bool, - /// Compliance Transition Capability (CTC) - RO. This bit indicates whether the xHC USB3 Root - /// Hub ports support the Compliance Transition Enabled (CTE) flag. When this bit is ‘1’, USB3 Root - /// Hub port state machine transitions to the Compliance substate shall be explicitly enabled - /// software. When this bit is ‘0’, USB3 Root Hub port state machine transitions to the Compliance - /// substate are automatically enabled. Refer to section 4.19.1.2.4.1 for more information. - #[bits(access=RO)] - pub compliance_transition_capability: bool, - /// Large ESIT Payload Capability (LEC) - RO. This bit indicates whether the xHC supports ESIT - /// Payloads greater than 48K bytes. When this bit is ‘1’, ESIT Payloads greater than 48K bytes are - /// supported. When this bit is ‘0’, ESIT Payloads greater than 48K bytes are not supported. Refer to - /// section 6.2.3.8 for more information. - #[bits(access=RO)] - pub large_esit_payload_capability: bool, - /// Configuration Information Capability (CIC) - RO. This bit indicates if the xHC supports - /// extended Configuration Information. When this bit is 1, the Configuration Value, Interface - /// Number, and Alternate Setting fields in the Input Control Context are supported. When this bit is - /// 0, the extended Input Control Context fields are not supported. Refer to section 6.2.5.1 for more - /// information. - #[bits(access=RO)] - pub configuration_information_capability: bool, - /// Extended TBC Capability78 (ETC) - RO. This bit indicates if the TBC field in an Isoch TRB - /// supports the definition of Burst Counts greater than 65535 bytes. When this bit is ‘1’, the - /// Extended EBC capability is supported by the xHC. When this bit is ‘0’, it is not. Refer to section - /// 4.11.2.3 for more information. - #[bits(access=RO)] - pub extended_tbc_capability: bool, - /// Extended TBC TRB Status Capability (ETC_TSC) - RO. This bit indicates if the TBC/TRBSts field - /// in an Isoch TRB indicates additional information regarding TRB in the TD. When this bit is ‘1’, the - /// Isoch TRB TD Size/TBC field presents TBC value and TBC/TRBSts field presents the TRBSts - /// value. When this bit is ‘0’ then the ETC/ETE values defines the TD Size/TBC field and TBC/RsvdZ - /// field. This capability shall be enabled only if LEC = ‘1’ and ETC=’1’. Refer to section 4.11.2.3 for - /// more information. - #[bits(access=RO)] - pub extended_tbc_trb_status_capability: bool, - /// Get/Set Extended Property Capability (GSC) – RO. This bit indicates support for the Set - /// Extended Property and Get Extended Property commands. When this bit is ‘1’, the xHC supports - /// the Get Extended Property and Set Extended Property commands defined in section 4.6.17 and - /// section 4.6.18. When this bit is ‘0’, the xHC does not support the Get Extended Property and Set - /// Extended Property commands and the xHC does not support any of the associated Extended - /// Capabilities. - /// - /// This bit shall only be set to ‘1’ if the xHC supports one or more extended capabilities that - /// require the Get Extended Property and Set Extended Property commands. - #[bits(access=RO)] - pub get_set_extended_property_capability: bool, - /// Virtualization Based Trusted I/O Capability (VTC) – RO. This bit when set to 1, indicates that - /// the xHC supports the Virtualization based Trusted IO (VTIO) Capability. When this bit is 0, the - /// VTIO Capability is not supported. This capability is enabled by the VTIOE flag in the USBCMD - /// register. - #[bits(access=RO)] - pub virtualization_based_trusted_io_capability: bool, - - #[bits(22)] - __: u32, -} - -/// XHCI Spec Section 5.3 -/// Note that for 64 bit implementations, the controller requires qword (32bit) accesses. -/// Hence the grouping of parameters here. -/// -/// These registers are located at the addresses specified in BAR0 and BAR1 in the PCI Header. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct HostControllerCapabilities { - pub cap_length_and_version: HostControllerCapabilitiesLengthAndVersion, - pub params_1: HCSParams1, - pub params_2: HCSParams2, - pub params_3: HCSParams3, - pub cap_params_1: HCCParams1, - /// This register defines the offset of the Doorbell Array base address from the Base. (RO) - pub doorbell_offset: u32, - /// This register defines the offset of the xHCI Runtime Registers from the Base. - pub runtime_register_space_offset: u32, - pub cap_params_2: HCCParams2, -} - -const _: () = assert!(size_of::() == 0x20); diff --git a/rust/sys/voyageurs/src/xhci/registers/doorbell.rs b/rust/sys/voyageurs/src/xhci/registers/doorbell.rs deleted file mode 100644 index 9427efe..0000000 --- a/rust/sys/voyageurs/src/xhci/registers/doorbell.rs +++ /dev/null @@ -1,106 +0,0 @@ -use core::ptr::NonNull; - -use alloc::boxed::Box; -use bitfield_struct::bitfield; -use volatile::VolatileRef; - -/// The Doorbell Array is organized as an array of up to 256 Doorbell Registers. One -/// 32-bit Doorbell Register is defined in the array for each Device Slot. System -/// software utilizes the Doorbell Register to notify the xHC that it has Device Slot -/// related work for the xHC to perform. -/// -/// The number of Doorbell Registers implemented by a particular instantiation of a -/// host controller is documented in the Number of Device Slots (MaxSlots) field of -/// the HCSPARAMS1 register (section 5.3.3). -/// -/// These registers are pointed to by the Doorbell Offset Register (DBOFF) in the -/// xHC Capability register space. The Doorbell Array base address shall be Dword -/// 430 aligned and is calculated by adding the value in the DBOFF register (section -/// 5.3.7) to “Base” (the base address of the xHCI Capability register address space). -/// Refer to section 4.7 for more information on Doorbell registers. -#[bitfield(u32)] -pub struct Doorbell { - /// DB Target – RW. Doorbell Target. This field defines the target of the doorbell reference. The - /// table below defines the xHC notification that is generated by ringing the doorbell. Note that - /// Doorbell Register 0 is dedicated to Command Ring and decodes this field differently than the - /// other Doorbell Registers. - /// - /// Device Context Doorbells (1-255) - /// Value Definition - /// 0 Reserved - /// 1 Control EP 0 Enqueue Pointer Update - /// 2 EP 1 OUT Enqueue Pointer Update - /// 3 EP 1 IN Enqueue Pointer Update - /// 4 EP 2 OUT Enqueue Pointer Update - /// 5 EP 2 IN Enqueue Pointer Update - /// … ... - /// 30 EP 15 OUT Enqueue Pointer Update - /// 31 EP 15 IN Enqueue Pointer Update - /// 32:247 Reserved - /// 248:255 Vendor Defined - /// - /// Host Controller Doorbell (0) - /// Value Definition - /// 0 Command Doorbell - /// 1:247 Reserved - /// 248:255 Vendor Defined - /// - /// This field returns ‘0’ when read and should be treated as “undefined” by software. - /// When the Command Doorbell is written, the DB Stream ID field shall be cleared to ‘0’. - db_target: u8, - _reserved: u8, - - /// DB Stream ID - RW. Doorbell Stream ID. If the endpoint of a Device Context Doorbell defines - /// Streams, then this field shall be used to identify which Stream of the endpoint the doorbell - /// reference is targeting. System software is responsible for ensuring that the value written to this - /// field is valid. - /// - /// If the endpoint defines Streams (MaxPStreams > 0), then 0, 65535 (No Stream) and 65534 - /// (Prime) are reserved Stream ID values and shall not be written to this field. - /// - /// If the endpoint does not define Streams (MaxPStreams = 0) and a non-'0' value is written to this - /// field, the doorbell reference shall be ignored. - /// - /// This field only applies to Device Context Doorbells and shall be cleared to ‘0’ for Host Controller - /// Command Doorbells. - /// - /// This field returns ‘0’ when read - db_stream_id: u16, -} - -#[repr(transparent)] -pub struct DoorbellPointer(VolatileRef<'static, Doorbell>); - -impl DoorbellPointer { - // Construct a new doorbell pointer. - fn new(doorbell: NonNull) -> Self { - // SAFETY: - // - We allocate this memory in the create - Self(unsafe { VolatileRef::new(doorbell) }) - } - - pub fn create_command_and_slots( - doorbell_physical: usize, - max_slots: u8, - ) -> (Self, Box<[Self]>) { - // Add one for the command doorbell. - let doorbell_cnt = max_slots as usize + 1; - let doorbell_array_size = size_of::() * doorbell_cnt; - let doorbells: NonNull = - mammoth::mem::map_direct_physical_and_leak(doorbell_physical, doorbell_array_size); - let first = DoorbellPointer::new(doorbells); - let remainder = (1..=max_slots) - .map(|offset| { - // SAFETY: We just allocated the array of this size above. - DoorbellPointer::new(unsafe { doorbells.add(offset as usize) }) - }) - .collect(); - (first, remainder) - } - - pub fn ring(&mut self, target: u8) { - self.0 - .as_mut_ptr() - .write(Doorbell::new().with_db_target(target)) - } -} diff --git a/rust/sys/voyageurs/src/xhci/registers/host_controller.rs b/rust/sys/voyageurs/src/xhci/registers/host_controller.rs deleted file mode 100644 index 34037d6..0000000 --- a/rust/sys/voyageurs/src/xhci/registers/host_controller.rs +++ /dev/null @@ -1,505 +0,0 @@ -use core::ptr::NonNull; - -use alloc::vec::Vec; -use bitfield_struct::bitfield; -use mammoth::{mem::map_direct_physical_and_leak, sync::Mutex}; -use volatile::{VolatilePtr, VolatileRef, map_field}; - -use crate::xhci::registers::{ - HostControllerCapabilities, HostControllerUsbPort, PortStatusAndControl, -}; - -#[bitfield(u32)] -pub struct UsbCommand { - /// Run/Stop (R/S) – RW. Default = ‘0’. ‘1’ = Run. ‘0’ = Stop. When set to a ‘1’, the xHC proceeds with - /// execution of the schedule. The xHC continues execution as long as this bit is set to a ‘1’. When - /// this bit is cleared to ‘0’, the xHC completes any current or queued commands or TDs, and any - /// USB transactions associated with them, then halts. - /// - /// Refer to section 5.4.1.1 for more information on how R/S shall be managed. - /// - /// The xHC shall halt within 16 ms. after software clears the Run/Stop bit if the above conditions - /// have been met. - /// - /// The HCHalted (HCH) bit in the USBSTS register indicates when the xHC has finished its pending - /// pipelined transactions and has entered the stopped state. Software shall not write a ‘1’ to this - /// flag unless the xHC is in the Halted state (i.e. HCH in the USBSTS register is ‘1’). Doing so may - /// yield undefined results. Writing a ‘0’ to this flag when the xHC is in the Running state (i.e. HCH = - /// ‘0’) and any Event Rings are in the Event Ring Full state (refer to section 4.9.4) may result in lost - /// events. - /// - /// When this register is exposed by a Virtual Function (VF), this bit only controls the run state of - /// the xHC instance presented by the selected VF. Refer to section 8 for more information. - pub run_stop: bool, - /// Host Controller Reset (HCRST) – RW. Default = ‘0’. This control bit is used by software to reset - /// the host controller. The effects of this bit on the xHC and the Root Hub registers are similar to a - /// Chip Hardware Reset. - /// - /// When software writes a ‘1’ to this bit, the Host Controller resets its internal pipelines, timers, - /// counters, state machines, etc. to their initial value. Any transaction currently in progress on the - /// USB is immediately terminated. A USB reset shall not be driven on USB2 downstream ports, - /// however a Hot or Warm Reset79 shall be initiated on USB3 Root Hub downstream ports. - /// - /// PCI Configuration registers are not affected by this reset. All operational registers, including port - /// registers and port state machines are set to their initial values. Software shall reinitialize the - /// host controller as described in Section 4.2 in order to return the host controller to an - /// operational state. - /// - /// This bit is cleared to ‘0’ by the Host Controller when the reset process is complete. Software - /// cannot terminate the reset process early by writing a ‘0’ to this bit and shall not write any xHC - /// Operational or Runtime registers until while HCRST is ‘1’. Note, the completion of the xHC reset - /// process is not gated by the Root Hub port reset process. - /// - /// Software shall not set this bit to ‘1’ when the HCHalted (HCH) bit in the USBSTS register is a ‘0’. - /// Attempting to reset an actively running host controller may result in undefined behavior. - /// - /// When this register is exposed by a Virtual Function (VF), this bit only resets the xHC instance - /// presented by the selected VF. Refer to section 8 for more information - pub host_controller_reset: bool, - /// Interrupter Enable (INTE) – RW. Default = ‘0’. This bit provides system software with a means of - /// enabling or disabling the host system interrupts generated by Interrupters. When this bit is a ‘1’, - /// then Interrupter host system interrupt generation is allowed, e.g. the xHC shall issue an interrupt - /// at the next interrupt threshold if the host system interrupt mechanism (e.g. MSI, MSI-X, etc.) is - /// enabled. The interrupt is acknowledged by a host system interrupt specific mechanism. - /// - /// When this register is exposed by a Virtual Function (VF), this bit only enables the set of - /// Interrupters assigned to the selected VF. Refer to section 7.7.2 for more information. - pub interrupter_enable: bool, - /// Host System Error Enable (HSEE) – RW. Default = ‘0’. When this bit is a ‘1’, and the HSE bit in - /// the USBSTS register is a ‘1’, the xHC shall assert out-of-band error signaling to the host. The - /// signaling is acknowledged by software clearing the HSE bit. Refer to section 4.10.2.6 for more - /// information. - /// When this register is exposed by a Virtual Function (VF), the effect of the assertion of this bit on - /// the Physical Function (PF0) is determined by the VMM. Refer to section 8 for more information - pub host_system_error_enable: bool, - #[bits(3)] - __: u8, - /// Light Host Controller Reset (LHCRST) – RO or RW. Optional normative. Default = ‘0’. If the Light - /// HC Reset Capability (LHRC) bit in the HCCPARAMS1 register is ‘1’, then this flag allows the driver - /// to reset the xHC without affecting the state of the ports. - /// - /// A system software read of this bit as ‘0’ indicates the Light Host Controller Reset has completed - /// and it is safe for software to re-initialize the xHC. A software read of this bit as a ‘1’ indicates the - /// Light Host Controller Reset has not yet completed. - /// - /// If not implemented, a read of this flag shall always return a ‘0’. - /// - /// All registers in the Aux Power well shall maintain the values that had been asserted prior to the - /// Light Host Controller Reset. Refer to section 4.23.1 for more information. - /// - /// When this register is exposed by a Virtual Function (VF), this bit only generates a Light Reset to - /// the xHC instance presented by the selected VF, e.g. Disable the VFs’ device slots and set the - /// associated VF Run bit to Stopped. Refer to section 8 for more information. - pub light_host_controller_reset: bool, - /// Controller Save State (CSS) - RW. Default = ‘0’. When written by software with ‘1’ and HCHalted - /// (HCH) = ‘1’, then the xHC shall save any internal state (that may be restored by a subsequent - /// Restore State operation) and if FSC = '1' any cached Slot, Endpoint, Stream, or other Context - /// information (so that software may save it). When written by software with ‘1’ and HCHalted - /// (HCH) = ‘0’, or written with ‘0’, no Save State operation shall be performed. This flag always - /// returns ‘0’ when read. Refer to the Save State Status (SSS) flag in the USBSTS register for - /// information on Save State completion. Refer to section 4.23.2 for more information on xHC - /// - /// Save/Restore operation. Note that undefined behavior may occur if a Save State operation is - /// initiated while Restore State Status (RSS) = ‘1’. - /// - /// When this register is exposed by a Virtual Function (VF), this bit only controls saving the state of - /// the xHC instance presented by the selected VF. Refer to section 8 for more information. - pub controller_save_state: bool, - /// Controller Restore State (CRS) - RW. Default = ‘0’. When set to ‘1’, and HCHalted (HCH) = ‘1’, - /// then the xHC shall perform a Restore State operation and restore its internal state. When set to - /// ‘1’ and Run/Stop (R/S) = ‘1’ or HCHalted (HCH) = ‘0’, or when cleared to ‘0’, no Restore State - /// operation shall be performed. This flag always returns ‘0’ when read. Refer to the Restore State - /// Status (RSS) flag in the USBSTS register for information on Restore State completion. Refer to - /// section 4.23.2 for more information. Note that undefined behavior may occur if a Restore State - /// operation is initiated while Save State Status (SSS) = ‘1’. - /// When this register is exposed by a Virtual Function (VF), this bit only controls restoring the state - /// of the xHC instance presented by the selected VF. Refer to section 8 for more information. - pub controller_restore_state: bool, - /// Enable Wrap Event (EWE) - RW. Default = ‘0’. When set to ‘1’, the xHC shall generate a MFINDEX - /// Wrap Event every time the MFINDEX register transitions from 03FFFh to 0. When cleared to ‘0’ - /// no MFINDEX Wrap Events are generated. Refer to section 4.14.2 for more information. - /// - /// When this register is exposed by a Virtual Function (VF), the generation of MFINDEX Wrap - /// Events to VFs shall be emulated by the VMM. - pub enable_wrap_event: bool, - /// Enable U3 MFINDEX Stop (EU3S) - RW. Default = ‘0’. When set to ‘1’, the xHC may stop the - /// MFINDEX counting action if all Root Hub ports are in the U3, Disconnected, Disabled, or - /// Powered-off state. When cleared to ‘0’ the xHC may stop the MFINDEX counting action if all - /// Root Hub ports are in the Disconnected, Disabled, Training, or Powered-off state. Refer to - /// section 4.14.2 for more information - pub enable_u3_mfindex_stop: bool, - ___: bool, - /// CEM Enable (CME) - RW. Default = '0'. When set to '1', a Max Exit Latency Too Large Capability - /// Error may be returned by a Configure Endpoint Command. When cleared to '0', a Max Exit - /// Latency Too Large Capability Error shall not be returned by a Configure Endpoint Command. - /// This bit is Reserved if CMC = ‘0’. Refer to section 4.23.5.2.2 for more information. - pub cem_enable: bool, - /// Extended TBC Enable (ETE). This flag indicates that the host controller implementation is - /// enabled to support Transfer Burst Count (TBC) values greater that 4 in isoch TDs. When this bit - /// is ‘1’, the Isoch TRB TD Size/TBC field presents the TBC value, and the TBC/RsvdZ field is RsvdZ. - /// When this bit is ‘0’, the TDSize/TCB field presents the TD Size value, and the TBC/RsvdZ field - /// presents the TBC value. This bit may be set only if ETC = ‘1’. Refer to section 4.11.2.3 for more - /// information. - pub extended_tbc_enable: bool, - /// Extended TBC TRB Status Enable (TSC_EN). This flag indicates that the host controller - /// implementation is enabled to support ETC_TSC capability. When this is ‘1’, TRBSts field in the - /// TRB updated to indicate if it is last transfer TRB in the TD. This bit may be set only if - /// ETC_TSC=’1’. Refer to section 4.11.2.3 for more information. - pub extended_tbc_trb_status_enable: bool, - /// VTIO Enable (VTIOE) – RW. Default = ‘0’. When set to ‘1’, XHCI HW will enable its VTIO - /// capability and begin to use the information provided via that VTIO Registers to determine its - /// DMA-ID. When cleared to ‘0’, XHCI HW will use the Primary DMA-ID for all accesses. This bit - /// may be set only if VTC = ‘1’. - pub vtio_enable: bool, - #[bits(15)] - ____: u16, -} - -#[bitfield(u32)] -pub struct UsbStatus { - /// HCHalted (HCH) – RO. Default = ‘1’. This bit is a ‘0’ whenever the Run/Stop (R/S) bit is a ‘1’. The - /// xHC sets this bit to ‘1’ after it has stopped executing as a result of the Run/Stop (R/S) bit being - /// cleared to ‘0’, either by software or by the xHC hardware (e.g. internal error). - /// - /// If this bit is '1', then SOFs, microSOFs, or Isochronous Timestamp Packets (ITP) shall not be - /// generated by the xHC, and any received Transaction Packet shall be dropped. - /// - /// When this register is exposed by a Virtual Function (VF), this bit only reflects the Halted state of - /// the xHC instance presented by the selected VF. Refer to section 8 for more information - #[bits(access=RO)] - pub host_controller_halted: bool, - __: bool, - /// Host System Error (HSE) – RW1C. Default = ‘0’. The xHC sets this bit to ‘1’ when a serious error - /// is detected, either internal to the xHC or during a host system access involving the xHC module. - /// (In a PCI system, conditions that set this bit to ‘1’ include PCI Parity error, PCI Master Abort, and - /// PCI Target Abort.) When this error occurs, the xHC clears the Run/Stop (R/S) bit in the USBCMD - /// register to prevent further execution of the scheduled TDs. If the HSEE bit in the USBCMD - /// register is a ‘1’, the xHC shall also assert out-of-band error signaling to the host. Refer to section - /// 4.10.2.6 for more information. - /// When this register is exposed by a Virtual Function (VF), the assertion of this bit affects all VFs - /// and reflects the Host System Error state of the Physical Function (PF0). Refer to section 8 for - /// more information. - pub host_system_error: bool, - /// Event Interrupt (EINT) – RW1C. Default = ‘0’. The xHC sets this bit to ‘1’ when the Interrupt - /// Pending (IP) bit of any Interrupter transitions from ‘0’ to ‘1’. Refer to section 7.1.2 for use. - /// Software that uses EINT shall clear it prior to clearing any IP flags. A race condition may occur if - /// software clears the IP flags then clears the EINT flag, and between the operations another IP ‘0’ - /// to '1' transition occurs. In this case the new IP transition shall be lost. - /// When this register is exposed by a Virtual Function (VF), this bit is the logical 'OR' of the IP bits - /// for the Interrupters assigned to the selected VF. And it shall be cleared to ‘0’ when all associated - /// interrupter IP bits are cleared, i.e. all the VF’s Interrupter Event Ring(s) are empty. Refer to - /// section 8 for more information - pub event_interrupt: bool, - /// Port Change Detect (PCD) – RW1C. Default = ‘0’. The xHC sets this bit to a ‘1’ when any port has - /// a change bit transition from a ‘0’ to a ‘1’. - /// - /// This bit is allowed to be maintained in the Aux Power well. Alternatively, it is also acceptable - /// that on a D3 to D0 transition of the xHC, this bit is loaded with the OR of all of the PORTSC - /// change bits. Refer to section 4.19.3. - /// - /// This bit provides system software an efficient means of determining if there has been Root Hub - /// port activity. Refer to section 4.15.2.3 for more information. - /// - /// When this register is exposed by a Virtual Function (VF), the VMM determines the state of this - /// bit as a function of the Root Hub Ports associated with the Device Slots assigned to the selected - /// VF. Refer to section 8 for more information. - pub port_change_detect: bool, - #[bits(3)] - __: u8, - /// Save State Status (SSS) - RO. Default = ‘0’. When the Controller Save State (CSS) flag in the - /// USBCMD register is written with ‘1’ this bit shall be set to ‘1’ and remain 1 while the xHC saves - /// its internal state. When the Save State operation is complete, this bit shall be cleared to ‘0’. - /// Refer to section 4.23.2 for more information. - /// - /// When this register is exposed by a Virtual Function (VF), the VMM determines the state of this - /// bit as a function of the saving the state for the selected VF. Refer to section 8 for more - /// information. - #[bits(access=RO)] - pub save_state_status: bool, - /// Restore State Status (RSS) - RO. Default = ‘0’. When the Controller Restore State (CRS) flag in - /// the USBCMD register is written with ‘1’ this bit shall be set to ‘1’ and remain 1 while the xHC - /// restores its internal state. When the Restore State operation is complete, this bit shall be - /// cleared to ‘0’. Refer to section 4.23.2 for more information. - /// - /// When this register is exposed by a Virtual Function (VF), the VMM determines the state of this - /// bit as a function of the restoring the state for the selected VF. Refer to section 8 for more - /// information. - #[bits(access=RO)] - pub restore_state_status: bool, - /// Save/Restore Error (SRE) - RW1C. Default = ‘0’. If an error occurs during a Save or Restore - /// operation this bit shall be set to ‘1’. This bit shall be cleared to ‘0’ when a Save or Restore - /// operation is initiated or when written with ‘1’. Refer to section 4.23.2 for more information. - /// When this register is exposed by a Virtual Function (VF), the VMM determines the state of this - /// bit as a function of the Save/Restore completion status for the selected VF. Refer to section 8 - /// for more information. - pub save_restore_error: bool, - /// Controller Not Ready (CNR) – RO. Default = ‘1’. ‘0’ = Ready and ‘1’ = Not Ready. Software shall - /// not write any Doorbell or Operational register of the xHC, other than the USBSTS register, until - /// CNR = ‘0’. This flag is set by the xHC after a Chip Hardware Reset and cleared when the xHC is - /// ready to begin accepting register writes. This flag shall remain cleared (‘0’) until the next Chip - /// Hardware Reset. - #[bits(access=RO)] - pub controller_not_ready: bool, - /// Host Controller Error (HCE) – RO. Default = 0. 0’ = No internal xHC error conditions exist and ‘1’ - /// = Internal xHC error condition. This flag shall be set to indicate that an internal error condition - /// has been detected which requires software to reset and reinitialize the xHC. Refer to section - /// 4.24.1 for more information. - #[bits(access=RO)] - pub host_controller_error: bool, - #[bits(19)] - __: u32, -} - -impl UsbStatus { - // Returns a copy of this object that can be written without overwritting flags that are RW1C. - fn preserving_flags(&self) -> UsbStatus { - self.with_host_system_error(false) - .with_event_interrupt(false) - .with_port_change_detect(false) - .with_save_restore_error(false) - } -} - -/// Internal data structure to ensure 64 bit reads and writes. -#[bitfield(u64)] -struct CommandAndStatus { - #[bits(32)] - usb_command: UsbCommand, - #[bits(32)] - usb_status: UsbStatus, -} - -impl CommandAndStatus { - fn update_command(&self, f: impl Fn(UsbCommand) -> UsbCommand) -> CommandAndStatus { - CommandAndStatus::new() - .with_usb_command(f(self.usb_command())) - .with_usb_status(self.usb_status().preserving_flags()) - } - - fn update_status(&self, f: impl Fn(UsbStatus) -> UsbStatus) -> CommandAndStatus { - self.with_usb_status(f(self.usb_status()).preserving_flags()) - } -} - -#[bitfield(u64)] -struct PageSize { - ///Page Size – RO. Default = Implementation defined. This field defines the page size supported by - /// the xHC implementation. This xHC supports a page size of 2^(n+12) if bit n is Set. For example, if - /// bit 0 is Set, the xHC supports 4k byte page sizes. - /// - /// For a Virtual Function, this register reflects the page size selected in the System Page Size field - /// of the SR-IOV Extended Capability structure. For the Physical Function 0, this register reflects - /// the implementation dependent default xHC page size. - /// - /// Various xHC resources reference PAGESIZE to describe their minimum alignment requirements. - /// - /// The maximum possible page size is 128M. - #[bits(access=RO)] - page_size: u32, - __: u32, -} - -#[bitfield(u64)] -struct DeviceNotificationControl { - __: u32, - /// This register is used by software to enable or disable the reporting of the - /// reception of specific USB Device Notification Transaction Packets. A Notification - /// Enable (Nx, where x = 0 to 15) flag is defined for each of the 16 possible de vice - /// notification types. If a flag is set for a specific notification type, a Device - /// Notification Event shall be generated when the respective notification packet is - /// received. After reset all notifications are disabled. Refer to section 6.4.2.7 - device_notification_control: u32, -} - -#[bitfield(u64)] -pub struct UsbConfigure { - /// Max Device Slots Enabled (MaxSlotsEn) – RW. Default = ‘0’. This field specifies the maximum - /// number of enabled Device Slots. Valid values are in the range of 0 to MaxSlots. Enabled Devices - /// Slots are allocated contiguously. e.g. A value of 16 specifies that Device Slots 1 to 16 are active. - /// - /// A value of ‘0’ disables all Device Slots. A disabled Device Slot shall not respond to Doorbell - /// Register references. - /// - /// This field shall not be modified by software if the xHC is running (Run/Stop (R/S) = ‘1’) - pub max_device_slots_enabled: u8, - /// U3 Entry Enable (U3E) – RW. Default = '0'. When set to '1', the xHC shall assert the PLC flag ('1') - /// when a Root Hub port transitions to the U3 State. Refer to section 4.15.1 for more information. - pub u3_entry_enable: bool, - /// Configuration Information Enable (CIE) - RW. Default = '0'. When set to '1', the software shall - /// initialize the Configuration Value, Interface Number, and Alternate Setting fields in the Input - /// Control Context when it is associated with a Configure Endpoint Command. When this bit is '0', - /// the extended Input Control Context fields are not supported. Refer to section 6.2.5.1 for more - /// information. - pub configuration_information_enable: bool, - - #[bits(22)] - __: u32, - - // Pad to 64 bits for the purposes of reads and writes. - __: u32, -} - -/// XHCI Spec Section 5.4 -/// -/// The base address of this register space is referred to as Operational Base. The -/// Operational Base shall be Dword aligned and is calculated by adding the value -/// of the Capability Registers Length (CAPLENGTH) register (refer to Section 5.3.1) -/// to the Capability Base address. All registers are multiples of 32 bits in length -#[repr(C)] -#[derive(Copy, Clone)] -pub struct HostControllerOperational { - command_and_status: CommandAndStatus, - page_size: PageSize, - device_notification_control: DeviceNotificationControl, - /// Bit 0: Ring Cycle State (RW) - /// Bit 1: Command Stop (RW1S) - /// Bit 2: Command Abort (RW1S) - /// Bit 3: Command Ring Running (RO) - command_ring_control: u64, - __: u64, - ___: u64, - /// The Device Context Base Address Array Pointer Register identifies the base - /// address of the Device Context Base Address Array. - /// The memory structure referenced by this physical memory pointer is assumed to - /// be physically contiguous and 64-byte aligned. - device_context_base_address_array_pointer: u64, - configure: UsbConfigure, -} - -const _: () = assert!(size_of::() == 0x40); - -pub struct HostControllerOperationalWrapper { - operational: Mutex>, - // TODO: This should maybe be its own structure. - ports: Vec>>, -} - -#[allow(dead_code)] -impl HostControllerOperationalWrapper { - pub fn new(mmio_address: usize) -> (Self, HostControllerCapabilities) { - const MAP_SIZE: usize = 0x1000; - let caps_ptr: NonNull = - map_direct_physical_and_leak(mmio_address, MAP_SIZE); - - // SAFETY: - // - The pointer is valid. - // - No other thread has access in this block. - let capabilities = unsafe { VolatilePtr::new(caps_ptr).read() }; - - assert!( - capabilities.cap_params_1.supports_64_bit(), - "We only support 64 bit XHCI" - ); - - // TODO: I don't think we acutally handle this properly. - // SAFETY: XHCI Spec says that this resides in a single page of memory which we mapped - // above. - // - // BAR0 Size Allocation - // If virtualization is supported, the Capability and Operational Register sets, and - // the Extended Capabilities may reside in a single page of virtual memory, - let cap_length_and_version = capabilities.cap_length_and_version; - let operational_ptr = unsafe { - (caps_ptr.as_ptr() as *mut u8).add(cap_length_and_version.cap_length() as usize) - as *mut HostControllerOperational - }; - - const PORT_OFFSET: usize = 0x400; - - // FIXME: This calculation is cursed. - let ports_addr = unsafe { (operational_ptr as *mut u8).add(PORT_OFFSET) as usize }; - let ports_space = MAP_SIZE - cap_length_and_version.cap_length() as usize - PORT_OFFSET; - let max_ports_we_support = ports_space / size_of::(); - let max_ports = capabilities.params_1.max_ports(); - assert!( - max_ports as usize <= max_ports_we_support, - "TODO: Support more ports." - ); - - let mut ports = Vec::new(); - let ports_addr = ports_addr as *mut HostControllerUsbPort; - for port_index in 0..max_ports { - ports.push(unsafe { - Mutex::new(VolatileRef::new( - NonNull::new(ports_addr.add(port_index as usize)).unwrap(), - )) - }); - } - - let operational = Self { - operational: Mutex::new(unsafe { - VolatileRef::new(NonNull::new(operational_ptr).unwrap()) - }), - ports, - }; - - (operational, capabilities) - } - - pub fn read_command(&self) -> UsbCommand { - let locked = self.operational.lock(); - let op = locked.as_ptr(); - map_field!(op.command_and_status).read().usb_command() - } - - pub fn update_command(&self, f: impl Fn(UsbCommand) -> UsbCommand) { - let mut locked = self.operational.lock(); - let op = locked.as_mut_ptr(); - map_field!(op.command_and_status).update(|c_and_s| c_and_s.update_command(f)); - } - - pub fn read_status(&self) -> UsbStatus { - let locked = self.operational.lock(); - let op = locked.as_ptr(); - map_field!(op.command_and_status).read().usb_status() - } - - pub fn update_status(&self, f: impl Fn(UsbStatus) -> UsbStatus) { - let mut locked = self.operational.lock(); - let op = locked.as_mut_ptr(); - map_field!(op.command_and_status).update(|c_and_s| c_and_s.update_status(f)); - } - - pub fn set_device_context_base_address_array_pointer(&self, pointer: usize) { - let mut locked = self.operational.lock(); - let op = locked.as_mut_ptr(); - map_field!(op.device_context_base_address_array_pointer).write(pointer as u64); - } - - pub fn set_command_ring_dequeue_pointer(&self, pointer: usize, cycle_bit: bool) { - // TODO: Assert that the command ring is not running here. - let mut locked = self.operational.lock(); - let op = locked.as_mut_ptr(); - map_field!(op.command_ring_control).write(pointer as u64 | cycle_bit as u64); - } - - pub fn read_configure(&self) -> UsbConfigure { - let locked = self.operational.lock(); - let op = locked.as_ptr(); - map_field!(op.configure).read() - } - - pub fn update_configure(&self, f: impl Fn(UsbConfigure) -> UsbConfigure) { - let mut locked = self.operational.lock(); - let op = locked.as_mut_ptr(); - map_field!(op.configure).update(f); - } - - pub fn get_port(&self, index: usize) -> HostControllerUsbPort { - self.ports[index].lock().as_ptr().read() - } - - pub fn update_port_status( - &self, - index: usize, - f: impl Fn(PortStatusAndControl) -> PortStatusAndControl, - ) { - let mut port_ref = self.ports[index].lock(); - let ptr = port_ref.as_mut_ptr(); - map_field!(ptr.status_and_control).update(f); - } - - pub fn num_ports(&self) -> usize { - self.ports.len() - } -} diff --git a/rust/sys/voyageurs/src/xhci/registers/host_controller_port.rs b/rust/sys/voyageurs/src/xhci/registers/host_controller_port.rs deleted file mode 100644 index 27f1f45..0000000 --- a/rust/sys/voyageurs/src/xhci/registers/host_controller_port.rs +++ /dev/null @@ -1,415 +0,0 @@ -use bitfield_struct::bitfield; - -/// A host controller shall implement one or more port registers. The number of -/// port registers implemented by a particular instantiation of a host controller is -/// documented in the HCSPARAMS1 register (Section 5.3.3). Software uses this -/// information as an input parameter to determine how many ports need to be -/// serviced. -/// -/// XHCI Spec 5.4.8 -#[bitfield(u32)] -pub struct PortStatusAndControl { - /// Current Connect Status (CCS) – ROS. Default = ‘0’. ‘1’ = A device is connected81 to the port. ‘0’ = - /// A device is not connected. This value reflects the current state of the port, and may not - /// correspond directly to the event that caused the Connect Status Change (CSC) bit to be set to ‘1’. - /// - /// Refer to sections 4.19.3 and 4.19.4 for more details on the Connect Status Change (CSC) - /// assertion conditions. - /// This flag is ‘0’ if PP is ‘0’. - #[bits(access=RO)] - pub current_connect_status: bool, - - /// Port Enabled/Disabled (PED) – RW1CS. Default = ‘0’. ‘1’ = Enabled. ‘0’ = Disabled. - /// Ports may only be enabled by the xHC. Software cannot enable a port by writing a ‘1’ to this flag. - /// - /// A port may be disabled by software writing a ‘1’ to this flag. - /// - /// This flag shall automatically be cleared to ‘0’ by a disconnect event or other fault condition. - /// Note that the bit status does not change until the port state actually changes. There may be a - /// delay in disabling or enabling a port due to other host controller or bus events. - /// - /// When the port is disabled (PED = ‘0’) downstream propagation of data is blocked on this port, - /// except for reset. - /// - /// For USB2 protocol ports: - /// When the port is in the Disabled state, software shall reset the port (PR = ‘1’) to transition PED to - /// ‘1’ and the port to the Enabled state. - /// - /// For USB3 protocol ports: - /// When the port is in the Polling state (after detecting an attach), the port shall automatically - /// transition to the Enabled state and set PED to ‘1’ upon the completion of successful link training. - /// When the port is in the Disabled state, software shall write a ‘5’ (RxDetect) to the PLS field to - /// transition the port to the Disconnected state. Refer to section 4.19.1.2. - /// - /// PED shall automatically be cleared to ‘0’ when PR is set to ‘1’, and set to ‘1’ when PR transitions - /// from ‘1’ to ‘0’ after a successful reset. Refer to Port Reset (PR) bit for more information on how - /// the PED bit is managed. - /// - /// Note that when software writes this bit to a ‘1’, it shall also write a ‘0’ to the PR bit. - /// This flag is ‘0’ if PP is ‘0’. - pub port_enabled_disabled: bool, - - __: bool, - - /// Over-current Active (OCA) – RO. Default = ‘0’. ‘1’ = This port currently has an over-current - /// condition. ‘0’ = This port does not have an over-current condition. This bit shall automatically - /// transition from a ‘1’ to a ‘0’ when the over-current condition is removed. - #[bits(access=RO)] - pub over_current_active: bool, - - /// Port Reset (PR) – RW1S. Default = ‘0’. ‘1’ = Port Reset signaling is asserted. ‘0’ = Port is not in - /// Reset. When software writes a ‘1’ to this bit generating a ‘0’ to ‘1’ transition, the bus reset - /// sequence is initiated83; USB2 protocol ports shall execute the bus reset sequence as defined in - /// the USB2 Spec. USB3 protocol ports shall execute the Hot Reset sequence as defined in the - /// USB3 Spec. PR remains set until reset signaling is completed by the root hub. - /// - /// Note that software shall write a ‘1’ to this flag to transition a USB2 port from the Polling state to - /// the Enabled state. Refer to sections 4.15.2.3 and 4.19.1.1. - /// - /// This flag is ‘0’ if PP is ‘0’. - pub port_reset: bool, - - /// Port Link State (PLS) – RWS. Default = RxDetect (‘5’). This field is used to power manage the port - /// and reflects its current link state. - /// - /// When the port is in the Enabled state, system software may set the link U state by writing this - /// field. System software may also write this field to force a Disabled to Disconnected state - /// transition of the port. - /// - /// Write Value Description - /// 0 The link shall transition to a U0 state from any of the U states. - /// 285 USB2 protocol ports only. The link should transition to the U2 State. - /// 384 The link shall transition to a U3 state from the U0 state. This action - /// selectively suspends the device connected to this port. While the Port - /// Link State = U3, the hub does not propagate downstream-directed - /// traffic to this port, but the hub shall respond to resume signaling from - /// the port. - /// 5 USB3 protocol ports only. If the port is in the Disabled state (PLS = - /// Disabled, PP = 1), then the link shall transition to a RxDetect state and - /// the port shall transition to the Disconnected state, else ignored. - /// 10 USB3 protocol ports only. Shall enable a link transition to the - /// Compliance state, i.e. CTE = ‘1’. Refer to section 4.19.1.2.4.1 for more - /// information. - /// 185,4,6-9,11-14 Ignored. - /// 15 USB2 protocol ports only. If the port is in the U3 state (PLS = U3), then - /// the link shall remain in the U3 state and the port shall transition to the - /// Resume substate, else ignored. Refer to section 4.15.2 for more - /// information. - /// - /// Note: The Port Link State Write Strobe (LWS) shall also be set to ‘1’ to write this - /// field. - /// - /// For USB2 protocol ports: Writing a value of '2' to this field shall request LPM, asserting L1 - /// signaling on the USB2 bus. Software may read this field to determine if the transition to the U2 - /// state was successful. Writing a value of '0' shall deassert L1 signaling on the USB. Writing a value - /// of '1' shall have no effect. The U1 state shall never be reported by a USB2 protocol port. - /// - /// Read Value Meaning - /// 0 Link is in the U0 State - /// 1 Link is in the U1 State - /// 2 Link is in the U2 State - /// 3 Link is in the U3 State (Device Suspended) - /// 4 Link is in the Disabled State86 - /// 5 Link is in the RxDetect State87 - /// 6 Link is in the Inactive State88 - /// 7 Link is in the Polling State - /// 8 Link is in the Recovery State - /// 9 Link is in the Hot Reset State - /// 10 Link is in the Compliance Mode State - /// 11 Link is in the Test Mode89 State - /// 12-14 Reserved - /// 15 Link is in the Resume State90 - /// - /// This field is undefined if PP = ‘0’. - /// - /// Note: Transitions between different states are not reflected until the transition is complete. Refer - /// to section 4.19 for PLS transition conditions. - /// 409 - /// - /// Refer to sections 4.15.2 and 4.23.5 for more information on the use of this field. Refer to the - /// USB2 LPM ECR for more information on USB link power management operation. Refer to section - /// 7.2 for supported USB protocols - #[bits(4)] - pub port_link_status: u8, - /// Port Power (PP) – RWS. Default = ‘1’. This flag reflects a port's logical, power control state. - /// Because host controllers can implement different methods of port power switching, this flag may - /// or may not represent whether (VBus) power is actually applied to the port. When PP equals a '0' - /// the port is nonfunctional and shall not report attaches, detaches, or Port Link State (PLS) - /// changes. However, the port shall report over-current conditions when PP = ‘0’ if PPC = ‘0’. After - /// modifying PP, software shall read PP and confirm that it is reached its target state before - /// modifying it again91, undefined behavior may occur if this procedure is not followed. - /// - /// 0 = This port is in the Powered-off state. - /// 1 = This port is not in the Powered-off state. - /// - /// If the Port Power Control (PPC) flag in the HCCPARAMS1 register is '1', then xHC has port power - /// control switches and this bit represents the current setting of the switch ('0' = off, '1' = on). - /// - /// If the Port Power Control (PPC) flag in the HCCPARAMS1 register is '0', then xHC does not have - /// port power control switches and each port is hard wired to power, and not affected by this bit. - /// When an over-current condition is detected on a powered port, the xHC shall transition the PP - /// bit in each affected port from a ‘1’ to ‘0’ (removing power from the port). - /// - /// Note: If this is an SSIC Port, then the DSP Disconnect process is initiated by '1' to '0' transition of - /// PP. After an SSIC USP disconnect process, the port may be disabled by setting PED = 1. As noted, - /// the SSIC spec does not define a mechanism for the USP to request DSP to be re-enabled for a - /// subsequent re-connect. If PED is set to 1 without a prior negotiated disconnect with the USP, - /// subsequent re-enabling of the port requires DSP to issue a WPR to bring USP back to Rx.Detect. - /// - /// Refer to section 5.1.2 in the SSIC Spec for more information. - /// Refer to section 4.19.4 for more information. - pub port_power: bool, - /// Port Speed (Port Speed) – ROS. Default = ‘0’. This field identifies the speed of the connected - /// USB Device. This field is only relevant if a device is connected (CCS = ‘1’) in all other cases this - /// field shall indicate Undefined Speed. Refer to section 4.19.3. - /// - /// Value Meaning - /// 0 Undefined Speed - /// 1 -15 Protocol Speed ID (PSI), refer to section 7.2.1 for the definition of PSIV - /// field in the PSI Dword - /// - /// Note: This field is invalid on a USB2 protocol port until after the port is reset. - #[bits(4)] - pub port_speed: u8, - /// Port Indicator Control (PIC) – RWS. Default = 0. Writing to these bits has no effect if the Port - /// Indicators (PIND) bit in the HCCPARAMS1 register is a ‘0’. If PIND bit is a ‘1’, then the bit - /// encodings are: - /// - /// Value Meaning - /// 0 Port indicators are off - /// 1 Amber - /// 2 Green - /// 3 Undefined - /// - /// Refer to the USB2 Specification section 11.5.3 for a description on how these bits shall be used. - /// This field is ‘0’ if PP is ‘0’ - #[bits(2)] - pub port_indicator_control: u8, - /// Port Link State Write Strobe (LWS) – RW. Default = ‘0’. When this bit is set to ‘1’ on a write - /// reference to this register, this flag enables writes to the PLS field. When ‘0’, write data in PLS field - /// is ignored. Reads to this bit return ‘0’ - pub port_link_state_write_strobe: bool, - /// Connect Status Change (CSC) – RW1CS. Default = ‘0’. ‘1’ = Change in CCS. ‘0’ = No change. This - /// flag indicates a change has occurred in the port’s Current Connect Status (CCS) or Cold Attach - /// Status (CAS) bits. Note that this flag shall not be set if the CCS transition was due to software - /// setting PP to ‘0’, or the CAS transition was due to software setting WPR to ‘1’. The xHC sets this - /// bit to ‘1’ for all changes to the port device connect status92, even if system software has not - /// cleared an existing Connect Status Change. For example, the insertion status changes twice - /// before system software has cleared the changed condition, root hub hardware will be “setting” - /// an already-set bit (i.e., the bit will remain ‘1’). Software shall clear this bit by writing a ‘1’ to it. - /// Refer to section 4.19.2 for more information on change bit usage. - pub connect_status_change: bool, - /// Port Enabled/Disabled Change (PEC) – RW1CS. Default = ‘0’. ‘1’ = change in PED. ‘0’ = No - /// change. Note that this flag shall not be set if the PED transition was due to software setting PP to - /// ‘0’. Software shall clear this bit by writing a ‘1’ to it. Refer to section 4.19.2 for more information - /// on change bit usage. - /// - /// For a USB2 protocol port, this bit shall be set to ‘1’ only when the port is disabled due to the - /// appropriate conditions existing at the EOF2 point (refer to section 11.8.1 of the USB2 - /// - /// Specification for the definition of a Port Error). - /// For a USB3 protocol port, this bit shall never be set to ‘1’. - pub port_enabled_disabled_change: bool, - /// Warm Port Reset Change (WRC) – RW1CS/RsvdZ. Default = ‘0’. This bit is set when Warm Reset - /// processing on this port completes. ‘0’ = No change. ‘1’ = Warm Reset complete. Note that this - /// flag shall not be set to ‘1’ if the Warm Reset processing was forced to terminate due to software - /// clearing PP or PED to '0'. Software shall clear this bit by writing a '1' to it. Refer to section 4.19.5.1. - /// Refer to section 4.19.2 for more information on change bit usage. - /// - /// This bit only applies to USB3 protocol ports. For USB2 protocol ports it shall be RsvdZ. - pub warm_port_reset_change: bool, - /// Over-current Change (OCC) – RW1CS. Default = ‘0’. This bit shall be set to a ‘1’ when there is a ‘0’ - /// to ‘1’ or ‘1’ to ‘0’ transition of Over-current Active (OCA). Software shall clear this bit by writing a - /// ‘1’ to it. Refer to section 4.19.2 for more information on change bit usage. - pub over_current_change: bool, - /// Port Reset Change (PRC) – RW1CS. Default = ‘0’. This flag is set to ‘1’ due to a '1' to '0' transition - /// of Port Reset (PR). e.g. when any reset processing (Warm or Hot) on this port is complete. Note - /// that this flag shall not be set to ‘1’ if the reset processing was forced to terminate due to software - /// clearing PP or PED to '0'. ‘0’ = No change. ‘1’ = Reset complete. Software shall clear this bit by - /// writing a '1' to it. Refer to section 4.19.5. Refer to section 4.19.2 for more information on change - /// bit usage - pub port_reset_change: bool, - /// Port Link State Change (PLC) – RW1CS. Default = ‘0’. This flag is set to ‘1’ due to the following - /// PLS transitions: - /// - /// Transition Condition - /// U3 -> Resume: Wakeup signaling from a device - /// Resume -> Recovery -> U0: Device Resume complete (USB3 protocol ports - /// only) - /// Resume -> U0: Device Resume complete (USB2 protocol ports - /// only) - /// U3 -> Recovery -> U0: Software Resume complete (USB3 protocol ports - /// only) - /// U3 -> U0: Software Resume complete (USB2 protocol ports - /// only) - /// U2 -> U0: L1 Resume complete (USB2 protocol ports only)93 - /// U0 -> U0: L1 Entry Reject (USB2 protocol ports only)93 - /// Any state -> Inactive: Error (USB3 protocol ports only). - /// Note: PLC is asserted only on the first LTSSM - /// SS.Inactive.Disconnect.Detect to SS.Inactive.Quiet - /// substate transition after entering the SS.Inactive - /// state. - /// Any State -> U3: U3 Entry complete. Note: PLC is asserted only if - /// U3E = ‘1’. - /// - /// Note that this flag shall not be set if the PLS transition was due to software - /// setting PP to ‘0’. Refer to section 4.23.5 for more information. '0' = No - /// change. '1' = Link Status Changed. Software shall clear this bit by - /// writing a '1' to it. Refer to “PLC Condition:” references in section 4.19.1 - /// for the specific port state transitions that set this flag. Refer to section - /// 4.19.2 for more information on change bit usage. - pub port_link_state_change: bool, - /// Port Config Error Change (CEC) – RW1CS/RsvdZ. Default = ‘0’. This flag indicates that the port - /// failed to configure its link partner. 0 = No change. 1 = Port Config Error detected. Software shall - /// clear this bit by writing a '1' to it. Refer to section 4.19.2 for more information on change bit - /// usage. - /// - /// Note: This flag is valid only for USB3 protocol ports. For USB2 protocol ports this bit shall be - /// RsvdZ. - pub port_config_error_change: bool, - /// Cold Attach Status (CAS) – RO. Default = ‘0’. ‘1’ = Far-end Receiver Terminations were detected - /// in the Disconnected state and the Root Hub Port State Machine was unable to advance to the - /// Enabled state. Refer to sections 4.19.8 for more details on the Cold Attach Status (CAS) assertion - /// conditions. Software shall clear this bit by writing a '1' to WPR or the xHC shall clear this bit if CCS - /// transitions to ‘1’. - /// This flag is ‘0’ if PP is ‘0’ or for USB2 protocol ports - #[bits(access=RO)] - pub cold_attach_status: bool, - /// Wake on Connect Enable (WCE) – RWS. Default = ‘0’. Writing this bit to a ‘1’ enables the port to - /// be sensitive to device connects as system wake-up events96. Refer to section 4.15 for operational - /// model. - pub wake_on_connect_enable: bool, - /// Wake on Disconnect Enable (WDE) – RWS. Default = ‘0’. Writing this bit to a ‘1’ enables the port - /// to be sensitive to device disconnects as system wake-up events. Refer to section 4.15 for - /// operational model. - pub wake_on_disconnect_enable: bool, - /// Wake on Over-current Enable (WOE) – RWS. Default = ‘0’. Writing this bit to a ‘1’ enables the - /// port to be sensitive to over-current conditions as system wake-up events96. Refer to section 4.15 - /// for operational model. - pub wake_on_overcurrent_enable: bool, - __: bool, - __: bool, - /// Device Removable97 (DR) - RO. This flag indicates if this port has a removable device attached. - /// ‘1’ = Device is non-removable. ‘0’ = Device is removable. - #[bits(access=RO)] - pub device_removable: bool, - /// Warm Port Reset (WPR) – RW1S/RsvdZ. Default = ‘0’. When software writes a ‘1’ to this bit, the - /// Warm Reset sequence as defined in the USB3 Specification is initiated and the PR flag is set to ‘1’. - /// Once initiated, the PR, PRC, and WRC flags shall reflect the progress of the Warm Reset - /// sequence. This flag shall always return ‘0’ when read. Refer to section 4.19.5.1. - /// This flag only applies to USB3 protocol ports. For USB2 protocol ports it shall be RsvdZ. - pub warm_port_reset: bool, -} - -impl PortStatusAndControl { - pub fn clear_change_bits(&self) -> Self { - PortStatusAndControl::new() - .with_connect_status_change(true) - .with_port_enabled_disabled_change(true) - .with_warm_port_reset_change(true) - .with_over_current_change(true) - .with_port_reset_change(true) - .with_port_link_state_change(true) - .with_port_config_error_change(true) - .with_port_power(self.port_power()) - .with_wake_on_connect_enable(self.wake_on_connect_enable()) - .with_wake_on_disconnect_enable(self.wake_on_disconnect_enable()) - .with_wake_on_overcurrent_enable(self.wake_on_overcurrent_enable()) - } -} - -/// XHCI Spec 5.4.9 -/// NOTE: This definition is USB3 only. -#[bitfield(u32)] -pub struct PortPowerManagementStatusAndControl { - /// U1 Timeout – RWS. Default = ‘0’. Timeout value for U1 inactivity timer. If equal to FFh, the port - /// is disabled from initiating U1 entry. This field shall be set to ‘0’ by the assertion of PR to ‘1’. Refer - /// to section 4.19.4.1 for more information on U1 Timeout operation. The following are - /// permissible values: - /// - /// Value Description - /// 00h Zero (default) - /// 01h 1 μs. - /// 02h 2 μs. - /// … - /// 7Fh 127 μs. - /// 80h–FEh Reserved - /// FFh Infinite - u1_timeout: u8, - /// U2 Timeout – RWS. Default = ‘0’. Timeout value for U2 inactivity timer. If equal to FFh, the port - /// is disabled from initiating U2 entry. This field shall be set to ‘0’ by the assertion of PR to ‘1’. Refer - /// to section 4.19.4.1 for more information on U2 Timeout operation. The following are - /// permissible values: - /// - /// Value Description - /// 00h Zero (default) - /// 01h 256 μs - /// 02h 512 μs - /// … - /// FEh 65,024 ms - /// FFh Infinite - /// - /// A U2 Inactivity Timeout LMP shall be sent by the xHC to the device connected on this port when - /// this field is written. Refer to Sections 8.4.3 and 10.4.2.10 of the USB3 specification for more - /// details - u2_timeout: u8, - /// Force Link PM Accept (FLA) - RW. Default = ‘0’. When this bit is set to ‘1’, the port shall generate - /// a Set Link Function LMP with the Force_LinkPM_Accept bit asserted (‘1’). When this bit is cleared - /// to ‘0’, the port shall generate a Set Link Function LMP with the Force_LinkPM_Accept bit de- - /// asserted (‘0’). - /// This flag shall be set to ‘0’ by the assertion of PR to ‘1’ or when CCS = transitions from ‘0’ to ‘1’. - /// Writes to this flag have no effect if PP = ‘0’. - /// The Set Link Function LMP is sent by the xHC to the device connected on this port when this bit - /// transitions from ‘0’ to ‘1’ or ‘1’ to ‘0’. Refer to Sections 8.4.2 and 10.14.2.2 of the USB3 - /// specification for more details. - /// Improper use of the SS Force_LinkPM_Accept functionality can impact the performance of the - /// link significantly. This bit shall only be used for compliance and testing purposes. Software shall - /// ensure that there are no pending packets at the link level before setting this bit. - /// This flag is ‘0’ if PP is ‘0’ - force_link_pm_accept: bool, - #[bits(15)] - __: u16, -} - -/// XHCI Spec 5.4.10 -/// -/// NOTE: This definition is USB3 only. -#[bitfield(u32)] -pub struct PortLinkInfo { - /// Link Error Count – RW. Default = ‘0’. This field returns the number of link errors detected by the - /// port. This value shall be reset to ‘0’ by the assertion of a Chip Hardware Reset, HCRST, when PR - /// transitions from ‘1’ to ‘0’, or when reset by software by writing 0 to it. This register will increment - /// by one each time a port transitions from U0 to Recovery to recover an error event and will - /// saturate at max - link_error_count: u16, - /// Rx Lane Count (RLC) - RO. Default = '0'. This field that identifies the number of Receive Lanes - /// negotiated by the port. This is a "zero-based" value, where 0 to 15 represents Lane Counts of 1 - /// to 16, respectively. This value is valid only when CCS = '1'. RLC shall equal '0' for a simplex - /// Sublink. Refer to section 7.2.1 for more information. - #[bits(4)] - rx_lane_count: u8, - /// Tx Lane Count (TLC) - RO. Default = '0'. This field that identifies the number of Transmit Lanes - /// negotiated by the port. This is a "zero-based" value, where 0 to 15 represents Lane Counts of 1 - /// to 16, respectively. This value is valid only when CCS = '1'. TLC shall equal '0' for a simplex - /// Sublink. Refer to section 7.2.1 for more information. - #[bits(4)] - tx_lane_count: u8, - __: u8, -} - -/// XHCI Spec 5.4.8 - 5.4.11 -/// -/// These registers are an array of size MAX_PORTS located at offset 0x400 -/// from the HostControllerOperation address. -/// -/// Where MAX_PORTS is HostControllerCapabilities.params_1.max_ports -#[repr(C)] -#[derive(Copy, Clone)] -pub struct HostControllerUsbPort { - pub status_and_control: PortStatusAndControl, - pub power_management_status_and_control: PortPowerManagementStatusAndControl, - pub link_info: PortLinkInfo, - pub hardware_lpm_control: u32, -} - -const _: () = assert!(size_of::() == 0x10); diff --git a/rust/sys/voyageurs/src/xhci/registers/interrupter.rs b/rust/sys/voyageurs/src/xhci/registers/interrupter.rs deleted file mode 100644 index 3b75f98..0000000 --- a/rust/sys/voyageurs/src/xhci/registers/interrupter.rs +++ /dev/null @@ -1,206 +0,0 @@ -use core::ptr::NonNull; - -use bitfield_struct::bitfield; -use volatile::{VolatileRef, map_field}; - -use crate::xhci::data_structures::EventRingSegmentTable; - -/// The Interrupter Management register allows system software to enable, disable, -/// and detect xHC interrupts. -/// -/// XHCI 5.5.2.1 -#[bitfield(u32)] -struct InterrupterManagement { - /// Interrupt Pending (IP) - RW1C. Default = ‘0’. This flag represents the current state of the - /// Interrupter. If IP = ‘1’, an interrupt is pending for this Interrupter. A ‘0’ value indicates that no - /// interrupt is pending for the Interrupter. Refer to section 4.17.3 for the conditions that modify - /// the state of this flag. - interrupt_pending: bool, - - /// Interrupt Enable (IE) – RW. Default = ‘0’. This flag specifies whether the Interrupter is capable of - /// generating an interrupt. When this bit and the IP bit are set (‘1’), the Interrupter shall generate - /// an interrupt when the Interrupter Moderation Counter reaches ‘0’. If this bit is ‘0’, then the - /// Interrupter is prohibited from generating interrupts - interrupt_enabled: bool, - - #[bits(30)] - _reserved: u32, -} - -/// The Interrupter Moderation Register controls the “interrupt moderation” feature -/// of an Interrupter, allowing system software to throttle the interrupt rate -/// generated by the xHC -/// -/// XHCI 5.5.2.2 -#[bitfield(u32)] -pub struct InterrupterModeration { - /// Interrupt Moderation Interval (IMODI) – RW. Default = ‘4000’ (~1ms). Minimum inter-interrupt - /// interval. The interval is specified in 250ns increments. A value of ‘0’ disables interrupt throttling - /// logic and interrupts shall be generated immediately if IP = ‘0’, EHB = ‘0’, and the Event Ring is - /// not empty - pub interrupt_moderation_interval: u16, - - /// Interrupt Moderation Counter (IMODC) – RW. Default = undefined. Down counter. Loaded with - /// the IMODI value whenever IP is cleared to ‘0’, counts down to ‘0’, and stops. The associated - /// interrupt shall be signaled whenever this counter is ‘0’, the Event Ring is not empty, the IE and IP - /// flags = ‘1’, and EHB = ‘0’. - /// This counter may be directly written by software at any time to alter the interrupt rate - pub interrupt_moderation_counter: u16, -} - -#[bitfield(u64)] -struct ManagementAndModeration { - #[bits(32)] - management: InterrupterManagement, - - #[bits(32)] - moderation: InterrupterModeration, -} - -impl ManagementAndModeration { - fn update_moderation(self, moderation: InterrupterModeration) -> Self { - // Update preserving intterupt pending. - self.with_management(self.management().with_interrupt_pending(false)) - .with_moderation(moderation) - } -} - -/// The Event Ring Dequeue Pointer Register is written by software to define the -/// Event Ring Dequeue Pointer location to the xHC. Software updates this pointer -/// when it is finished the evaluation of an Event(s) on the Event Ring. -/// -/// XHCI 5.5.2.3.3 -#[bitfield(u64)] -struct EventRingDequePointer { - /// Dequeue ERST Segment Index (DESI) – RW. Default = ‘0’. This field may be used by the xHC to - /// accelerate checking the Event Ring full condition. This field is written with the low order 3 bits of - /// the offset of the ERST entry which defines the Event Ring segment that the Event Ring Dequeue - /// Pointer resides in. Refer to section 6.5 for the definition of an ERST entry. - #[bits(3)] - dequeue_erst_segment_index: u8, - - /// Event Handler Busy (EHB) - RW1C. Default = ‘0’. This flag shall be set to ‘1’ when the IP bit is set - /// to ‘1’ and cleared to ‘0’ by software when the Dequeue Pointer register is written. Refer to - /// section 4.17.2 for more information - event_handler_busy: bool, - - /// Event Ring Dequeue Pointer - RW. Default = ‘0’. This field defines the high order bits of the 64- - /// bit address of the current Event Ring Dequeue Pointer - #[bits(60)] - event_ring_dequeue_pointer: u64, -} - -impl EventRingDequePointer { - fn with_dequeue_pointer_adjusted(self, event_ring_dequeue_pointer: usize) -> Self { - assert!( - event_ring_dequeue_pointer & 0b1111 == 0, - "Bottom four bits of event ring dequeue pointer must be 0" - ); - self.with_event_ring_dequeue_pointer((event_ring_dequeue_pointer >> 4) as u64) - } - - fn clear_event_hanlder_busy(self) -> Self { - // RW1C - self.with_event_handler_busy(true) - } -} - -/// The Event Ring Segment Table Size Register defines the number of segments -/// supported by the Event Ring Segment Table. -/// -/// XHCI 5.5.2.3.1 -#[bitfield(u64)] -struct EventRingSegmentTableSize { - /// Event Ring Segment Table Size – RW. Default = ‘0’. This field identifies the number of valid - /// Event Ring Segment Table entries in the Event Ring Segment Table pointed to by the Event Ring - /// Segment Table Base Address register. The maximum value supported by an xHC - /// implementation for this register is defined by the ERST Max field in the HCSPARAMS2 register - /// (5.3.4). - /// For Secondary Interrupters: Writing a value of ‘0’ to this field disables the Event Ring. Any events - /// targeted at this Event Ring when it is disabled shall result in undefined behavior of the Event - /// Ring. - /// For the Primary Interrupter: Writing a value of ‘0’ to this field shall result in undefined behavior - /// of the Event Ring. The Primary Event Ring cannot be disabled. - event_ring_segment_table_size: u16, - __: u16, - __: u32, -} - -/// This is an array of registers starting at offset 0x20 of the Runtime Base. -/// The Runtime Base shall be 32-byte aligned and is calculated by adding the -/// value Runtime Register Space Offset register (refer to Section 5.3.8) to -/// the Capability Base address. All Runtime registers are multiples of 32 bits in length. -/// -/// XHCI Spec 5.5.2 -#[repr(C)] -pub struct InterrupterRegisterSet { - management_and_moderation: ManagementAndModeration, - event_ring_segment_table_size: EventRingSegmentTableSize, - /// Event Ring Segment Table Base Address Register – RW. Default = ‘0’. This field defines the - /// high order bits of the start address of the Event Ring Segment Table. - /// Writing this register sets the Event Ring State Machine:EREP Advancement to the Start state. - /// Refer to Figure 4-12 for more information. - /// For Secondary Interrupters: This field may be modified at any time. - /// For the Primary Interrupter: This field shall not be modified if HCHalted (HCH) = ‘0’. - /// - /// NOTE: This must be aligned such that bits 0:5 are 0. - /// - /// XHCI 5.5.2.3.2 - event_ring_segment_table_base_address: u64, - event_ring_deque_pointer: EventRingDequePointer, -} - -const _: () = assert!(size_of::() == 0x20); - -pub struct InterrupterRegisters(VolatileRef<'static, InterrupterRegisterSet>); - -impl InterrupterRegisters { - pub fn new(interrupter_register_set: NonNull) -> Self { - // TODO: Validate safety. - unsafe { Self(VolatileRef::new(interrupter_register_set)) } - } - - /// SAFETY: - /// - For the primary interrupter HC must be halted. - /// - The event rings size must be at most ERST_MAX from HCSPARAMS2 - pub unsafe fn set_event_ring( - &mut self, - event_ring_segment_table: &EventRingSegmentTable, - event_ring_dequeue_pointer: usize, - ) { - // NOTE: We must write the size before the base address otherwise qemu is unhappy. - // Not sure if this is required by the spec. - - let internal = self.0.as_mut_ptr(); - map_field!(internal.event_ring_segment_table_size).write( - EventRingSegmentTableSize::new() - .with_event_ring_segment_table_size(event_ring_segment_table.len() as u16), - ); - map_field!(internal.event_ring_segment_table_base_address) - .write(event_ring_segment_table.physical_address() as u64); - map_field!(internal.event_ring_deque_pointer).write( - EventRingDequePointer::new().with_dequeue_pointer_adjusted(event_ring_dequeue_pointer), - ); - } - - pub fn update_dequeue_pointer_clearing_busy(&mut self, event_ring_dequeue_pointer: usize) { - let internal = self.0.as_mut_ptr(); - map_field!(internal.event_ring_deque_pointer).update(|ptr| { - ptr.with_dequeue_pointer_adjusted(event_ring_dequeue_pointer) - .clear_event_hanlder_busy() - }); - } - - pub fn set_moderation(&mut self, moderation: InterrupterModeration) { - let internal = self.0.as_mut_ptr(); - map_field!(internal.management_and_moderation) - .update(|reg| reg.update_moderation(moderation)); - } - - pub fn enable_interrupts(&mut self) { - let internal = self.0.as_mut_ptr(); - map_field!(internal.management_and_moderation).update(|reg| { - reg.with_management(InterrupterManagement::new().with_interrupt_enabled(true)) - }); - } -} diff --git a/rust/sys/voyageurs/src/xhci/registers/mod.rs b/rust/sys/voyageurs/src/xhci/registers/mod.rs deleted file mode 100644 index 37acf46..0000000 --- a/rust/sys/voyageurs/src/xhci/registers/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// This mod contains XHCI Register Definitions -/// -/// These are generally hardware backed registers -/// defined at fixed addresses. -mod capabilities; -mod doorbell; -mod host_controller; -mod host_controller_port; -mod interrupter; - -pub use capabilities::*; -pub use doorbell::*; -pub use host_controller::*; -pub use host_controller_port::*; -pub use interrupter::*; diff --git a/rust/sys/voyageurs/src/xhci/trb_ring.rs b/rust/sys/voyageurs/src/xhci/trb_ring.rs deleted file mode 100644 index 6b58b45..0000000 --- a/rust/sys/voyageurs/src/xhci/trb_ring.rs +++ /dev/null @@ -1,199 +0,0 @@ -use core::task::{Poll, Waker}; - -use alloc::{collections::vec_deque::VecDeque, sync::Arc, vec::Vec}; -use mammoth::sync::Mutex; - -use crate::xhci::{ - data_structures::{ - CommandCompletionEvent, CommandTrb, TransferRequestBlock, TrbLink, TrbRingSegment, TypedTrb, - }, - registers::DoorbellPointer, -}; - -struct TrbFutureState { - /// Physical Address for the enqueued TRB. - /// Used for sanity checking. - physical_address: usize, - - waker: Option, - response: Option, -} - -#[derive(Clone)] -pub struct TrbFuture { - state: Arc>>, -} - -impl TrbFuture { - fn new(paddr: usize) -> Self { - Self { - state: Arc::new(Mutex::new(TrbFutureState { - physical_address: paddr, - waker: None, - response: None, - })), - } - } -} - -impl Future for TrbFuture { - type Output = T; - - fn poll( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll { - let mut state = self.state.lock(); - match state.response { - Some(trb) => Poll::Ready(trb), - None => { - state.waker = Some(cx.waker().clone()); - Poll::Pending - } - } - } -} - -#[derive(Default, Copy, Clone, Debug)] -pub struct TrbPointer { - /// Index into the vector of trb segments. - pub segment_index: usize, - /// Index into the specific segment. - /// This is a TransferRequestBlock index, - /// to get the physical_offset use segment_physical_offset() - pub segment_offset: usize, -} - -impl TrbPointer { - pub fn segment_physical_offset(&self) -> usize { - self.segment_offset * size_of::() - } -} - -pub struct TrbRing { - segments: Vec, - enqueue_pointer: TrbPointer, - cycle_bit: bool, - pending_futures: VecDeque>, -} - -impl TrbRing { - pub fn new() -> Self { - Self { - // TODO: What size and count should this be. - segments: alloc::vec![TrbRingSegment::new(100)], - enqueue_pointer: TrbPointer::default(), - // Start with this as true so we are flipping bits from 0 (default) to 1 - // to mark the enqueue pointer. - cycle_bit: true, - pending_futures: VecDeque::new(), - } - } - - pub fn physical_base_address(&self) -> usize { - self.segments[0].physical_address() - } - - fn physical_address_of_enqueue_pointer(&self) -> usize { - self.segments[self.enqueue_pointer.segment_index].physical_address() - + self.enqueue_pointer.segment_physical_offset() - } - - pub fn enqueue_trb(&mut self, trb: TransferRequestBlock) { - *self.next_trb_ref() = trb.with_cycle(self.cycle_bit); - self.advance_enqueue_pointer(); - } - - pub fn enqueue_trb_expect_interrupt(&mut self, trb: TransferRequestBlock) -> TrbFuture { - let paddr = self.physical_address_of_enqueue_pointer(); - *self.next_trb_ref() = trb.with_cycle(self.cycle_bit); - self.advance_enqueue_pointer(); - let future = TrbFuture::new(paddr); - self.pending_futures.push_back(future.clone()); - future - } - - fn next_trb_ref(&mut self) -> &mut TransferRequestBlock { - &mut self.segments[self.enqueue_pointer.segment_index][self.enqueue_pointer.segment_offset] - } - - fn advance_enqueue_pointer(&mut self) { - self.enqueue_pointer.segment_offset += 1; - - if self.enqueue_pointer.segment_offset - == self.segments[self.enqueue_pointer.segment_index].len() - 1 - { - // We have reached the end of the segment, insert a link trb. - - // Increment the segment index with wrapping. - let next_segment_index = - if self.enqueue_pointer.segment_index + 1 == self.segments.len() { - 0 - } else { - self.enqueue_pointer.segment_index + 1 - }; - - let next_segment_pointer = self.segments[next_segment_index].physical_address(); - let toggle_cycle = next_segment_index == 0; - - *self.next_trb_ref() = TrbLink::new() - .with_ring_segment_pointer(next_segment_pointer as u64) - .with_cycle(self.cycle_bit) - .with_toggle_cycle(toggle_cycle) - .to_trb(); - - // Flip toggle cycle bit if necessary. - self.cycle_bit ^= toggle_cycle; - - self.enqueue_pointer = TrbPointer { - segment_index: next_segment_index, - segment_offset: 0, - }; - } - } - - pub fn handle_completion(&mut self, completion_trb: T, physical_address: usize) { - { - let peek_completion = self.pending_futures.front().unwrap(); - let peek_completion = peek_completion.state.lock(); - // TODO: Handle recovery scenarios here. - if peek_completion.physical_address != physical_address { - mammoth::debug!( - "Got an unexpected command completion. Expected: {:0x}, Got: {:0x}", - peek_completion.physical_address, - physical_address - ); - return; - } - } - let completion = self.pending_futures.pop_front().unwrap(); - let mut completion = completion.state.lock(); - completion.response = Some(completion_trb); - - if let Some(waker) = &completion.waker { - waker.wake_by_ref(); - } - } -} - -pub struct CommandRing { - pub trb_ring: TrbRing, - doorbell: DoorbellPointer, -} - -impl CommandRing { - pub fn new(doorbell: DoorbellPointer) -> Self { - Self { - trb_ring: TrbRing::new(), - doorbell, - } - } - - // We have to explicitly return a future her - pub fn enqueue_command(&mut self, command: CommandTrb) -> TrbFuture { - let fut = self.trb_ring.enqueue_trb_expect_interrupt(command.into()); - // Command Doorbell is always 0. - self.doorbell.ring(0); - fut - } -} diff --git a/rust/sys/voyageurs/src/xhci/usb/common.rs b/rust/sys/voyageurs/src/xhci/usb/common.rs deleted file mode 100644 index 5cdbacb..0000000 --- a/rust/sys/voyageurs/src/xhci/usb/common.rs +++ /dev/null @@ -1,47 +0,0 @@ -use bitfield_struct::{bitenum, bitfield}; - -use core::fmt::Debug; - -/// > The value of the bcdUSB field is 0xJJMN -/// > for version JJ.M.N (JJ – major version number, M – minor version number, N – sub-minor -/// > version number), e.g., version 2.1.3 is represented with value 0213 H and version 3.0 is -/// > represented with a value of 0300H -#[bitfield(u16, debug = false)] -pub struct BCDVersion { - #[bits(4)] - sub_minor: u8, - #[bits(4)] - minor: u8, - major: u8, -} - -impl Debug for BCDVersion { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_fmt(format_args!( - "{}.{}.{}", - self.major(), - self.minor(), - self.sub_minor() - )) - } -} - -#[bitenum] -#[repr(u8)] -#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)] -pub enum DescriptorType { - #[default] - #[fallback] - Unknown = 0, - Device = 1, - Configuration = 2, - String = 3, - Interface = 4, - Endpoint = 5, - InterfacePower = 8, - Otg = 9, - Debug = 10, - InterfaceAssociaton = 11, - Bos = 15, - DeviceCapability = 16, -} diff --git a/rust/sys/voyageurs/src/xhci/usb/configuration_descriptor.rs b/rust/sys/voyageurs/src/xhci/usb/configuration_descriptor.rs deleted file mode 100644 index e7fd789..0000000 --- a/rust/sys/voyageurs/src/xhci/usb/configuration_descriptor.rs +++ /dev/null @@ -1,183 +0,0 @@ -use alloc::vec::Vec; -use mammoth::mem::MemoryRegion; - -use crate::xhci::{data_structures::EndpointType, usb::DescriptorType}; - -#[repr(C, packed)] -#[derive(Copy, Clone)] -pub struct ConfigurationDescriptor { - length: u8, - descriptor_type: u8, - total_length: u16, - num_interfaces: u8, - pub configuration_value: u8, - configuration_str_index: u8, - attributes: u8, - max_power: u8, -} - -const _: () = assert!(size_of::() == 0x09); -impl core::fmt::Debug for ConfigurationDescriptor { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let total_length = self.total_length; - - f.debug_struct("ConfigurationDescriptor") - .field("length", &self.length) - .field("descriptor_type", &self.descriptor_type) - .field("total_length", &total_length) - .field("num_interfaces", &self.num_interfaces) - .field("configuration_value", &self.configuration_value) - .field("configuration_str_index", &self.configuration_str_index) - .field("attributes", &self.attributes) - .field("max_power", &self.max_power) - .finish() - } -} - -#[repr(C, packed)] -#[derive(Copy, Clone)] -pub struct InterfaceDescriptor { - length: u8, - descriptor_type: u8, - pub interface_number: u8, - pub alternate_setting: u8, - pub num_endpoints: u8, - pub class: u8, - pub subclass: u8, - pub protocol: u8, - interface_str_index: u8, -} - -const _: () = assert!(size_of::() == 0x09); - -impl core::fmt::Debug for InterfaceDescriptor { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("InterfaceDescriptor") - .field("length", &self.length) - .field("descriptor_type", &self.descriptor_type) - .field("interface_number", &self.interface_number) - .field("alternate_setting", &self.alternate_setting) - .field("num_endpoints", &self.num_endpoints) - .field("class", &self.class) - .field("subclass", &self.subclass) - .field("protocol", &self.protocol) - .field("interface_str_index", &self.interface_str_index) - .finish() - } -} - -#[repr(C, packed)] -#[derive(Copy, Clone)] -pub struct EndpointDescriptor { - length: u8, - descriptor_type: u8, - pub endpoint_address: u8, - pub attributes: u8, - pub max_packet_size: u16, - pub interval: u8, -} - -impl EndpointDescriptor { - pub fn endpoint_type(&self) -> EndpointType { - if self.direction_is_in() { - match self.attributes & 0x3 { - 0b00 => EndpointType::Control, - 0b01 => EndpointType::IsochIn, - 0b10 => EndpointType::BulkIn, - 0b11 => EndpointType::InterruptIn, - _ => unreachable!(), - } - } else { - match self.attributes & 0x3 { - 0b00 => EndpointType::Control, - 0b01 => EndpointType::IsochOut, - 0b10 => EndpointType::BulkOut, - 0b11 => EndpointType::InterruptOut, - _ => unreachable!(), - } - } - } - - pub fn direction_is_in(&self) -> bool { - const IN_FLAG: u8 = 0x80; - self.endpoint_address & IN_FLAG == IN_FLAG - } - - pub fn endpoint_index(&self) -> u8 { - if self.direction_is_in() { - (2 * self.endpoint_address) + 1 - } else { - 2 * self.endpoint_address - } - } -} - -impl core::fmt::Debug for EndpointDescriptor { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("EndpointDescriptor") - .field("length", &self.length) - .field("descriptor_type", &self.descriptor_type) - .field("endpoint_address", &self.endpoint_address) - .field("attributes", &self.attributes) - .field("interval", &self.interval) - .finish() - } -} - -const _: () = assert!(size_of::() == 0x07); - -pub struct Interface { - pub interface: InterfaceDescriptor, - pub endpoints: Vec, -} - -pub struct Configuration { - pub configuration: ConfigurationDescriptor, - pub interfaces: Vec, -} - -impl Configuration { - pub fn from(region: MemoryRegion) -> Self { - let configuration = unsafe { *region.raw_ptr_at_offset::(0) }; - - let mut interfaces = Vec::new(); - let mut curr_offset = configuration.length as u64; - for _ in 0..configuration.num_interfaces { - mammoth::debug!("{:#x}", curr_offset); - let interface = - unsafe { *region.raw_ptr_at_offset::(curr_offset) }; - curr_offset += interface.length as u64; - let mut endpoints = Vec::new(); - - for _ in 0..interface.num_endpoints { - mammoth::debug!("{:#x}", curr_offset); - let mut endpoint = - unsafe { *region.raw_ptr_at_offset::(curr_offset) }; - let mut descriptor_type = DescriptorType::from_bits(endpoint.descriptor_type); - - while descriptor_type != DescriptorType::Endpoint { - let maybe_cap = endpoint.endpoint_address; - mammoth::debug!( - "Ignoring Descriptor: {:?}, {}", - endpoint.descriptor_type, - maybe_cap - ); - curr_offset += endpoint.length as u64; - endpoint = - unsafe { *region.raw_ptr_at_offset::(curr_offset) }; - descriptor_type = DescriptorType::from_bits(endpoint.descriptor_type); - } - curr_offset += endpoint.length as u64; - endpoints.push(endpoint); - } - interfaces.push(Interface { - interface, - endpoints, - }) - } - Self { - configuration, - interfaces, - } - } -} diff --git a/rust/sys/voyageurs/src/xhci/usb/device_descriptor.rs b/rust/sys/voyageurs/src/xhci/usb/device_descriptor.rs deleted file mode 100644 index f37f370..0000000 --- a/rust/sys/voyageurs/src/xhci/usb/device_descriptor.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::xhci::usb::{BCDVersion, DescriptorType}; - -#[repr(C, packed)] -#[derive(Default, Copy, Clone)] -pub struct DeviceDescriptor { - length: u8, - descriptor_type: u8, - usb_version: BCDVersion, - device_class: u8, - device_subclass: u8, - device_protocol: u8, - max_packet_size_ep_0: u8, - vendor_id: u16, - product_id: u16, - device_version: BCDVersion, - manufacturer_str_index: u8, - product_str_index: u8, - serial_str_index: u8, - pub num_configurations: u8, -} - -const _: () = assert!(size_of::() == 0x12); - -impl core::fmt::Debug for DeviceDescriptor { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let usb_version = self.usb_version; - let descriptor_type = DescriptorType::from_bits(self.descriptor_type); - let vendor_id = self.vendor_id; - let product_id = self.product_id; - let device_version = self.device_version; - f.debug_struct("DeviceDescriptor") - .field("length", &self.length) - .field("descriptor_type", &descriptor_type) - .field("usb_version", &usb_version) - .field("device_class", &self.device_class) - .field("device_subclass", &self.device_subclass) - .field("device_protocol", &self.device_protocol) - .field("max_packet_size_ep_0", &self.max_packet_size_ep_0) - .field("vendor_id", &vendor_id) - .field("product_id", &product_id) - .field("device_version", &device_version) - .field("manufacturer_str_index", &self.manufacturer_str_index) - .field("product_str_index", &self.product_str_index) - .field("serial_str_index", &self.serial_str_index) - .field("num_configurations", &self.num_configurations) - .finish() - } -} diff --git a/rust/sys/voyageurs/src/xhci/usb/mod.rs b/rust/sys/voyageurs/src/xhci/usb/mod.rs deleted file mode 100644 index 57823ba..0000000 --- a/rust/sys/voyageurs/src/xhci/usb/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod common; -mod configuration_descriptor; -mod device_descriptor; - -pub use common::*; -pub use configuration_descriptor::*; -pub use device_descriptor::*; diff --git a/rust/sys/yellowstone/Cargo.toml b/rust/sys/yellowstone/Cargo.toml index 70e9995..6a89d4d 100644 --- a/rust/sys/yellowstone/Cargo.toml +++ b/rust/sys/yellowstone/Cargo.toml @@ -7,5 +7,6 @@ edition = "2021" mammoth = { path = "../../lib/mammoth" } denali_client = { path = "../../lib/client/denali_client" } victoriafalls = { path = "../victoriafalls" } +voyageurs = { path = "../../lib/voyageurs" } yellowstone-yunq = { path = "../../lib/yellowstone" } yunq = { path = "../../lib/yunq" } diff --git a/scripts/qemu.sh b/scripts/qemu.sh index a68570d..22d6f98 100755 --- a/scripts/qemu.sh +++ b/scripts/qemu.sh @@ -18,7 +18,7 @@ if [[ $1 == "debug" ]]; then fi # Use machine q35 to access PCI devices. -~/.local/bin/qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio -hda ${BUILD_DIR}/disk.img ${QEMU_ARGS} -device nec-usb-xhci,id=xhci -device usb-kbd,bus=xhci.0 +qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio -hda ${BUILD_DIR}/disk.img ${QEMU_ARGS} -device nec-usb-xhci,id=xhci -device usb-kbd,bus=xhci.0 popd # Extra options to add to this script in the future. diff --git a/zion/interrupt/driver_manager.cpp b/zion/interrupt/driver_manager.cpp index b991004..3aa2bc5 100644 --- a/zion/interrupt/driver_manager.cpp +++ b/zion/interrupt/driver_manager.cpp @@ -18,8 +18,6 @@ void DriverManager::WriteMessage(uint64_t irq_num, IpcMessage&& message) { return; } - dbgln("IRQ offset {x}", offset); - driver_list_[offset]->Send(glcr::Move(message)); }