From 64fcd0a32347488c5e78df6f67a3e96c082b6566 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 15 Apr 2024 12:54:05 -0600 Subject: [PATCH] xhcid: ensure max packet size is set correctly before reading descriptors --- xhcid/src/usb/device.rs | 27 ++++++++++++++++++++++-- xhcid/src/usb/mod.rs | 2 +- xhcid/src/xhci/mod.rs | 45 ++++++++++++++++++++++++++++++++++++++-- xhcid/src/xhci/scheme.rs | 5 +++-- 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/xhcid/src/usb/device.rs b/xhcid/src/usb/device.rs index 7c99946bfb..c7d1835cf7 100644 --- a/xhcid/src/usb/device.rs +++ b/xhcid/src/usb/device.rs @@ -20,10 +20,33 @@ pub struct DeviceDescriptor { unsafe impl plain::Plain for DeviceDescriptor {} impl DeviceDescriptor { - fn minor_usb_vers(&self) -> u8 { + pub fn minor_usb_vers(&self) -> u8 { (self.usb & 0xFF) as u8 } - fn major_usb_vers(&self) -> u8 { + pub fn major_usb_vers(&self) -> u8 { + ((self.usb >> 8) & 0xFF) as u8 + } +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct DeviceDescriptor8Byte { + pub length: u8, + pub kind: u8, + pub usb: u16, + pub class: u8, + pub sub_class: u8, + pub protocol: u8, + pub packet_size: u8, +} + +unsafe impl plain::Plain for DeviceDescriptor8Byte {} + +impl DeviceDescriptor8Byte { + pub fn minor_usb_vers(&self) -> u8 { + (self.usb & 0xFF) as u8 + } + pub fn major_usb_vers(&self) -> u8 { ((self.usb >> 8) & 0xFF) as u8 } } diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 4c1e57a8f0..14af518556 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -1,6 +1,6 @@ pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuperSpeedDesc}; pub use self::config::ConfigDescriptor; -pub use self::device::DeviceDescriptor; +pub use self::device::{DeviceDescriptor, DeviceDescriptor8Byte}; pub use self::endpoint::{ EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 06c57ab35f..4e4da6fbd7 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -129,6 +129,12 @@ impl Xhci { Ok(()) } + async fn fetch_dev_desc_8_byte(&self, port: usize, slot: u8) -> Result { + let mut desc = unsafe { self.alloc_dma_zeroed::()? }; + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?; + Ok(*desc) + } + async fn fetch_dev_desc(&self, port: usize, slot: u8) -> Result { let mut desc = unsafe { self.alloc_dma_zeroed::()? }; self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?; @@ -552,6 +558,16 @@ impl Xhci { }; self.port_states.insert(i, port_state); + // Ensure correct packet size is used + let dev_desc_8_byte = self.fetch_dev_desc_8_byte(i, slot).await?; + { + let mut port_state = self.port_states.get_mut(&i).unwrap(); + + let mut input = port_state.input_context.lock().unwrap(); + + self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte).await?; + } + let dev_desc = self.get_desc(i, slot).await?; self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); @@ -574,6 +590,33 @@ impl Xhci { Ok(()) } + pub async fn update_max_packet_size( + &self, + input_context: &mut Dma, + slot_id: u8, + dev_desc: usb::DeviceDescriptor8Byte + ) -> Result<()> { + let new_max_packet_size = if dev_desc.major_usb_vers() == 2 { + u32::from(dev_desc.packet_size) + } else { + 1u32 << dev_desc.packet_size + }; + let endp_ctx = &mut input_context.device.endpoints[0]; + let mut b = endp_ctx.b.read(); + b &= 0x0000_FFFF; + b |= (new_max_packet_size) << 16; + endp_ctx.b.write(b); + + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { + trb.evaluate_context(slot_id, input_context.physical(), false, cycle) + }).await; + + self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; + self.event_handler_finished(); + + Ok(()) + } + pub async fn update_default_control_pipe( &self, input_context: &mut Dma, @@ -594,14 +637,12 @@ impl Xhci { b |= (new_max_packet_size) << 16; endp_ctx.b.write(b); - /*TODO: this causes issues on real hardware, maybe it should only be used on USB 2? let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) }).await; self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; self.event_handler_finished(); - */ Ok(()) } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 4a682ff8e6..afb5a200ad 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1036,7 +1036,7 @@ impl Xhci { } let raw_dd = self.fetch_dev_desc(port_id, slot).await?; - log::debug!("port {}, slot {}, desc {:?}", port_id, slot, raw_dd); + log::debug!("port {} slot {} desc {:X?}", port_id, slot, raw_dd); let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { @@ -1055,6 +1055,7 @@ impl Xhci { None }, ); + log::debug!("manufacturer {:?} product {:?} serial {:?}", manufacturer_str, product_str, serial_str); //TODO let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?; @@ -1067,7 +1068,7 @@ impl Xhci { for index in 0..raw_dd.configurations { let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; - log::debug!("port {}, slot {}, config {}, desc {:?}", port_id, slot, index, desc); + log::debug!("port {} slot {} config {} desc {:X?}", port_id, slot, index, desc); let extra_length = desc.total_length as usize - mem::size_of_val(&desc); let data = &data[..extra_length];