From 6c1e23eee3065b3f3d6fc4fb992ac9884dbabf68 Mon Sep 17 00:00:00 2001 From: Jingkui Wang Date: Tue, 9 Apr 2019 14:30:21 -0700 Subject: crosvm: update xhci abi to use new bit_field features We don't need schema anymore. Will use bool and custom enums. BUG=None TEST=local build and run crosvm Change-Id: I1396916878f2903b17a75f375aee4eec1ced0583 Signed-off-by: Daniel Verkamp Reviewed-on: https://chromium-review.googlesource.com/1564780 Tested-by: kokoro Legacy-Commit-Queue: Commit Bot Reviewed-by: Zach Reizner --- bit_field/bit_field_derive/bit_field_derive.rs | 2 +- devices/src/usb/xhci/command_ring_controller.rs | 6 +- devices/src/usb/xhci/device_slot.rs | 68 +- devices/src/usb/xhci/event_ring.rs | 28 +- devices/src/usb/xhci/interrupter.rs | 12 +- devices/src/usb/xhci/mod.rs | 2 - devices/src/usb/xhci/ring_buffer.rs | 26 +- devices/src/usb/xhci/ring_buffer_controller.rs | 15 +- devices/src/usb/xhci/scatter_gather_buffer.rs | 11 +- devices/src/usb/xhci/xhci_abi.rs | 1048 +++++++++++++++-------- devices/src/usb/xhci/xhci_abi_schema.rs | 543 ------------ devices/src/usb/xhci/xhci_transfer.rs | 7 +- 12 files changed, 794 insertions(+), 974 deletions(-) delete mode 100644 devices/src/usb/xhci/xhci_abi_schema.rs diff --git a/bit_field/bit_field_derive/bit_field_derive.rs b/bit_field/bit_field_derive/bit_field_derive.rs index 8a9fb50..7084e22 100644 --- a/bit_field/bit_field_derive/bit_field_derive.rs +++ b/bit_field/bit_field_derive/bit_field_derive.rs @@ -179,7 +179,7 @@ fn bitfield_enum_with_width_impl( impl bit_field::BitFieldSpecifier for #ident { const FIELD_WIDTH: u8 = #bits; type SetterType = Self; - type GetterType = Result; + type GetterType = std::result::Result; #[inline] fn from_u64(val: u64) -> Self::GetterType { diff --git a/devices/src/usb/xhci/command_ring_controller.rs b/devices/src/usb/xhci/command_ring_controller.rs index 6c84fc6..e893194 100644 --- a/devices/src/usb/xhci/command_ring_controller.rs +++ b/devices/src/usb/xhci/command_ring_controller.rs @@ -311,7 +311,7 @@ impl CommandRingTrbHandler { let slot_id = trb.get_slot_id(); let endpoint_id = trb.get_endpoint_id(); // See Set TR Dequeue Pointer Trb in spec. - let dequeue_ptr = trb.get_dequeue_ptr() << 4; + let dequeue_ptr = trb.get_dequeue_ptr().get_gpa().offset(); let completion_code = { if valid_slot_id(slot_id) { self.slot(slot_id)? @@ -341,7 +341,7 @@ impl TransferDescriptorHandler for CommandRingTrbHandler { // Command descriptor always consist of a single TRB. assert_eq!(descriptor.len(), 1); let atrb = &descriptor[0]; - let command_result = match atrb.trb.trb_type() { + let command_result = match atrb.trb.get_trb_type() { Ok(TrbType::EnableSlotCommand) => self.enable_slot(atrb, complete_event), Ok(TrbType::DisableSlotCommand) => self.disable_slot(atrb, complete_event), Ok(TrbType::AddressDeviceCommand) => self.address_device(atrb, complete_event), @@ -376,7 +376,7 @@ impl TransferDescriptorHandler for CommandRingTrbHandler { warn!( // We are not handling type 14,15,16. See table 6.4.6. "Unexpected command ring trb type: {}", - atrb.trb.get_trb_type() + atrb.trb ); match self.interrupter.lock().send_command_completion_trb( TrbCompletionCode::TrbError, diff --git a/devices/src/usb/xhci/device_slot.rs b/devices/src/usb/xhci/device_slot.rs index d3d556a..c6738f5 100644 --- a/devices/src/usb/xhci/device_slot.rs +++ b/devices/src/usb/xhci/device_slot.rs @@ -6,14 +6,15 @@ use super::interrupter::Interrupter; use super::transfer_ring_controller::{TransferRingController, TransferRingControllerError}; use super::usb_hub::{self, UsbHub}; use super::xhci_abi::{ - AddressDeviceCommandTrb, ConfigureEndpointCommandTrb, DeviceContext, DeviceSlotState, - EndpointContext, EndpointState, Error as TrbError, EvaluateContextCommandTrb, + AddressDeviceCommandTrb, ConfigureEndpointCommandTrb, DequeuePtr, DeviceContext, + DeviceSlotState, EndpointContext, EndpointState, EvaluateContextCommandTrb, InputControlContext, SlotContext, TrbCompletionCode, DEVICE_CONTEXT_ENTRY_SIZE, }; use super::xhci_regs::{valid_slot_id, MAX_PORTS, MAX_SLOTS}; use crate::register_space::Register; use crate::usb::xhci::ring_buffer_stop_cb::{fallible_closure, RingBufferStopCallback}; use crate::utils::{EventLoop, FailHandle}; +use bit_field::Error as BitFieldError; use std::fmt::{self, Display}; use std::mem::size_of; use std::sync::atomic::{AtomicBool, Ordering}; @@ -28,7 +29,8 @@ pub enum Error { WriteGuestMemory(GuestMemoryError), WeakReferenceUpgrade, CallbackFailed, - GetSlotContextState(TrbError), + GetSlotContextState(BitFieldError), + GetEndpointState(BitFieldError), GetPort(u8), GetTrc(u8), BadInputContextAddr(GuestAddress), @@ -49,6 +51,7 @@ impl Display for Error { WeakReferenceUpgrade => write!(f, "failed to upgrade weak reference"), CallbackFailed => write!(f, "callback failed"), GetSlotContextState(e) => write!(f, "failed to get slot context state: {}", e), + GetEndpointState(e) => write!(f, "failed to get endpoint state: {}", e), GetPort(v) => write!(f, "failed to get port: {}", v), GetTrc(v) => write!(f, "failed to get trc: {}", v), BadInputContextAddr(addr) => write!(f, "bad input context address: {}", addr), @@ -310,9 +313,10 @@ impl DeviceSlot { } }; let context = self.get_device_context()?; - // TODO(jkwang) Refactor the code to have bitfield return enum. - if context.endpoint_context[endpoint_index].get_endpoint_state() - == EndpointState::Running as u8 + if context.endpoint_context[endpoint_index] + .get_endpoint_state() + .map_err(Error::GetEndpointState)? + == EndpointState::Running { usb_debug!("endpoint is started, start transfer ring"); transfer_ring_controller.start(); @@ -350,7 +354,7 @@ impl DeviceSlot { let mut device_context = slot.get_device_context()?; device_context .slot_context - .set_state(DeviceSlotState::DisabledOrEnabled); + .set_slot_state(DeviceSlotState::DisabledOrEnabled); slot.set_device_context(device_context)?; slot.reset(); usb_debug!( @@ -378,11 +382,11 @@ impl DeviceSlot { let device_context = self.get_device_context()?; let state = device_context .slot_context - .state() + .get_slot_state() .map_err(Error::GetSlotContextState)?; match state { DeviceSlotState::DisabledOrEnabled => {} - DeviceSlotState::Default if trb.get_block_set_address_request() == 0 => {} + DeviceSlotState::Default if !trb.get_block_set_address_request() => {} _ => { error!("slot {} has unexpected slot state", self.slot_id); return Ok(TrbCompletionCode::ContextStateError); @@ -424,10 +428,10 @@ impl DeviceSlot { ); // Assign slot ID as device address if block_set_address_request is not set. - if trb.get_block_set_address_request() > 0 { + if trb.get_block_set_address_request() { device_context .slot_context - .set_state(DeviceSlotState::Default); + .set_slot_state(DeviceSlotState::Default); } else { let port = self.hub.get_port(port_id).ok_or(Error::GetPort(port_id))?; match port.get_backend_device().as_mut() { @@ -444,24 +448,24 @@ impl DeviceSlot { .set_usb_device_address(self.slot_id); device_context .slot_context - .set_state(DeviceSlotState::Addressed); + .set_slot_state(DeviceSlotState::Addressed); } // TODO(jkwang) trc should always exists. Fix this. self.get_trc(0) .ok_or(Error::GetTrc(0))? - .set_dequeue_pointer(GuestAddress( - device_context.endpoint_context[0].get_tr_dequeue_pointer() << 4, - )); + .set_dequeue_pointer( + device_context.endpoint_context[0] + .get_tr_dequeue_pointer() + .get_gpa(), + ); self.get_trc(0) .ok_or(Error::GetTrc(0))? - .set_consumer_cycle_state( - device_context.endpoint_context[0].get_dequeue_cycle_state() > 0, - ); + .set_consumer_cycle_state(device_context.endpoint_context[0].get_dequeue_cycle_state()); usb_debug!("Setting endpoint 0 to running"); - device_context.endpoint_context[0].set_state(EndpointState::Running); + device_context.endpoint_context[0].set_endpoint_state(EndpointState::Running); self.set_device_context(device_context)?; Ok(TrbCompletionCode::Success) } @@ -472,7 +476,7 @@ impl DeviceSlot { trb: &ConfigureEndpointCommandTrb, ) -> Result { usb_debug!("configuring endpoint"); - let input_control_context = if trb.get_deconfigure() > 0 { + let input_control_context = if trb.get_deconfigure() { // From section 4.6.6 of the xHCI spec: // Setting the deconfigure (DC) flag to '1' in the Configure Endpoint Command // TRB is equivalent to setting Input Context Drop Context flags 2-31 to '1' @@ -500,7 +504,7 @@ impl DeviceSlot { } } - if trb.get_deconfigure() > 0 { + if trb.get_deconfigure() { self.set_state(DeviceSlotState::Addressed)?; } else { self.set_state(DeviceSlotState::Configured)?; @@ -572,7 +576,7 @@ impl DeviceSlot { s.drop_one_endpoint(i)?; } let mut ctx = s.get_device_context()?; - ctx.slot_context.set_state(DeviceSlotState::Default); + ctx.slot_context.set_slot_state(DeviceSlotState::Default); ctx.slot_context.set_context_entries(1); ctx.slot_context.set_root_hub_port_number(0); s.set_device_context(ctx)?; @@ -636,7 +640,8 @@ impl DeviceSlot { Some(trc) => { trc.set_dequeue_pointer(GuestAddress(ptr)); let mut ctx = self.get_device_context()?; - ctx.endpoint_context[index].set_tr_dequeue_pointer(ptr >> 4); + ctx.endpoint_context[index] + .set_tr_dequeue_pointer(DequeuePtr::new(GuestAddress(ptr))); self.set_device_context(ctx)?; Ok(TrbCompletionCode::Success) } @@ -677,14 +682,17 @@ impl DeviceSlot { device_context_index, ) .map_err(Error::CreateTransferController)?; - trc.set_dequeue_pointer(GuestAddress( - device_context.endpoint_context[transfer_ring_index].get_tr_dequeue_pointer() << 4, - )); + trc.set_dequeue_pointer( + device_context.endpoint_context[transfer_ring_index] + .get_tr_dequeue_pointer() + .get_gpa(), + ); trc.set_consumer_cycle_state( - device_context.endpoint_context[transfer_ring_index].get_dequeue_cycle_state() > 0, + device_context.endpoint_context[transfer_ring_index].get_dequeue_cycle_state(), ); self.set_trc(transfer_ring_index, Some(trc)); - device_context.endpoint_context[transfer_ring_index].set_state(EndpointState::Running); + device_context.endpoint_context[transfer_ring_index] + .set_endpoint_state(EndpointState::Running); self.set_device_context(device_context) } @@ -692,7 +700,7 @@ impl DeviceSlot { let endpoint_index = (device_context_index - 1) as usize; self.set_trc(endpoint_index, None); let mut ctx = self.get_device_context()?; - ctx.endpoint_context[endpoint_index].set_state(EndpointState::Disabled); + ctx.endpoint_context[endpoint_index].set_endpoint_state(EndpointState::Disabled); self.set_device_context(ctx) } @@ -752,7 +760,7 @@ impl DeviceSlot { fn set_state(&self, state: DeviceSlotState) -> Result<()> { let mut ctx = self.get_device_context()?; - ctx.slot_context.set_state(state); + ctx.slot_context.set_slot_state(state); self.set_device_context(ctx) } } diff --git a/devices/src/usb/xhci/event_ring.rs b/devices/src/usb/xhci/event_ring.rs index 4b510f1..fcaff23 100644 --- a/devices/src/usb/xhci/event_ring.rs +++ b/devices/src/usb/xhci/event_ring.rs @@ -80,7 +80,7 @@ impl EventRing { } // Event is write twice to avoid race condition. // Guest kernel use cycle bit to check ownership, thus we should write cycle last. - trb.set_cycle_bit(!self.producer_cycle_state); + trb.set_cycle(!self.producer_cycle_state); self.mem .write_obj_at_addr(trb, self.enqueue_pointer) .map_err(Error::MemoryWrite)?; @@ -88,7 +88,7 @@ impl EventRing { // Updating the cycle state bit should always happen after updating other parts. fence(Ordering::SeqCst); - trb.set_cycle_bit(self.producer_cycle_state); + trb.set_cycle(self.producer_cycle_state); // Offset of cycle state byte. const CYCLE_STATE_OFFSET: usize = 12usize; @@ -275,7 +275,7 @@ mod test { assert_eq!(er.is_empty(), false); let t: Trb = gm.read_obj_from_addr(GuestAddress(0x100)).unwrap(); assert_eq!(t.get_control(), 1); - assert_eq!(t.get_cycle(), 1); + assert_eq!(t.get_cycle(), true); trb.set_control(2); assert_eq!(er.add_event(trb.clone()).unwrap(), ()); @@ -285,7 +285,7 @@ mod test { .read_obj_from_addr(GuestAddress(0x100 + trb_size)) .unwrap(); assert_eq!(t.get_control(), 2); - assert_eq!(t.get_cycle(), 1); + assert_eq!(t.get_cycle(), true); trb.set_control(3); assert_eq!(er.add_event(trb.clone()).unwrap(), ()); @@ -295,7 +295,7 @@ mod test { .read_obj_from_addr(GuestAddress(0x100 + 2 * trb_size)) .unwrap(); assert_eq!(t.get_control(), 3); - assert_eq!(t.get_cycle(), 1); + assert_eq!(t.get_cycle(), true); // Fill second table. trb.set_control(4); @@ -304,7 +304,7 @@ mod test { assert_eq!(er.is_empty(), false); let t: Trb = gm.read_obj_from_addr(GuestAddress(0x200)).unwrap(); assert_eq!(t.get_control(), 4); - assert_eq!(t.get_cycle(), 1); + assert_eq!(t.get_cycle(), true); trb.set_control(5); assert_eq!(er.add_event(trb.clone()).unwrap(), ()); @@ -314,7 +314,7 @@ mod test { .read_obj_from_addr(GuestAddress(0x200 + trb_size)) .unwrap(); assert_eq!(t.get_control(), 5); - assert_eq!(t.get_cycle(), 1); + assert_eq!(t.get_cycle(), true); trb.set_control(6); assert_eq!(er.add_event(trb.clone()).unwrap(), ()); @@ -324,7 +324,7 @@ mod test { .read_obj_from_addr(GuestAddress(0x200 + 2 * trb_size as u64)) .unwrap(); assert_eq!(t.get_control(), 6); - assert_eq!(t.get_cycle(), 1); + assert_eq!(t.get_cycle(), true); // Fill third table. trb.set_control(7); @@ -333,7 +333,7 @@ mod test { assert_eq!(er.is_empty(), false); let t: Trb = gm.read_obj_from_addr(GuestAddress(0x300)).unwrap(); assert_eq!(t.get_control(), 7); - assert_eq!(t.get_cycle(), 1); + assert_eq!(t.get_cycle(), true); trb.set_control(8); assert_eq!(er.add_event(trb.clone()).unwrap(), ()); @@ -344,7 +344,7 @@ mod test { .read_obj_from_addr(GuestAddress(0x300 + trb_size)) .unwrap(); assert_eq!(t.get_control(), 8); - assert_eq!(t.get_cycle(), 1); + assert_eq!(t.get_cycle(), true); // Add the last trb will result in error. match er.add_event(trb.clone()) { @@ -367,7 +367,7 @@ mod test { .read_obj_from_addr(GuestAddress(0x300 + trb_size)) .unwrap(); assert_eq!(t.get_control(), 8); - assert_eq!(t.get_cycle(), 1); + assert_eq!(t.get_cycle(), true); // Add the last trb will result in error. match er.add_event(trb.clone()) { @@ -388,7 +388,7 @@ mod test { let t: Trb = gm.read_obj_from_addr(GuestAddress(0x100)).unwrap(); assert_eq!(t.get_control(), 10); // cycle bit should be reversed. - assert_eq!(t.get_cycle(), 0); + assert_eq!(t.get_cycle(), false); trb.set_control(11); assert_eq!(er.add_event(trb.clone()).unwrap(), ()); @@ -398,7 +398,7 @@ mod test { .read_obj_from_addr(GuestAddress(0x100 + trb_size)) .unwrap(); assert_eq!(t.get_control(), 11); - assert_eq!(t.get_cycle(), 0); + assert_eq!(t.get_cycle(), false); trb.set_control(12); assert_eq!(er.add_event(trb.clone()).unwrap(), ()); @@ -408,6 +408,6 @@ mod test { .read_obj_from_addr(GuestAddress(0x100 + 2 * trb_size)) .unwrap(); assert_eq!(t.get_control(), 12); - assert_eq!(t.get_cycle(), 0); + assert_eq!(t.get_cycle(), false); } } diff --git a/devices/src/usb/xhci/interrupter.rs b/devices/src/usb/xhci/interrupter.rs index a896fb4..c58ae59 100644 --- a/devices/src/usb/xhci/interrupter.rs +++ b/devices/src/usb/xhci/interrupter.rs @@ -87,8 +87,8 @@ impl Interrupter { .cast_mut::() .map_err(Error::CastTrb)?; psctrb.set_port_id(port_id); - psctrb.set_completion_code(TrbCompletionCode::Success as u8); - psctrb.set_trb_type(TrbType::PortStatusChangeEvent as u8); + psctrb.set_completion_code(TrbCompletionCode::Success); + psctrb.set_trb_type(TrbType::PortStatusChangeEvent); self.add_event(trb) } @@ -105,8 +105,8 @@ impl Interrupter { .map_err(Error::CastTrb)?; ctrb.set_trb_pointer(trb_addr.0); ctrb.set_command_completion_parameter(0); - ctrb.set_completion_code(completion_code as u8); - ctrb.set_trb_type(TrbType::CommandCompletionEvent as u8); + ctrb.set_completion_code(completion_code); + ctrb.set_trb_type(TrbType::CommandCompletionEvent); ctrb.set_vf_id(0); ctrb.set_slot_id(slot_id); self.add_event(trb) @@ -126,9 +126,9 @@ impl Interrupter { let event_trb = trb.cast_mut::().map_err(Error::CastTrb)?; event_trb.set_trb_pointer(trb_pointer); event_trb.set_trb_transfer_length(transfer_length); - event_trb.set_completion_code(completion_code as u8); + event_trb.set_completion_code(completion_code); event_trb.set_event_data(event_data.into()); - event_trb.set_trb_type(TrbType::TransferEvent as u8); + event_trb.set_trb_type(TrbType::TransferEvent); event_trb.set_endpoint_id(endpoint_id); event_trb.set_slot_id(slot_id); self.add_event(trb) diff --git a/devices/src/usb/xhci/mod.rs b/devices/src/usb/xhci/mod.rs index c652e90..42cdef5 100644 --- a/devices/src/usb/xhci/mod.rs +++ b/devices/src/usb/xhci/mod.rs @@ -15,8 +15,6 @@ mod xhci; #[allow(dead_code)] mod xhci_abi; #[allow(dead_code)] -mod xhci_abi_schema; -#[allow(dead_code)] mod xhci_regs; pub mod scatter_gather_buffer; diff --git a/devices/src/usb/xhci/ring_buffer.rs b/devices/src/usb/xhci/ring_buffer.rs index 72c9ec0..a178ebb 100644 --- a/devices/src/usb/xhci/ring_buffer.rs +++ b/devices/src/usb/xhci/ring_buffer.rs @@ -67,14 +67,14 @@ impl RingBuffer { pub fn dequeue_transfer_descriptor(&mut self) -> Result> { let mut td: TransferDescriptor = TransferDescriptor::new(); while let Some(addressed_trb) = self.get_current_trb()? { - if let Ok(TrbType::Link) = addressed_trb.trb.trb_type() { + if let Ok(TrbType::Link) = addressed_trb.trb.get_trb_type() { let link_trb = addressed_trb .trb .cast::() .map_err(Error::CastTrb)?; self.dequeue_pointer = GuestAddress(link_trb.get_ring_segment_pointer()); self.consumer_cycle_state = - self.consumer_cycle_state != link_trb.get_toggle_cycle_bit(); + self.consumer_cycle_state != link_trb.get_toggle_cycle(); continue; } @@ -131,7 +131,7 @@ impl RingBuffer { usb_debug!("{}: trb read from memory {:?}", self.name.as_str(), trb); // If cycle bit of trb does not equal consumer cycle state, the ring is empty. // This trb is invalid. - if trb.get_cycle_bit() != self.consumer_cycle_state { + if trb.get_cycle() != self.consumer_cycle_state { usb_debug!( "cycle bit does not match, self cycle {}", self.consumer_cycle_state @@ -163,9 +163,9 @@ mod test { // trb 2 | trb 4 | trb 6 // l trb - l trb - l trb to 0x100 let mut trb = NormalTrb::new(); - trb.set_trb_type(TrbType::Normal as u8); + trb.set_trb_type(TrbType::Normal); trb.set_data_buffer(1); - trb.set_chain(1); + trb.set_chain(true); gm.write_obj_at_addr(trb.clone(), GuestAddress(0x100)) .unwrap(); @@ -174,7 +174,7 @@ mod test { .unwrap(); let mut ltrb = LinkTrb::new(); - ltrb.set_trb_type(TrbType::Link as u8); + ltrb.set_trb_type(TrbType::Link); ltrb.set_ring_segment_pointer(0x200); gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size)) .unwrap(); @@ -184,7 +184,7 @@ mod test { // Chain bit is false. trb.set_data_buffer(4); - trb.set_chain(0); + trb.set_chain(false); gm.write_obj_at_addr(trb, GuestAddress(0x200 + 1 * trb_size)) .unwrap(); @@ -193,12 +193,12 @@ mod test { .unwrap(); trb.set_data_buffer(5); - trb.set_chain(1); + trb.set_chain(true); gm.write_obj_at_addr(trb, GuestAddress(0x300)).unwrap(); // Chain bit is false. trb.set_data_buffer(6); - trb.set_chain(0); + trb.set_chain(false); gm.write_obj_at_addr(trb, GuestAddress(0x300 + 1 * trb_size)) .unwrap(); @@ -237,9 +237,9 @@ mod test { let mut transfer_ring = RingBuffer::new(String::new(), gm.clone()); let mut trb = NormalTrb::new(); - trb.set_trb_type(TrbType::Normal as u8); + trb.set_trb_type(TrbType::Normal); trb.set_data_buffer(1); - trb.set_chain(1); + trb.set_chain(true); gm.write_obj_at_addr(trb.clone(), GuestAddress(0x100)) .unwrap(); @@ -248,9 +248,9 @@ mod test { .unwrap(); let mut ltrb = LinkTrb::new(); - ltrb.set_trb_type(TrbType::Link as u8); + ltrb.set_trb_type(TrbType::Link); ltrb.set_ring_segment_pointer(0x200); - ltrb.set_toggle_cycle(1); + ltrb.set_toggle_cycle(true); gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size)) .unwrap(); diff --git a/devices/src/usb/xhci/ring_buffer_controller.rs b/devices/src/usb/xhci/ring_buffer_controller.rs index 201441a..8dd5426 100644 --- a/devices/src/usb/xhci/ring_buffer_controller.rs +++ b/devices/src/usb/xhci/ring_buffer_controller.rs @@ -238,7 +238,6 @@ where #[cfg(test)] mod tests { use super::*; - use crate::utils::FailHandle; use std::mem::size_of; use std::sync::mpsc::{channel, Sender}; @@ -253,7 +252,7 @@ mod tests { complete_event: EventFd, ) -> std::result::Result<(), ()> { for atrb in descriptor { - assert_eq!(atrb.trb.trb_type().unwrap(), TrbType::Normal); + assert_eq!(atrb.trb.get_trb_type().unwrap(), TrbType::Normal); self.sender.send(atrb.trb.get_parameter() as i32).unwrap(); } complete_event.write(1).unwrap(); @@ -271,9 +270,9 @@ mod tests { // trb 2 | trb 4 | trb 6 // l trb - l trb - l trb to 0x100 let mut trb = NormalTrb::new(); - trb.set_trb_type(TrbType::Normal as u8); + trb.set_trb_type(TrbType::Normal); trb.set_data_buffer(1); - trb.set_chain(1); + trb.set_chain(true); gm.write_obj_at_addr(trb.clone(), GuestAddress(0x100)) .unwrap(); @@ -282,7 +281,7 @@ mod tests { .unwrap(); let mut ltrb = LinkTrb::new(); - ltrb.set_trb_type(TrbType::Link as u8); + ltrb.set_trb_type(TrbType::Link); ltrb.set_ring_segment_pointer(0x200); gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size)) .unwrap(); @@ -292,7 +291,7 @@ mod tests { // Chain bit is false. trb.set_data_buffer(4); - trb.set_chain(0); + trb.set_chain(false); gm.write_obj_at_addr(trb, GuestAddress(0x200 + 1 * trb_size)) .unwrap(); @@ -301,12 +300,12 @@ mod tests { .unwrap(); trb.set_data_buffer(5); - trb.set_chain(1); + trb.set_chain(true); gm.write_obj_at_addr(trb, GuestAddress(0x300)).unwrap(); // Chain bit is false. trb.set_data_buffer(6); - trb.set_chain(0); + trb.set_chain(false); gm.write_obj_at_addr(trb, GuestAddress(0x300 + 1 * trb_size)) .unwrap(); diff --git a/devices/src/usb/xhci/scatter_gather_buffer.rs b/devices/src/usb/xhci/scatter_gather_buffer.rs index da43b33..0150e4f 100644 --- a/devices/src/usb/xhci/scatter_gather_buffer.rs +++ b/devices/src/usb/xhci/scatter_gather_buffer.rs @@ -3,6 +3,7 @@ // found in the LICENSE file. use super::xhci_abi::{Error as TrbError, NormalTrb, TransferDescriptor, TrbCast, TrbType}; +use bit_field::Error as BitFieldError; use std::fmt::{self, Display}; use sys_util::{GuestAddress, GuestMemory, GuestMemoryError}; @@ -10,7 +11,7 @@ use sys_util::{GuestAddress, GuestMemory, GuestMemoryError}; pub enum Error { ReadGuestMemory(GuestMemoryError), WriteGuestMemory(GuestMemoryError), - UnknownTrbType(TrbError), + UnknownTrbType(BitFieldError), CastTrb(TrbError), BadTrbType(TrbType), } @@ -42,7 +43,7 @@ impl ScatterGatherBuffer { /// Create a new buffer from transfer descriptor. pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result { for atrb in &td { - let trb_type = atrb.trb.trb_type().map_err(Error::UnknownTrbType)?; + let trb_type = atrb.trb.get_trb_type().map_err(Error::UnknownTrbType)?; if trb_type != TrbType::Normal && trb_type != TrbType::DataStage && trb_type != TrbType::Isoch @@ -138,21 +139,21 @@ mod test { let mut trb = Trb::new(); let ntrb = trb.cast_mut::().unwrap(); - ntrb.set_trb_type(TrbType::Normal as u8); + ntrb.set_trb_type(TrbType::Normal); ntrb.set_data_buffer(0x100); ntrb.set_trb_transfer_length(4); td.push(AddressedTrb { trb, gpa: 0 }); let mut trb = Trb::new(); let ntrb = trb.cast_mut::().unwrap(); - ntrb.set_trb_type(TrbType::Normal as u8); + ntrb.set_trb_type(TrbType::Normal); ntrb.set_data_buffer(0x200); ntrb.set_trb_transfer_length(2); td.push(AddressedTrb { trb, gpa: 0 }); let mut trb = Trb::new(); let ntrb = trb.cast_mut::().unwrap(); - ntrb.set_trb_type(TrbType::Normal as u8); + ntrb.set_trb_type(TrbType::Normal); ntrb.set_data_buffer(0x300); ntrb.set_trb_transfer_length(1); td.push(AddressedTrb { trb, gpa: 0 }); diff --git a/devices/src/usb/xhci/xhci_abi.rs b/devices/src/usb/xhci/xhci_abi.rs index 92f26ea..5a8748e 100644 --- a/devices/src/usb/xhci/xhci_abi.rs +++ b/devices/src/usb/xhci/xhci_abi.rs @@ -2,150 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -pub use super::xhci_abi_schema::*; +use bit_field::Error as BitFieldError; +use bit_field::*; use data_model::DataInit; use std::fmt::{self, Display}; +use sys_util::GuestAddress; -unsafe impl DataInit for Trb {} -unsafe impl DataInit for NormalTrb {} -unsafe impl DataInit for SetupStageTrb {} -unsafe impl DataInit for DataStageTrb {} -unsafe impl DataInit for StatusStageTrb {} -unsafe impl DataInit for IsochTrb {} -unsafe impl DataInit for LinkTrb {} -unsafe impl DataInit for EventDataTrb {} -unsafe impl DataInit for NoopTrb {} -unsafe impl DataInit for DisableSlotCommandTrb {} -unsafe impl DataInit for AddressDeviceCommandTrb {} -unsafe impl DataInit for ConfigureEndpointCommandTrb {} -unsafe impl DataInit for EvaluateContextCommandTrb {} -unsafe impl DataInit for ResetEndpointCommandTrb {} -unsafe impl DataInit for StopEndpointCommandTrb {} -unsafe impl DataInit for SetTRDequeuePointerCommandTrb {} -unsafe impl DataInit for ResetDeviceCommandTrb {} -unsafe impl DataInit for TransferEventTrb {} -unsafe impl DataInit for CommandCompletionEventTrb {} -unsafe impl DataInit for PortStatusChangeEventTrb {} -unsafe impl DataInit for EventRingSegmentTableEntry {} -unsafe impl DataInit for InputControlContext {} -unsafe impl DataInit for SlotContext {} -unsafe impl DataInit for EndpointContext {} - -unsafe impl DataInit for DeviceContext {} -unsafe impl DataInit for AddressedTrb {} - -unsafe impl TrbCast for Trb {} -unsafe impl TrbCast for NormalTrb {} -unsafe impl TrbCast for SetupStageTrb {} -unsafe impl TrbCast for DataStageTrb {} -unsafe impl TrbCast for StatusStageTrb {} -unsafe impl TrbCast for IsochTrb {} -unsafe impl TrbCast for LinkTrb {} -unsafe impl TrbCast for EventDataTrb {} -unsafe impl TrbCast for NoopTrb {} -unsafe impl TrbCast for DisableSlotCommandTrb {} -unsafe impl TrbCast for AddressDeviceCommandTrb {} -unsafe impl TrbCast for ConfigureEndpointCommandTrb {} -unsafe impl TrbCast for EvaluateContextCommandTrb {} -unsafe impl TrbCast for ResetEndpointCommandTrb {} -unsafe impl TrbCast for StopEndpointCommandTrb {} -unsafe impl TrbCast for SetTRDequeuePointerCommandTrb {} -unsafe impl TrbCast for ResetDeviceCommandTrb {} -unsafe impl TrbCast for TransferEventTrb {} -unsafe impl TrbCast for CommandCompletionEventTrb {} -unsafe impl TrbCast for PortStatusChangeEventTrb {} - -/// Associate real type of trb. -pub trait TypedTrb { - const TY: TrbType; -} - -impl TypedTrb for Trb { - const TY: TrbType = TrbType::Reserved; -} - -impl TypedTrb for NormalTrb { - const TY: TrbType = TrbType::Normal; -} - -impl TypedTrb for SetupStageTrb { - const TY: TrbType = TrbType::SetupStage; -} - -impl TypedTrb for DataStageTrb { - const TY: TrbType = TrbType::DataStage; -} - -impl TypedTrb for StatusStageTrb { - const TY: TrbType = TrbType::StatusStage; -} - -impl TypedTrb for IsochTrb { - const TY: TrbType = TrbType::Isoch; -} - -impl TypedTrb for LinkTrb { - const TY: TrbType = TrbType::Link; -} +use std; -impl TypedTrb for EventDataTrb { - const TY: TrbType = TrbType::EventData; -} - -impl TypedTrb for NoopTrb { - const TY: TrbType = TrbType::Noop; -} - -impl TypedTrb for DisableSlotCommandTrb { - const TY: TrbType = TrbType::DisableSlotCommand; -} - -impl TypedTrb for AddressDeviceCommandTrb { - const TY: TrbType = TrbType::AddressDeviceCommand; -} - -impl TypedTrb for ConfigureEndpointCommandTrb { - const TY: TrbType = TrbType::ConfigureEndpointCommand; -} - -impl TypedTrb for EvaluateContextCommandTrb { - const TY: TrbType = TrbType::EvaluateContextCommand; -} - -impl TypedTrb for ResetEndpointCommandTrb { - const TY: TrbType = TrbType::ResetEndpointCommand; -} - -impl TypedTrb for StopEndpointCommandTrb { - const TY: TrbType = TrbType::StopEndpointCommand; -} - -impl TypedTrb for SetTRDequeuePointerCommandTrb { - const TY: TrbType = TrbType::SetTRDequeuePointerCommand; -} - -impl TypedTrb for ResetDeviceCommandTrb { - const TY: TrbType = TrbType::ResetDeviceCommand; -} - -impl TypedTrb for TransferEventTrb { - const TY: TrbType = TrbType::TransferEvent; -} - -impl TypedTrb for CommandCompletionEventTrb { - const TY: TrbType = TrbType::CommandCompletionEvent; -} - -impl TypedTrb for PortStatusChangeEventTrb { - const TY: TrbType = TrbType::PortStatusChangeEvent; -} - -#[derive(Debug, PartialEq)] +#[derive(Debug)] pub enum Error { - UnknownTrbType(u8), - UnknownCompletionCode(u8), - UnknownDeviceSlotState(u8), - UnknownEndpointState(u8), + UnknownTrbType(BitFieldError), CannotCastTrb, } @@ -156,52 +23,114 @@ impl Display for Error { use self::Error::*; match self { - UnknownTrbType(v) => write!(f, "we got an unknown trb type value: {}", v), - UnknownCompletionCode(v) => write!(f, "we got an unknown trb completion code: {}", v), - UnknownDeviceSlotState(v) => write!(f, "we got and unknown device slot state: {}", v), - UnknownEndpointState(v) => write!(f, "we got and unknown endpoint state: {}", v), + UnknownTrbType(e) => write!(f, "we got an unknown trb type value: {}", e), CannotCastTrb => write!(f, "cannot cast trb from raw memory"), } } } -/// All trb structs have the same size. One trb could be safely casted to another, though the -/// values might be invalid. -pub unsafe trait TrbCast: DataInit + TypedTrb { - fn cast(&self) -> Result<&T> { - T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb) - } +// Fixed size of all TRB types. +const TRB_SIZE: usize = 16; - fn cast_mut(&mut self) -> Result<&mut T> { - T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb) - } +// Size of segment table. +const SEGMENT_TABLE_SIZE: usize = 16; - fn checked_cast(&self) -> Result<&T> { - if Trb::from_slice(self.as_slice()) - .ok_or(Error::CannotCastTrb)? - .trb_type()? - != T::TY - { - return Err(Error::CannotCastTrb); - } - T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb) +/// All kinds of trb. +#[bitfield] +#[bits = 6] +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum TrbType { + 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, + NoopCommand = 23, + TransferEvent = 32, + CommandCompletionEvent = 33, + PortStatusChangeEvent = 34, +} + +/// Completion code of trb types. +#[bitfield] +#[bits = 8] +#[derive(PartialEq, Debug)] +pub enum TrbCompletionCode { + Success = 1, + TransactionError = 4, + TrbError = 5, + NoSlotsAvailableError = 9, + SlotNotEnabledError = 11, + ShortPacket = 13, + ContextStateError = 19, +} + +/// State of device slot. +#[bitfield] +#[bits = 5] +#[derive(PartialEq, Debug)] +pub enum DeviceSlotState { + // The same value (0) is used for both the enabled and disabled states. See + // xhci spec table 60. + DisabledOrEnabled = 0, + Default = 1, + Addressed = 2, + Configured = 3, +} + +/// State of endpoint. +#[bitfield] +#[bits = 3] +#[derive(PartialEq, Debug)] +pub enum EndpointState { + Disabled = 0, + Running = 1, +} + +#[bitfield] +#[bits = 60] +#[derive(PartialEq, Debug)] +pub struct DequeuePtr(u64); + +impl DequeuePtr { + pub fn new(addr: GuestAddress) -> Self { + DequeuePtr(addr.0 >> 4) } - fn checked_mut_cast(&mut self) -> Result<&mut T> { - if Trb::from_slice(self.as_slice()) - .ok_or(Error::CannotCastTrb)? - .trb_type()? - != T::TY - { - return Err(Error::CannotCastTrb); - } - T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb) + // Get the guest physical address. + pub fn get_gpa(&self) -> GuestAddress { + GuestAddress(self.0 << 4) } } +// Generic TRB struct containing only fields common to all types. +#[bitfield] +#[derive(Clone, Copy, PartialEq)] +pub struct Trb { + parameter: B64, + status: B32, + cycle: bool, + flags: B9, + trb_type: TrbType, + control: B16, +} + impl Trb { fn fmt_helper(&self, f: &mut fmt::Formatter) -> Result { - match self.trb_type()? { + match self.get_trb_type().map_err(Error::UnknownTrbType)? { TrbType::Reserved => Ok(write!(f, "reserved trb type")), TrbType::Normal => { let t = self.cast::()?; @@ -284,6 +213,7 @@ impl Trb { } } } + impl Display for Trb { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.fmt_helper(f) { @@ -294,34 +224,16 @@ impl Display for Trb { } impl Trb { - /// Get trb type. - pub fn trb_type(&self) -> Result { - TrbType::from_raw(self.get_trb_type()) - } - - /// Get cycle bit. - pub fn get_cycle_bit(&self) -> bool { - self.get_cycle() != 0 - } - - /// Set cyle bit. - pub fn set_cycle_bit(&mut self, b: bool) { - match b { - true => self.set_cycle(1u8), - false => self.set_cycle(0u8), - } - } - /// Get chain bit. pub fn get_chain_bit(&self) -> Result { - Ok(match self.trb_type() { - Ok(TrbType::Normal) => self.cast::()?.get_chain() != 0, - Ok(TrbType::DataStage) => self.cast::()?.get_chain() != 0, - Ok(TrbType::StatusStage) => self.cast::()?.get_chain() != 0, - Ok(TrbType::Isoch) => self.cast::()?.get_chain() != 0, - Ok(TrbType::Noop) => self.cast::()?.get_chain() != 0, - Ok(TrbType::Link) => self.cast::()?.get_chain() != 0, - Ok(TrbType::EventData) => self.cast::()?.get_chain() != 0, + Ok(match self.get_trb_type() { + Ok(TrbType::Normal) => self.cast::()?.get_chain(), + Ok(TrbType::DataStage) => self.cast::()?.get_chain(), + Ok(TrbType::StatusStage) => self.cast::()?.get_chain(), + Ok(TrbType::Isoch) => self.cast::()?.get_chain(), + Ok(TrbType::Noop) => self.cast::()?.get_chain(), + Ok(TrbType::Link) => self.cast::()?.get_chain(), + Ok(TrbType::EventData) => self.cast::()?.get_chain(), _ => false, }) } @@ -334,7 +246,7 @@ impl Trb { /// Only some of trb types could appear in transfer ring. pub fn can_be_in_transfer_ring(&self) -> Result { - match self.trb_type()? { + match self.get_trb_type().map_err(Error::UnknownTrbType)? { TrbType::Normal | TrbType::SetupStage | TrbType::DataStage @@ -350,7 +262,7 @@ impl Trb { /// Length of this transfer. pub fn transfer_length(&self) -> Result { const STATUS_TRANSFER_LENGTH_MASK: u32 = 0x1ffff; - match self.trb_type()? { + match self.get_trb_type().map_err(Error::UnknownTrbType)? { TrbType::Normal | TrbType::SetupStage | TrbType::DataStage | TrbType::Isoch => { Ok(self.get_status() & STATUS_TRANSFER_LENGTH_MASK) } @@ -373,7 +285,7 @@ impl Trb { /// Returns true if this trb is immediate data. pub fn immediate_data(&self) -> Result { const FLAGS_IMMEDIATE_DATA_MASK: u16 = 0x20; - match self.trb_type()? { + match self.get_trb_type().map_err(Error::UnknownTrbType)? { TrbType::Normal | TrbType::SetupStage | TrbType::DataStage | TrbType::Isoch => { Ok((self.get_flags() & FLAGS_IMMEDIATE_DATA_MASK) != 0) } @@ -382,184 +294,504 @@ impl Trb { } } -impl LinkTrb { - /// Get cycle. - pub fn get_cycle_bit(&self) -> bool { - self.get_cycle() != 0 - } +#[bitfield] +#[derive(Clone, Copy)] +pub struct NormalTrb { + data_buffer: B64, + trb_transfer_length: B17, + td_size: B5, + interrupter_target: B10, + cycle: bool, + evaluate_next_trb: B1, + interrupt_on_short_packet: B1, + no_snoop: B1, + chain: bool, + interrupt_on_completion: B1, + immediate_data: B1, + reserved: B2, + block_event_interrupt: B1, + trb_type: TrbType, + reserved1: B16, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct SetupStageTrb { + request_type: B8, + request: B8, + value: B16, + index: B16, + length: B16, + trb_transfer_length: B17, + reserved0: B5, + interrupter_target: B10, + cycle: bool, + reserved1: B4, + interrupt_on_completion: B1, + immediate_data: B1, + reserved2: B3, + trb_type: TrbType, + transfer_type: B2, + reserved3: B14, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct DataStageTrb { + data_buffer_pointer: B64, + trb_transfer_length: B17, + td_size: B5, + interrupter_target: B10, + cycle: bool, + evaluate_next_trb: B1, + interrupt_on_short_packet: B1, + no_snoop: B1, + chain: bool, + interrupt_on_completion: B1, + immediate_data: B1, + reserved0: B3, + trb_type: TrbType, + direction: B1, + reserved1: B15, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct StatusStageTrb { + reserved0: B64, + reserved1: B22, + interrupter_target: B10, + cycle: bool, + evaluate_next_trb: B1, + reserved2: B2, + chain: bool, + interrupt_on_completion: B1, + reserved3: B4, + trb_type: TrbType, + direction: B1, + reserved4: B15, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct IsochTrb { + data_buffer_pointer: B64, + trb_transfer_length: B17, + td_size: B5, + interrupter_target: B10, + cycle: bool, + evaulate_nex_trb: B1, + interrupt_on_short_packet: B1, + no_snoop: B1, + chain: bool, + interrupt_on_completion: B1, + immediate_data: B1, + transfer_burst_count: B2, + block_event_interrupt: B1, + trb_type: TrbType, + tlbpc: B4, + frame_id: B11, + sia: B1, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct LinkTrb { + ring_segment_pointer: B64, + reserved0: B22, + interrupter_target: B10, + cycle: bool, + toggle_cycle: bool, + reserved1: B2, + chain: bool, + interrupt_on_completion: bool, + reserved2: B4, + trb_type: TrbType, + reserved3: B16, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct EventDataTrb { + event_data: B64, + reserved0: B22, + interrupter_target: B10, + cycle: bool, + evaluate_next_trb: B1, + reserved1: B2, + chain: bool, + interrupt_on_completion: B1, + reserved2: B3, + block_event_interrupt: B1, + trb_type: TrbType, + reserved3: B16, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct NoopTrb { + reserved0: B64, + reserved1: B22, + interrupter_target: B10, + cycle: bool, + evaluate_next_trb: B1, + reserved2: B2, + chain: bool, + interrupt_on_completion: B1, + reserved3: B4, + trb_type: TrbType, + reserved4: B16, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct DisableSlotCommandTrb { + reserved0: B32, + reserved1: B32, + reserved2: B32, + cycle: bool, + reserved3: B9, + trb_type: TrbType, + reserved4: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct AddressDeviceCommandTrb { + input_context_pointer: B64, + reserved: B32, + cycle: bool, + reserved2: B8, + block_set_address_request: bool, + trb_type: TrbType, + reserved3: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct ConfigureEndpointCommandTrb { + input_context_pointer: B64, + reserved0: B32, + cycle: bool, + reserved1: B8, + deconfigure: bool, + trb_type: TrbType, + reserved2: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct EvaluateContextCommandTrb { + input_context_pointer: B64, + reserved0: B32, + cycle: bool, + reserved1: B9, + trb_type: TrbType, + reserved2: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct ResetEndpointCommandTrb { + reserved0: B32, + reserved1: B32, + reserved2: B32, + cycle: bool, + reserved3: B8, + transfer_state_preserve: B1, + trb_type: TrbType, + endpoint_id: B5, + reserved4: B3, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct StopEndpointCommandTrb { + reserved0: B32, + reserved1: B32, + reserved2: B32, + cycle: bool, + reserved3: B9, + trb_type: TrbType, + endpoint_id: B5, + reserved4: B2, + suspend: B1, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct SetTRDequeuePointerCommandTrb { + dequeue_cycle_state: bool, + stream_context_type: B3, + dequeue_ptr: DequeuePtr, + reserved0: B16, + stream_id: B16, + cycle: bool, + reserved1: B9, + trb_type: TrbType, + endpoint_id: B5, + reserved3: B2, + suspend: B1, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct ResetDeviceCommandTrb { + reserved0: B32, + reserved1: B32, + reserved2: B32, + cycle: bool, + reserved3: B9, + trb_type: TrbType, + reserved4: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct TransferEventTrb { + trb_pointer: B64, + trb_transfer_length: B24, + completion_code: TrbCompletionCode, + cycle: bool, + reserved0: B1, + event_data: B1, + reserved1: B7, + trb_type: TrbType, + endpoint_id: B5, + reserved2: B3, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct CommandCompletionEventTrb { + trb_pointer: B64, + command_completion_parameter: B24, + completion_code: TrbCompletionCode, + cycle: bool, + reserved: B9, + trb_type: TrbType, + vf_id: B8, + slot_id: B8, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct PortStatusChangeEventTrb { + reserved0: B24, + port_id: B8, + reserved1: B32, + reserved2: B24, + completion_code: TrbCompletionCode, + cycle: bool, + reserved3: B9, + trb_type: TrbType, + reserved4: B16, +} - /// Get toggle cycle. - pub fn get_toggle_cycle_bit(&self) -> bool { - self.get_toggle_cycle() != 0 - } +/// Associate real type of trb. +pub trait TypedTrb { + const TY: TrbType; +} - /// set chain status. - pub fn set_chain_bit(&mut self, v: bool) { - self.set_chain(v as u8); - } +impl TypedTrb for Trb { + const TY: TrbType = TrbType::Reserved; +} - /// Get chain status. - pub fn get_chain_bit(&self) -> bool { - self.get_chain() != 0 - } +impl TypedTrb for NormalTrb { + const TY: TrbType = TrbType::Normal; +} - /// Get interrupt on completion. - pub fn interrupt_on_completion(&self) -> bool { - self.get_interrupt_on_completion() != 0 - } +impl TypedTrb for SetupStageTrb { + const TY: TrbType = TrbType::SetupStage; } -/// Trait for enum that could be converted from raw u8. -pub trait PrimitiveTrbEnum: Sized { - fn from_raw(val: u8) -> Result; +impl TypedTrb for DataStageTrb { + const TY: TrbType = TrbType::DataStage; } -/// All kinds of trb. -#[derive(PartialEq, Debug)] -pub enum TrbType { - 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, - NoopCommand = 23, - TransferEvent = 32, - CommandCompletionEvent = 33, - PortStatusChangeEvent = 34, +impl TypedTrb for StatusStageTrb { + const TY: TrbType = TrbType::StatusStage; } -impl PrimitiveTrbEnum for TrbType { - fn from_raw(val: u8) -> Result { - match val { - 0 => Ok(TrbType::Reserved), - 1 => Ok(TrbType::Normal), - 2 => Ok(TrbType::SetupStage), - 3 => Ok(TrbType::DataStage), - 4 => Ok(TrbType::StatusStage), - 5 => Ok(TrbType::Isoch), - 6 => Ok(TrbType::Link), - 7 => Ok(TrbType::EventData), - 8 => Ok(TrbType::Noop), - 9 => Ok(TrbType::EnableSlotCommand), - 10 => Ok(TrbType::DisableSlotCommand), - 11 => Ok(TrbType::AddressDeviceCommand), - 12 => Ok(TrbType::ConfigureEndpointCommand), - 13 => Ok(TrbType::EvaluateContextCommand), - 14 => Ok(TrbType::ResetEndpointCommand), - 15 => Ok(TrbType::StopEndpointCommand), - 16 => Ok(TrbType::SetTRDequeuePointerCommand), - 17 => Ok(TrbType::ResetDeviceCommand), - 23 => Ok(TrbType::NoopCommand), - 32 => Ok(TrbType::TransferEvent), - 33 => Ok(TrbType::CommandCompletionEvent), - 34 => Ok(TrbType::PortStatusChangeEvent), - v => Err(Error::UnknownTrbType(v)), - } - } +impl TypedTrb for IsochTrb { + const TY: TrbType = TrbType::Isoch; } -/// Completion code of trb types. -pub enum TrbCompletionCode { - Success = 1, - TransactionError = 4, - TrbError = 5, - NoSlotsAvailableError = 9, - SlotNotEnabledError = 11, - ShortPacket = 13, - ContextStateError = 19, +impl TypedTrb for LinkTrb { + const TY: TrbType = TrbType::Link; } -impl PrimitiveTrbEnum for TrbCompletionCode { - fn from_raw(val: u8) -> Result { - match val { - 1 => Ok(TrbCompletionCode::Success), - 4 => Ok(TrbCompletionCode::TransactionError), - 5 => Ok(TrbCompletionCode::TrbError), - 9 => Ok(TrbCompletionCode::NoSlotsAvailableError), - 11 => Ok(TrbCompletionCode::SlotNotEnabledError), - 13 => Ok(TrbCompletionCode::ShortPacket), - 19 => Ok(TrbCompletionCode::ContextStateError), - v => Err(Error::UnknownCompletionCode(v)), - } - } +impl TypedTrb for EventDataTrb { + const TY: TrbType = TrbType::EventData; } -/// State of device slot. -#[derive(PartialEq, Debug)] -pub enum DeviceSlotState { - // The same value (0) is used for both the enabled and disabled states. See - // xhci spec table 60. - DisabledOrEnabled = 0, - Default = 1, - Addressed = 2, - Configured = 3, +impl TypedTrb for NoopTrb { + const TY: TrbType = TrbType::Noop; } -impl PrimitiveTrbEnum for DeviceSlotState { - fn from_raw(val: u8) -> Result { - match val { - 0 => Ok(DeviceSlotState::DisabledOrEnabled), - 1 => Ok(DeviceSlotState::Default), - 2 => Ok(DeviceSlotState::Addressed), - 3 => Ok(DeviceSlotState::Configured), - v => Err(Error::UnknownDeviceSlotState(v)), - } - } +impl TypedTrb for DisableSlotCommandTrb { + const TY: TrbType = TrbType::DisableSlotCommand; } -impl SlotContext { - /// Set slot context state. - pub fn state(&self) -> Result { - DeviceSlotState::from_raw(self.get_slot_state()) - } +impl TypedTrb for AddressDeviceCommandTrb { + const TY: TrbType = TrbType::AddressDeviceCommand; +} - /// Get slot context state. - pub fn set_state(&mut self, state: DeviceSlotState) { - self.set_slot_state(state as u8); - } +impl TypedTrb for ConfigureEndpointCommandTrb { + const TY: TrbType = TrbType::ConfigureEndpointCommand; } -/// State of endpoint. -pub enum EndpointState { - Disabled = 0, - Running = 1, +impl TypedTrb for EvaluateContextCommandTrb { + const TY: TrbType = TrbType::EvaluateContextCommand; } -impl PrimitiveTrbEnum for EndpointState { - fn from_raw(val: u8) -> Result { - match val { - 0 => Ok(EndpointState::Disabled), - 1 => Ok(EndpointState::Running), - v => Err(Error::UnknownEndpointState(v)), - } - } +impl TypedTrb for ResetEndpointCommandTrb { + const TY: TrbType = TrbType::ResetEndpointCommand; +} + +impl TypedTrb for StopEndpointCommandTrb { + const TY: TrbType = TrbType::StopEndpointCommand; +} + +impl TypedTrb for SetTRDequeuePointerCommandTrb { + const TY: TrbType = TrbType::SetTRDequeuePointerCommand; +} + +impl TypedTrb for ResetDeviceCommandTrb { + const TY: TrbType = TrbType::ResetDeviceCommand; } -impl EndpointContext { - /// Get endpoint context state. - pub fn state(&self) -> Result { - EndpointState::from_raw(self.get_endpoint_state()) +impl TypedTrb for TransferEventTrb { + const TY: TrbType = TrbType::TransferEvent; +} + +impl TypedTrb for CommandCompletionEventTrb { + const TY: TrbType = TrbType::CommandCompletionEvent; +} + +impl TypedTrb for PortStatusChangeEventTrb { + const TY: TrbType = TrbType::PortStatusChangeEvent; +} + +/// All trb structs have the same size. One trb could be safely casted to another, though the +/// values might be invalid. +pub unsafe trait TrbCast: DataInit + TypedTrb { + fn cast(&self) -> Result<&T> { + T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb) + } + + fn cast_mut(&mut self) -> Result<&mut T> { + T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb) } - /// Set endpoint context state. - pub fn set_state(&mut self, state: EndpointState) { - self.set_endpoint_state(state as u8); + fn checked_cast(&self) -> Result<&T> { + if Trb::from_slice(self.as_slice()) + .ok_or(Error::CannotCastTrb)? + .get_trb_type() + .map_err(Error::UnknownTrbType)? + != T::TY + { + return Err(Error::CannotCastTrb); + } + T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb) + } + + fn checked_mut_cast(&mut self) -> Result<&mut T> { + if Trb::from_slice(self.as_slice()) + .ok_or(Error::CannotCastTrb)? + .get_trb_type() + .map_err(Error::UnknownTrbType)? + != T::TY + { + return Err(Error::CannotCastTrb); + } + T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb) } } +unsafe impl DataInit for Trb {} +unsafe impl DataInit for NormalTrb {} +unsafe impl DataInit for SetupStageTrb {} +unsafe impl DataInit for DataStageTrb {} +unsafe impl DataInit for StatusStageTrb {} +unsafe impl DataInit for IsochTrb {} +unsafe impl DataInit for LinkTrb {} +unsafe impl DataInit for EventDataTrb {} +unsafe impl DataInit for NoopTrb {} +unsafe impl DataInit for DisableSlotCommandTrb {} +unsafe impl DataInit for AddressDeviceCommandTrb {} +unsafe impl DataInit for ConfigureEndpointCommandTrb {} +unsafe impl DataInit for EvaluateContextCommandTrb {} +unsafe impl DataInit for ResetEndpointCommandTrb {} +unsafe impl DataInit for StopEndpointCommandTrb {} +unsafe impl DataInit for SetTRDequeuePointerCommandTrb {} +unsafe impl DataInit for ResetDeviceCommandTrb {} +unsafe impl DataInit for TransferEventTrb {} +unsafe impl DataInit for CommandCompletionEventTrb {} +unsafe impl DataInit for PortStatusChangeEventTrb {} +unsafe impl DataInit for EventRingSegmentTableEntry {} +unsafe impl DataInit for InputControlContext {} +unsafe impl DataInit for SlotContext {} +unsafe impl DataInit for EndpointContext {} + +unsafe impl DataInit for DeviceContext {} +unsafe impl DataInit for AddressedTrb {} + +unsafe impl TrbCast for Trb {} +unsafe impl TrbCast for NormalTrb {} +unsafe impl TrbCast for SetupStageTrb {} +unsafe impl TrbCast for DataStageTrb {} +unsafe impl TrbCast for StatusStageTrb {} +unsafe impl TrbCast for IsochTrb {} +unsafe impl TrbCast for LinkTrb {} +unsafe impl TrbCast for EventDataTrb {} +unsafe impl TrbCast for NoopTrb {} +unsafe impl TrbCast for DisableSlotCommandTrb {} +unsafe impl TrbCast for AddressDeviceCommandTrb {} +unsafe impl TrbCast for ConfigureEndpointCommandTrb {} +unsafe impl TrbCast for EvaluateContextCommandTrb {} +unsafe impl TrbCast for ResetEndpointCommandTrb {} +unsafe impl TrbCast for StopEndpointCommandTrb {} +unsafe impl TrbCast for SetTRDequeuePointerCommandTrb {} +unsafe impl TrbCast for ResetDeviceCommandTrb {} +unsafe impl TrbCast for TransferEventTrb {} +unsafe impl TrbCast for CommandCompletionEventTrb {} +unsafe impl TrbCast for PortStatusChangeEventTrb {} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct EventRingSegmentTableEntry { + ring_segment_base_address: B64, + ring_segment_size: B16, + reserved2: B48, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct InputControlContext { + // Xhci spec 6.2.5.1. + drop_context_flags: B32, + add_context_flags: B32, + reserved0: B32, + reserved1: B32, + reserved2: B32, + reserved3: B32, + reserved4: B32, + configuration_value: B8, + interface_number: B8, + alternate_setting: B8, + reserved5: B8, +} + impl InputControlContext { /// Get drop context flag. pub fn drop_context_flag(&self, idx: u8) -> bool { @@ -571,3 +803,127 @@ impl InputControlContext { (self.get_add_context_flags() & (1 << idx)) != 0 } } + +// Size of device context entries (SlotContext and EndpointContext). +pub const DEVICE_CONTEXT_ENTRY_SIZE: usize = 32usize; + +#[bitfield] +#[derive(Clone, Copy)] +pub struct SlotContext { + route_string: B20, + speed: B4, + reserved1: B1, + mtt: B1, + hub: B1, + context_entries: B5, + max_exit_latency: B16, + root_hub_port_number: B8, + num_ports: B8, + tt_hub_slot_id: B8, + tt_port_number: B8, + tt_think_time: B2, + reserved2: B4, + interrupter_target: B10, + usb_device_address: B8, + reserved3: B19, + slot_state: DeviceSlotState, + reserved4: B32, + reserved5: B32, + reserved6: B32, + reserved7: B32, +} + +#[bitfield] +#[derive(Clone, Copy)] +pub struct EndpointContext { + endpoint_state: EndpointState, + reserved1: B5, + mult: B2, + max_primary_streams: B5, + linear_stream_array: B1, + interval: B8, + max_esit_payload_hi: B8, + reserved2: B1, + error_count: B2, + endpoint_type: B3, + reserved3: B1, + host_initiate_disable: B1, + max_burst_size: B8, + max_packet_size: B16, + dequeue_cycle_state: bool, + reserved4: B3, + tr_dequeue_pointer: DequeuePtr, + average_trb_length: B16, + max_esit_payload_lo: B16, + reserved5: B32, + reserved6: B32, + reserved7: B32, +} + +/// Device context. +#[derive(Clone, Copy, Debug)] +pub struct DeviceContext { + pub slot_context: SlotContext, + pub endpoint_context: [EndpointContext; 31], +} + +/// POD struct associates a TRB with its address in guest memory. This is +/// useful because transfer and command completion event TRBs must contain +/// pointers to the original TRB that generated the event. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct AddressedTrb { + pub trb: Trb, + pub gpa: u64, +} + +pub type TransferDescriptor = Vec; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn check_struct_sizes() { + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!( + std::mem::size_of::(), + TRB_SIZE + ); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + assert_eq!(std::mem::size_of::(), TRB_SIZE); + + assert_eq!( + std::mem::size_of::(), + SEGMENT_TABLE_SIZE + ); + assert_eq!(std::mem::size_of::(), 32); + assert_eq!( + std::mem::size_of::(), + DEVICE_CONTEXT_ENTRY_SIZE + ); + assert_eq!( + std::mem::size_of::(), + DEVICE_CONTEXT_ENTRY_SIZE + ); + assert_eq!( + std::mem::size_of::(), + 32 * DEVICE_CONTEXT_ENTRY_SIZE + ); + } +} diff --git a/devices/src/usb/xhci/xhci_abi_schema.rs b/devices/src/usb/xhci/xhci_abi_schema.rs deleted file mode 100644 index 91ca7c1..0000000 --- a/devices/src/usb/xhci/xhci_abi_schema.rs +++ /dev/null @@ -1,543 +0,0 @@ -// Copyright 2018 The Chromium OS Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -use bit_field::*; -use std; - -// TODO(jkwang) move these to bitfield crate. -type B0 = BitField0; -type B1 = BitField1; -type B2 = BitField2; -type B3 = BitField3; -type B4 = BitField4; -type B5 = BitField5; -type B6 = BitField6; -type B7 = BitField7; -type B8 = BitField8; -type B9 = BitField9; -type B10 = BitField10; -type B11 = BitField11; -type B12 = BitField12; -type B13 = BitField13; -type B14 = BitField14; -type B15 = BitField15; -type B16 = BitField16; -type B17 = BitField17; -type B18 = BitField18; -type B19 = BitField19; -type B20 = BitField20; -type B21 = BitField21; -type B22 = BitField22; -type B23 = BitField23; -type B24 = BitField24; -type B25 = BitField25; -type B26 = BitField26; -type B27 = BitField27; -type B28 = BitField28; -type B29 = BitField29; -type B30 = BitField30; -type B31 = BitField31; -type B32 = BitField32; -type B33 = BitField33; -type B34 = BitField34; -type B35 = BitField35; -type B36 = BitField36; -type B37 = BitField37; -type B38 = BitField38; -type B39 = BitField39; -type B40 = BitField40; -type B41 = BitField41; -type B42 = BitField42; -type B43 = BitField43; -type B44 = BitField44; -type B45 = BitField45; -type B46 = BitField46; -type B47 = BitField47; -type B48 = BitField48; -type B49 = BitField49; -type B50 = BitField50; -type B51 = BitField51; -type B52 = BitField52; -type B53 = BitField53; -type B54 = BitField54; -type B55 = BitField55; -type B56 = BitField56; -type B57 = BitField57; -type B58 = BitField58; -type B59 = BitField59; -type B60 = BitField60; -type B61 = BitField61; -type B62 = BitField62; -type B63 = BitField63; -type B64 = BitField64; - -// Fixed size of all TRB types. -const TRB_SIZE: usize = 16; - -// Size of segment table. -const SEGMENT_TABLE_SIZE: usize = 16; - -// Generic TRB struct containing only fields common to all types. -#[bitfield] -#[derive(Clone, Copy, PartialEq)] -pub struct Trb { - parameter: B64, - status: B32, - cycle: B1, - flags: B9, - trb_type: B6, - control: B16, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct NormalTrb { - data_buffer: B64, - trb_transfer_length: B17, - td_size: B5, - interrupter_target: B10, - cycle: B1, - evaluate_next_trb: B1, - interrupt_on_short_packet: B1, - no_snoop: B1, - chain: B1, - interrupt_on_completion: B1, - immediate_data: B1, - reserved: B2, - block_event_interrupt: B1, - trb_type: B6, - reserved1: B16, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct SetupStageTrb { - request_type: B8, - request: B8, - value: B16, - index: B16, - length: B16, - trb_transfer_length: B17, - reserved0: B5, - interrupter_target: B10, - cycle: B1, - reserved1: B4, - interrupt_on_completion: B1, - immediate_data: B1, - reserved2: B3, - trb_type: B6, - transfer_type: B2, - reserved3: B14, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct DataStageTrb { - data_buffer_pointer: B64, - trb_transfer_length: B17, - td_size: B5, - interrupter_target: B10, - cycle: B1, - evaluate_next_trb: B1, - interrupt_on_short_packet: B1, - no_snoop: B1, - chain: B1, - interrupt_on_completion: B1, - immediate_data: B1, - reserved0: B3, - trb_type: B6, - direction: B1, - reserved1: B15, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct StatusStageTrb { - reserved0: B64, - reserved1: B22, - interrupter_target: B10, - cycle: B1, - evaluate_next_trb: B1, - reserved2: B2, - chain: B1, - interrupt_on_completion: B1, - reserved3: B4, - trb_type: B6, - direction: B1, - reserved4: B15, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct IsochTrb { - data_buffer_pointer: B64, - trb_transfer_length: B17, - td_size: B5, - interrupter_target: B10, - cycle: B1, - evaulate_nex_trb: B1, - interrupt_on_short_packet: B1, - no_snoop: B1, - chain: B1, - interrupt_on_completion: B1, - immediate_data: B1, - transfer_burst_count: B2, - block_event_interrupt: B1, - trb_type: B6, - tlbpc: B4, - frame_id: B11, - sia: B1, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct LinkTrb { - ring_segment_pointer: B64, - reserved0: B22, - interrupter_target: B10, - cycle: B1, - toggle_cycle: B1, - reserved1: B2, - chain: B1, - interrupt_on_completion: B1, - reserved2: B4, - trb_type: B6, - reserved3: B16, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct EventDataTrb { - event_data: B64, - reserved0: B22, - interrupter_target: B10, - cycle: B1, - evaluate_next_trb: B1, - reserved1: B2, - chain: B1, - interrupt_on_completion: B1, - reserved2: B3, - block_event_interrupt: B1, - trb_type: B6, - reserved3: B16, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct NoopTrb { - reserved0: B64, - reserved1: B22, - interrupter_target: B10, - cycle: B1, - evaluate_next_trb: B1, - reserved2: B2, - chain: B1, - interrupt_on_completion: B1, - reserved3: B4, - trb_type: B6, - reserved4: B16, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct DisableSlotCommandTrb { - reserved0: B32, - reserved1: B32, - reserved2: B32, - cycle: B1, - reserved3: B9, - trb_type: B6, - reserved4: B8, - slot_id: B8, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct AddressDeviceCommandTrb { - input_context_pointer: B64, - reserved: B32, - cycle: B1, - reserved2: B8, - block_set_address_request: B1, - trb_type: B6, - reserved3: B8, - slot_id: B8, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct ConfigureEndpointCommandTrb { - input_context_pointer: B64, - reserved0: B32, - cycle: B1, - reserved1: B8, - deconfigure: B1, - trb_type: B6, - reserved2: B8, - slot_id: B8, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct EvaluateContextCommandTrb { - input_context_pointer: B64, - reserved0: B32, - cycle: B1, - reserved1: B9, - trb_type: B6, - reserved2: B8, - slot_id: B8, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct ResetEndpointCommandTrb { - reserved0: B32, - reserved1: B32, - reserved2: B32, - cycle: B1, - reserved3: B8, - transfer_state_preserve: B1, - trb_type: B6, - endpoint_id: B5, - reserved4: B3, - slot_id: B8, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct StopEndpointCommandTrb { - reserved0: B32, - reserved1: B32, - reserved2: B32, - cycle: B1, - reserved3: B9, - trb_type: B6, - endpoint_id: B5, - reserved4: B2, - suspend: B1, - slot_id: B8, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct SetTRDequeuePointerCommandTrb { - dequeue_cycle_state: B1, - stream_context_type: B3, - dequeue_ptr: B60, - reserved0: B16, - stream_id: B16, - cycle: B1, - reserved1: B9, - trb_type: B6, - endpoint_id: B5, - reserved3: B2, - suspend: B1, - slot_id: B8, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct ResetDeviceCommandTrb { - reserved0: B32, - reserved1: B32, - reserved2: B32, - cycle: B1, - reserved3: B9, - trb_type: B6, - reserved4: B8, - slot_id: B8, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct TransferEventTrb { - trb_pointer: B64, - trb_transfer_length: B24, - completion_code: B8, - cycle: B1, - reserved0: B1, - event_data: B1, - reserved1: B7, - trb_type: B6, - endpoint_id: B5, - reserved2: B3, - slot_id: B8, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct CommandCompletionEventTrb { - trb_pointer: B64, - command_completion_parameter: B24, - completion_code: B8, - cycle: B1, - reserved: B9, - trb_type: B6, - vf_id: B8, - slot_id: B8, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct PortStatusChangeEventTrb { - reserved0: B24, - port_id: B8, - reserved1: B32, - reserved2: B24, - completion_code: B8, - cycle: B1, - reserved3: B9, - trb_type: B6, - reserved4: B16, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct EventRingSegmentTableEntry { - ring_segment_base_address: B64, - ring_segment_size: B16, - reserved2: B48, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct InputControlContext { - // Xhci spec 6.2.5.1. - drop_context_flags: B32, - add_context_flags: B32, - reserved0: B32, - reserved1: B32, - reserved2: B32, - reserved3: B32, - reserved4: B32, - configuration_value: B8, - interface_number: B8, - alternate_setting: B8, - reserved5: B8, -} - -// Size of device context entries (SlotContext and EndpointContext). -pub const DEVICE_CONTEXT_ENTRY_SIZE: usize = 32usize; - -#[bitfield] -#[derive(Clone, Copy)] -pub struct SlotContext { - route_string: B20, - speed: B4, - reserved1: B1, - mtt: B1, - hub: B1, - context_entries: B5, - max_exit_latency: B16, - root_hub_port_number: B8, - num_ports: B8, - tt_hub_slot_id: B8, - tt_port_number: B8, - tt_think_time: B2, - reserved2: B4, - interrupter_target: B10, - usb_device_address: B8, - reserved3: B19, - slot_state: B5, - reserved4: B32, - reserved5: B32, - reserved6: B32, - reserved7: B32, -} - -#[bitfield] -#[derive(Clone, Copy)] -pub struct EndpointContext { - endpoint_state: B3, - reserved1: B5, - mult: B2, - max_primary_streams: B5, - linear_stream_array: B1, - interval: B8, - max_esit_payload_hi: B8, - reserved2: B1, - error_count: B2, - endpoint_type: B3, - reserved3: B1, - host_initiate_disable: B1, - max_burst_size: B8, - max_packet_size: B16, - dequeue_cycle_state: B1, - reserved4: B3, - tr_dequeue_pointer: B60, - average_trb_length: B16, - max_esit_payload_lo: B16, - reserved5: B32, - reserved6: B32, - reserved7: B32, -} - -/// Device context. -#[derive(Clone, Copy, Debug)] -pub struct DeviceContext { - pub slot_context: SlotContext, - pub endpoint_context: [EndpointContext; 31], -} - -/// POD struct associates a TRB with its address in guest memory. This is -/// useful because transfer and command completion event TRBs must contain -/// pointers to the original TRB that generated the event. -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct AddressedTrb { - pub trb: Trb, - pub gpa: u64, -} - -pub type TransferDescriptor = Vec; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn check_struct_sizes() { - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!( - std::mem::size_of::(), - TRB_SIZE - ); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - assert_eq!(std::mem::size_of::(), TRB_SIZE); - - assert_eq!( - std::mem::size_of::(), - SEGMENT_TABLE_SIZE - ); - assert_eq!(std::mem::size_of::(), 32); - assert_eq!( - std::mem::size_of::(), - DEVICE_CONTEXT_ENTRY_SIZE - ); - assert_eq!( - std::mem::size_of::(), - DEVICE_CONTEXT_ENTRY_SIZE - ); - assert_eq!( - std::mem::size_of::(), - 32 * DEVICE_CONTEXT_ENTRY_SIZE - ); - } -} diff --git a/devices/src/usb/xhci/xhci_transfer.rs b/devices/src/usb/xhci/xhci_transfer.rs index eb0c782..e166c1a 100644 --- a/devices/src/usb/xhci/xhci_transfer.rs +++ b/devices/src/usb/xhci/xhci_transfer.rs @@ -10,6 +10,7 @@ use super::xhci_abi::{ TrbCompletionCode, TrbType, }; use super::xhci_regs::MAX_INTERRUPTER; +use bit_field::Error as BitFieldError; use std::cmp::min; use std::fmt::{self, Display}; use std::mem; @@ -21,7 +22,7 @@ use usb_util::usb_transfer::TransferStatus; #[derive(Debug)] pub enum Error { - TrbType(TrbError), + TrbType(BitFieldError), CastTrb(TrbError), TransferLength(TrbError), BadTrbType(TrbType), @@ -114,7 +115,7 @@ impl XhciTransferType { pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result { // We can figure out transfer type from the first trb. // See transfer descriptor description in xhci spec for more details. - match td[0].trb.trb_type().map_err(Error::TrbType)? { + match td[0].trb.get_trb_type().map_err(Error::TrbType)? { TrbType::Normal => { let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?; Ok(XhciTransferType::Normal(buffer)) @@ -329,7 +330,7 @@ impl XhciTransfer { || (atrb.trb.interrupt_on_short_packet() && edtla > bytes_transferred) { // For details about event data trb and EDTLA, see spec 4.11.5.2. - if atrb.trb.trb_type().map_err(Error::TrbType)? == TrbType::EventData { + if atrb.trb.get_trb_type().map_err(Error::TrbType)? == TrbType::EventData { let tlength = min(edtla, bytes_transferred); self.interrupter .lock() -- cgit 1.4.1