// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. // // StratoVirt is licensed under Mulan PSL v2. // You can use this software according to the terms and conditions of the Mulan // PSL v2. // You may obtain a copy of Mulan PSL v2 at: // http://license.coscl.org.cn/MulanPSL2 // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. use std::{ collections::LinkedList, sync::{Arc, Mutex, Weak}, }; use crate::config::*; use crate::descriptor::{ UsbConfigDescriptor, UsbDescriptorOps, UsbDeviceDescriptor, UsbEndpointDescriptor, UsbInterfaceDescriptor, }; use crate::xhci::xhci_controller::XhciDevice; use anyhow::{bail, Result}; use log::{debug, error, warn}; const USB_MAX_ENDPOINTS: u32 = 15; const USB_MAX_INTERFACES: u32 = 16; /// USB max address. const USB_MAX_ADDRESS: u8 = 127; /// USB packet return status. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum UsbPacketStatus { Success, NoDev, Nak, Stall, Babble, IoError, Async, } /// USB packet setup state. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum SetupState { Idle, Setup, Data, Ack, Parameter, } /// USB device state. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum UsbDeviceState { Removed, Attached, Powered, Default, Address, Configured, Suspended, } /// USB request used to transfer to USB device. #[repr(C)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct UsbDeviceRequest { pub request_type: u8, pub request: u8, pub value: u16, pub index: u16, pub length: u16, } /// The data transmission channel. #[derive(Default)] pub struct UsbEndpoint { pub nr: u8, pub pid: u8, pub usb_type: u8, pub ifnum: u8, pub max_packet_size: u32, pub pipeline: bool, pub halted: bool, pub dev: Option<Weak<Mutex<dyn UsbDeviceOps>>>, pub queue: LinkedList<UsbPacket>, } impl UsbEndpoint { pub fn new(nr: u8, pid: u8, usb_type: u8, ifnum: u8, max_packet_size: u32) -> Self { Self { nr, pid, usb_type, ifnum, max_packet_size, pipeline: false, halted: false, dev: None, queue: LinkedList::new(), } } pub fn get_ep_id(&self) -> u8 { if self.nr == 0 { // Control endpoint 1 } else if self.pid == USB_TOKEN_IN { self.nr * 2 + 1 } else { self.nr * 2 } } } /// Init USB endpoint, similar with init_usb_endpoint, but set dev in endpoint. pub fn usb_endpoint_init(dev: &Arc<Mutex<dyn UsbDeviceOps>>) { let mut locked_dev = dev.lock().unwrap(); let usb_dev = locked_dev.get_mut_usb_device(); let mut locked_dev = usb_dev.lock().unwrap(); locked_dev.reset_usb_endpoint(); let mut ep_ctl = locked_dev.ep_ctl.lock().unwrap(); ep_ctl.dev = Some(Arc::downgrade(dev)); ep_ctl.queue = LinkedList::new(); for i in 0..USB_MAX_ENDPOINTS { let mut ep_in = locked_dev.ep_in[i as usize].lock().unwrap(); let mut ep_out = locked_dev.ep_out[i as usize].lock().unwrap(); ep_in.queue = LinkedList::new(); ep_out.queue = LinkedList::new(); ep_in.dev = Some(Arc::downgrade(dev)); ep_out.dev = Some(Arc::downgrade(dev)); } } /// USB port which can attached device. pub struct UsbPort { pub dev: Option<Arc<Mutex<dyn UsbDeviceOps>>>, pub speed_mask: u32, pub path: String, pub index: u8, } impl UsbPort { pub fn new(index: u8) -> Self { Self { dev: None, speed_mask: 0, path: String::new(), index, } } } /// USB descriptor strings. pub struct UsbDescString { pub index: u32, pub str: String, } /// USB packet state. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum UsbPacketState { Undefined = 0, Setup, Queued, Async, Complete, Canceled, } // USB descriptor pub struct UsbDesc { pub full_dev: Option<Arc<UsbDescDevice>>, pub high_dev: Option<Arc<UsbDescDevice>>, pub super_dev: Option<Arc<UsbDescDevice>>, pub strings: Vec<String>, } // USB device descriptor pub struct UsbDescDevice { pub device_desc: UsbDeviceDescriptor, pub confs: Vec<Arc<UsbDescConfig>>, } // USB config descriptor pub struct UsbDescConfig { pub config_desc: UsbConfigDescriptor, pub if_groups: Vec<Arc<UsbDescIfaceAssoc>>, pub ifs: Vec<Arc<UsbDescIface>>, } // USB interface descriptor pub struct UsbDescIface { pub interface_desc: UsbInterfaceDescriptor, pub other_desc: Vec<Arc<UsbDescOther>>, pub eps: Vec<Arc<UsbDescEndpoint>>, } /* conceptually an Interface Association Descriptor, and related interfaces */ #[allow(non_snake_case)] #[repr(C)] pub struct UsbDescIfaceAssoc { pub bFirstInterface: u8, pub bInterfaceCount: u8, pub bFunctionClass: u8, pub bFunctionSubClass: u8, pub bFunctionProtocol: u8, pub iFunction: u8, pub ifs: Vec<Arc<UsbDescIface>>, } // USB other descriptor pub struct UsbDescOther { pub length: u8, pub data: Vec<u8>, } // USB endpoint descriptor pub struct UsbDescEndpoint { pub endpoint_desc: UsbEndpointDescriptor, pub extra: Option<Arc<u8>>, } /// USB device common structure. pub struct UsbDevice { pub port: Option<Weak<Mutex<UsbPort>>>, pub speed: u32, pub speed_mask: u32, pub addr: u8, pub product_desc: String, pub state: UsbDeviceState, pub setup_buf: Vec<u8>, pub data_buf: Vec<u8>, pub remote_wakeup: u32, pub setup_state: SetupState, pub setup_len: u32, pub setup_index: u32, pub ep_ctl: Arc<Mutex<UsbEndpoint>>, pub ep_in: Vec<Arc<Mutex<UsbEndpoint>>>, pub ep_out: Vec<Arc<Mutex<UsbEndpoint>>>, /// USB descriptor pub strings: Vec<UsbDescString>, pub usb_desc: Option<Arc<UsbDesc>>, pub device_desc: Option<Arc<UsbDescDevice>>, pub configuration: u32, pub ninterfaces: u32, pub altsetting: Vec<u32>, pub config: Option<Arc<UsbDescConfig>>, pub ifaces: Vec<Option<Arc<UsbDescIface>>>, } impl UsbDevice { pub fn new() -> Self { let mut dev = UsbDevice { port: None, speed: 0, speed_mask: 0, addr: 0, ep_ctl: Arc::new(Mutex::new(UsbEndpoint::new( 0, 0, USB_ENDPOINT_ATTR_CONTROL, 0, 64, ))), ep_in: Vec::new(), ep_out: Vec::new(), product_desc: String::new(), strings: Vec::new(), usb_desc: None, device_desc: None, configuration: 0, ninterfaces: 0, config: None, altsetting: vec![0; USB_MAX_INTERFACES as usize], state: UsbDeviceState::Removed, setup_buf: vec![0_u8; 8], data_buf: vec![0_u8; 4096], ifaces: vec![None; USB_MAX_INTERFACES as usize], remote_wakeup: 0, setup_index: 0, setup_len: 0, setup_state: SetupState::Idle, }; for i in 0..USB_MAX_ENDPOINTS as u8 { dev.ep_in.push(Arc::new(Mutex::new(UsbEndpoint::new( i + 1, USB_TOKEN_IN, USB_ENDPOINT_ATTR_INVALID, USB_INTERFACE_INVALID, 0, )))); dev.ep_out.push(Arc::new(Mutex::new(UsbEndpoint::new( i + 1, USB_TOKEN_OUT, USB_ENDPOINT_ATTR_INVALID, USB_INTERFACE_INVALID, 0, )))); } dev } pub fn get_endpoint(&self, pid: u32, ep: u32) -> Arc<Mutex<UsbEndpoint>> { if ep == 0 { return self.ep_ctl.clone(); } if pid as u8 == USB_TOKEN_IN { self.ep_in[(ep - 1) as usize].clone() } else { self.ep_out[(ep - 1) as usize].clone() } } pub fn init_usb_endpoint(&mut self) { self.reset_usb_endpoint(); let mut ep_ctl = self.ep_ctl.lock().unwrap(); ep_ctl.queue = LinkedList::new(); for i in 0..USB_MAX_ENDPOINTS { let mut ep_in = self.ep_in[i as usize].lock().unwrap(); let mut ep_out = self.ep_out[i as usize].lock().unwrap(); ep_in.queue = LinkedList::new(); ep_out.queue = LinkedList::new(); } } pub fn reset_usb_endpoint(&mut self) { let mut ep_ctl = self.ep_ctl.lock().unwrap(); ep_ctl.nr = 0; ep_ctl.usb_type = USB_ENDPOINT_ATTR_CONTROL; ep_ctl.ifnum = 0; ep_ctl.max_packet_size = 64; ep_ctl.pipeline = false; for i in 0..USB_MAX_ENDPOINTS { let mut ep_in = self.ep_in[i as usize].lock().unwrap(); let mut ep_out = self.ep_out[i as usize].lock().unwrap(); ep_in.nr = (i + 1) as u8; ep_out.nr = (i + 1) as u8; ep_in.pid = USB_TOKEN_IN; ep_out.pid = USB_TOKEN_OUT; ep_in.usb_type = USB_ENDPOINT_ATTR_INVALID; ep_out.usb_type = USB_ENDPOINT_ATTR_INVALID; ep_in.ifnum = USB_INTERFACE_INVALID; ep_out.ifnum = USB_INTERFACE_INVALID; ep_in.max_packet_size = 0; ep_out.max_packet_size = 0; ep_in.pipeline = false; ep_out.pipeline = false; } } /// Handle USB control request which is for descriptor. /// /// # Arguments /// /// * `packet` - USB packet. /// * `device_req` - USB device request. /// * `data` - USB control transfer data. /// /// # Returns /// /// Return true if request is handled, false is unhandled. pub fn handle_control_for_descriptor( &mut self, packet: &mut UsbPacket, device_req: &UsbDeviceRequest, data: &mut [u8], ) -> Result<bool> { let value = device_req.value as u32; let index = device_req.index as u32; let length = device_req.length as u32; match device_req.request_type { USB_DEVICE_IN_REQUEST => match device_req.request { USB_REQUEST_GET_DESCRIPTOR => { let res = self.get_descriptor(value)?; let len = std::cmp::min(res.len() as u32, length); data[..(len as usize)].clone_from_slice(&res[..(len as usize)]); packet.actual_length = len; } USB_REQUEST_GET_CONFIGURATION => { data[0] = if let Some(conf) = &self.config { conf.config_desc.bConfigurationValue } else { 0 }; packet.actual_length = 1; } USB_REQUEST_GET_STATUS => { let conf = if let Some(conf) = &self.config { conf.clone() } else { let x = &self.device_desc.as_ref().unwrap().confs[0]; x.clone() }; data[0] = 0; if conf.config_desc.bmAttributes & USB_CONFIGURATION_ATTR_SELF_POWER == USB_CONFIGURATION_ATTR_SELF_POWER { data[0] |= 1 << USB_DEVICE_SELF_POWERED; } if self.remote_wakeup & USB_DEVICE_REMOTE_WAKEUP == USB_DEVICE_REMOTE_WAKEUP { data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP; } data[1] = 0x00; packet.actual_length = 2; } _ => { return Ok(false); } }, USB_DEVICE_OUT_REQUEST => match device_req.request { USB_REQUEST_SET_ADDRESS => { if value as u8 > USB_MAX_ADDRESS { packet.status = UsbPacketStatus::Stall; bail!("The address is invalid {}", value); } else { self.addr = value as u8; } } USB_REQUEST_SET_CONFIGURATION => { self.set_config_descriptor(value as u8)?; } USB_REQUEST_CLEAR_FEATURE => { if value == USB_DEVICE_REMOTE_WAKEUP { self.remote_wakeup = 0; } } USB_REQUEST_SET_FEATURE => { if value == USB_DEVICE_REMOTE_WAKEUP { self.remote_wakeup = 1; } } _ => { return Ok(false); } }, USB_INTERFACE_IN_REQUEST => match device_req.request { USB_REQUEST_GET_INTERFACE => { if index < self.ninterfaces { data[0] = self.altsetting[index as usize] as u8; packet.actual_length = 1; } } _ => { return Ok(false); } }, USB_INTERFACE_OUT_REQUEST => match device_req.request { USB_REQUEST_SET_INTERFACE => { self.set_interface_descriptor(index, value)?; } _ => { return Ok(false); } }, _ => { return Ok(false); } } Ok(true) } } impl Default for UsbDevice { fn default() -> Self { Self::new() } } /// UsbDeviceOps is the interface for USB device. /// Include device handle attach/detach and the transfer between controller and device. pub trait UsbDeviceOps: Send + Sync { /// Handle the attach ops when attach device to controller. fn handle_attach(&mut self) -> Result<()> { let usb_dev = self.get_mut_usb_device(); let mut locked_dev = usb_dev.lock().unwrap(); locked_dev.state = UsbDeviceState::Attached; drop(locked_dev); let usb_dev = self.get_mut_usb_device(); let mut locked_dev = usb_dev.lock().unwrap(); locked_dev.set_default_descriptor()?; Ok(()) } /// Reset the USB device. fn reset(&mut self); /// Set the controller which the USB device attached. /// USB deivce need to kick controller in some cases. fn set_controller(&mut self, ctrl: Weak<Mutex<XhciDevice>>); /// Set the controller which the USB device attached. fn get_controller(&self) -> Option<Weak<Mutex<XhciDevice>>>; /// Get the endpoint to wakeup. fn get_endpoint(&self) -> Option<Weak<Mutex<UsbEndpoint>>>; /// Set the attached USB port. fn set_usb_port(&mut self, port: Option<Weak<Mutex<UsbPort>>>) { let usb_dev = self.get_mut_usb_device(); let mut locked_dev = usb_dev.lock().unwrap(); locked_dev.port = port; } /// Handle usb packet, used for controller to deliever packet to device. fn handle_packet(&mut self, packet: &mut UsbPacket) { if packet.state != UsbPacketState::Setup { error!("The packet state is not Setup"); return; } if let Err(e) = self.process_packet(packet) { error!("Failed to process packet: {}", e); } if packet.status != UsbPacketStatus::Nak { packet.state = UsbPacketState::Complete; } } /// Handle control pakcet. fn handle_control( &mut self, packet: &mut UsbPacket, device_req: &UsbDeviceRequest, data: &mut [u8], ); /// Handle data pakcet. fn handle_data(&mut self, packet: &mut UsbPacket); /// Unique device id. fn device_id(&self) -> String; /// Get the UsbDevice. fn get_usb_device(&self) -> Arc<Mutex<UsbDevice>>; /// Get the mut UsbDevice. fn get_mut_usb_device(&mut self) -> Arc<Mutex<UsbDevice>>; /// Get the device speed. fn speed(&self) -> u32 { let usb_dev = self.get_usb_device(); let locked_dev = usb_dev.lock().unwrap(); locked_dev.speed } fn process_packet(&mut self, packet: &mut UsbPacket) -> Result<()> { packet.status = UsbPacketStatus::Success; let ep = if let Some(ep) = &packet.ep { ep.upgrade().unwrap() } else { bail!("Failed to find ep"); }; let locked_ep = ep.lock().unwrap(); let nr = locked_ep.nr; drop(locked_ep); if nr == 0 { if packet.parameter != 0 { return self.do_parameter(packet); } match packet.pid as u8 { USB_TOKEN_SETUP => { warn!("process_packet USB_TOKEN_SETUP not implemented"); } USB_TOKEN_IN => { warn!("process_packet USB_TOKEN_IN not implemented"); } USB_TOKEN_OUT => { warn!("process_packet USB_TOKEN_OUT not implemented"); } _ => { warn!("Unknown pid {}", packet.pid); packet.status = UsbPacketStatus::Stall; } } } else { self.handle_data(packet); } Ok(()) } fn do_parameter(&mut self, p: &mut UsbPacket) -> Result<()> { let usb_dev = self.get_mut_usb_device(); let mut locked_dev = usb_dev.lock().unwrap(); for i in 0..8 { locked_dev.setup_buf[i] = (p.parameter >> (i * 8)) as u8; } locked_dev.setup_state = SetupState::Parameter; locked_dev.setup_index = 0; let device_req = UsbDeviceRequest { request_type: locked_dev.setup_buf[0], request: locked_dev.setup_buf[1], value: (locked_dev.setup_buf[3] as u16) << 8 | locked_dev.setup_buf[2] as u16, index: (locked_dev.setup_buf[5] as u16) << 8 | locked_dev.setup_buf[4] as u16, length: (locked_dev.setup_buf[7] as u16) << 8 | locked_dev.setup_buf[6] as u16, }; if device_req.length as usize > locked_dev.data_buf.len() { bail!("data buffer small len {}", device_req.length); } locked_dev.setup_len = device_req.length as u32; if p.pid as u8 == USB_TOKEN_OUT { let len = locked_dev.data_buf.len(); usb_packet_transfer(p, &mut locked_dev.data_buf, len); } // Drop locked for handle_control use it drop(locked_dev); let mut data_buf: [u8; 4096] = [0; 4096]; self.handle_control(p, &device_req, &mut data_buf); let mut locked_dev = usb_dev.lock().unwrap(); locked_dev.data_buf = data_buf.to_vec(); if p.status == UsbPacketStatus::Async { return Ok(()); } if p.actual_length < locked_dev.setup_len { locked_dev.setup_len = p.actual_length; } if p.pid as u8 == USB_TOKEN_IN { p.actual_length = 0; let len = locked_dev.data_buf.len(); usb_packet_transfer(p, &mut locked_dev.data_buf, len); } Ok(()) } } /// Notify controller to process data request. pub fn notify_controller(dev: &Arc<Mutex<dyn UsbDeviceOps>>) -> Result<()> { let locked_dev = dev.lock().unwrap(); let xhci = if let Some(ctrl) = &locked_dev.get_controller() { ctrl.upgrade().unwrap() } else { bail!("USB controller not found"); }; drop(locked_dev); // Lock controller before device to avoid dead lock. let mut locked_xhci = xhci.lock().unwrap(); let locked_dev = dev.lock().unwrap(); let usb_dev = locked_dev.get_usb_device(); drop(locked_dev); let locked_usb_dev = usb_dev.lock().unwrap(); let usb_port = if let Some(port) = &locked_usb_dev.port { port.upgrade().unwrap() } else { bail!("No usb port found"); }; let slot_id = locked_usb_dev.addr; let wakeup = locked_usb_dev.remote_wakeup & USB_DEVICE_REMOTE_WAKEUP == USB_DEVICE_REMOTE_WAKEUP; drop(locked_usb_dev); let xhci_port = if let Some(xhci_port) = locked_xhci.lookup_xhci_port(&usb_port) { xhci_port } else { bail!("No xhci port found"); }; if wakeup { let mut locked_port = xhci_port.lock().unwrap(); let port_status = locked_port.get_port_link_state(); if port_status == PLS_U3 { locked_port.set_port_link_state(PLS_RESUME); debug!( "Update portsc when notify controller, port {} status {}", locked_port.portsc, port_status ); drop(locked_port); locked_xhci.port_notify(&xhci_port, PORTSC_PLC)?; } } let locked_dev = dev.lock().unwrap(); let intr = if let Some(intr) = locked_dev.get_endpoint() { intr } else { bail!("No interrupter found"); }; drop(locked_dev); let ep = intr.upgrade().unwrap(); if let Err(e) = locked_xhci.wakeup_endpoint(slot_id as u32, &ep) { error!("Failed to wakeup endpoint {}", e); } Ok(()) } /// Io vector which save the hva. #[derive(Debug, Copy, Clone)] pub struct Iovec { pub iov_base: u64, pub iov_len: usize, } impl Iovec { pub fn new(base: u64, len: usize) -> Self { Iovec { iov_base: base, iov_len: len, } } } /// Usb packet used for device transfer data. #[derive(Clone)] pub struct UsbPacket { /// USB packet id. pub pid: u32, pub ep: Option<Weak<Mutex<UsbEndpoint>>>, pub iovecs: Vec<Iovec>, /// control transfer parameter. pub parameter: u64, /// USB packet return status. pub status: UsbPacketStatus, /// Actually transfer length. pub actual_length: u32, pub state: UsbPacketState, } impl std::fmt::Display for UsbPacket { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, "pid {} param {} status {:?} actual_length {}, state {:?}", self.pid, self.parameter, self.status, self.actual_length, self.state ) } } impl UsbPacket { pub fn init(&mut self, pid: u32, ep: Weak<Mutex<UsbEndpoint>>) { self.pid = pid; self.ep = Some(ep); self.status = UsbPacketStatus::Success; self.actual_length = 0; self.parameter = 0; self.state = UsbPacketState::Setup; } } impl Default for UsbPacket { fn default() -> UsbPacket { UsbPacket { pid: 0, ep: None, iovecs: Vec::new(), parameter: 0, status: UsbPacketStatus::NoDev, actual_length: 0, state: UsbPacketState::Undefined, } } } fn read_mem(hva: u64, buf: &mut [u8]) { let slice = unsafe { std::slice::from_raw_parts(hva as *const u8, buf.len()) }; buf.clone_from_slice(&slice[..buf.len()]); } fn write_mem(hva: u64, buf: &[u8]) { use std::io::Write; let mut slice = unsafe { std::slice::from_raw_parts_mut(hva as *mut u8, buf.len()) }; if let Err(e) = (&mut slice).write(buf) { error!("Failed to write mem {:?}", e); } } /// Transfer packet from host to device or from device to host. pub fn usb_packet_transfer(packet: &mut UsbPacket, vec: &mut [u8], len: usize) { let to_host = packet.pid as u8 & USB_TOKEN_IN == USB_TOKEN_IN; if to_host { let mut copyed = 0; let mut offset = 0; for iov in &packet.iovecs { let cnt = std::cmp::min(iov.iov_len, len - copyed); let tmp = &vec[offset..(offset + cnt)]; write_mem(iov.iov_base, tmp); copyed += cnt; offset += cnt; if len - copyed == 0 { break; } } } else { let mut copyed = 0; let mut offset = 0; for iov in &packet.iovecs { let cnt = std::cmp::min(iov.iov_len, len - copyed); let tmp = &mut vec[offset..(offset + cnt)]; read_mem(iov.iov_base, tmp); copyed += cnt; offset += cnt; if len - copyed == 0 { break; } } } packet.actual_length += len as u32; }