Path: blob/main/devices/src/usb/xhci/scatter_gather_buffer.rs
5394 views
// Copyright 2019 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use bit_field::Error as BitFieldError;5use remain::sorted;6use thiserror::Error;7use vm_memory::GuestAddress;8use vm_memory::GuestMemory;9use vm_memory::GuestMemoryError;1011use super::xhci_abi::AddressedTrb;12use super::xhci_abi::Error as TrbError;13use super::xhci_abi::NormalTrb;14use super::xhci_abi::TransferDescriptor;15use super::xhci_abi::TrbCast;16use super::xhci_abi::TrbType;1718#[sorted]19#[derive(Error, Debug)]20pub enum Error {21#[error("should not build buffer from trb type: {0:?}")]22BadTrbType(TrbType),23#[error("cannot cast trb: {0}")]24CastTrb(TrbError),25#[error("immediate data longer than allowed: {0}")]26ImmediateDataTooLong(usize),27#[error("cannot read guest memory: {0}")]28ReadGuestMemory(GuestMemoryError),29#[error("unknown trb type: {0}")]30UnknownTrbType(BitFieldError),31#[error("cannot write guest memory: {0}")]32WriteGuestMemory(GuestMemoryError),33}3435type Result<T> = std::result::Result<T, Error>;3637/// See xHCI spec 3.2.8 for scatter/gather transfer. It's used in bulk/interrupt transfers. See38/// 3.2.10 for details.39pub struct ScatterGatherBuffer {40mem: GuestMemory,41td: TransferDescriptor,42}4344impl ScatterGatherBuffer {45/// Create a new buffer from transfer descriptor.46pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result<ScatterGatherBuffer> {47for atrb in &td {48let trb_type = atrb.trb.get_trb_type().map_err(Error::UnknownTrbType)?;49if trb_type != TrbType::Normal50&& trb_type != TrbType::DataStage51&& trb_type != TrbType::Isoch52{53return Err(Error::BadTrbType(trb_type));54}55}56Ok(ScatterGatherBuffer { mem, td })57}5859/// Total len of this buffer.60pub fn len(&self) -> Result<usize> {61let mut total_len = 0usize;62for atrb in &self.td {63total_len += atrb64.trb65.cast::<NormalTrb>()66.map_err(Error::CastTrb)?67.get_trb_transfer_length() as usize;68}69Ok(total_len)70}7172pub fn is_empty(&self) -> Result<bool> {73Ok(self.len()? == 0)74}7576/// Get the guest address and length of the TRB's data buffer.77/// This is usually a separate buffer pointed to by the TRB,78/// but it can also be within the TRB itself in the case of immediate data.79fn get_trb_data(&self, atrb: &AddressedTrb) -> Result<(GuestAddress, usize)> {80let normal_trb = atrb.trb.cast::<NormalTrb>().map_err(Error::CastTrb)?;81let len = normal_trb.get_trb_transfer_length() as usize;82let addr = if normal_trb.get_immediate_data() == 1 {83// If the Immediate Data flag is set, the first <= 8 bytes of the TRB hold the data.84if len > 8 {85return Err(Error::ImmediateDataTooLong(len));86}87atrb.gpa88} else {89normal_trb.get_data_buffer_pointer()90};91Ok((GuestAddress(addr), len))92}9394/// Read content to buffer, return number of bytes read.95pub fn read(&self, buffer: &mut [u8]) -> Result<usize> {96let mut total_size = 0usize;97let mut offset = 0;98for atrb in &self.td {99let (guest_address, len) = self.get_trb_data(atrb)?;100let buffer_len = {101if offset == buffer.len() {102return Ok(total_size);103}104if buffer.len() > offset + len {105len106} else {107buffer.len() - offset108}109};110let buffer_end = offset + buffer_len;111let cur_buffer = &mut buffer[offset..buffer_end];112offset = buffer_end;113total_size += self114.mem115.read_at_addr(cur_buffer, guest_address)116.map_err(Error::ReadGuestMemory)?;117}118Ok(total_size)119}120121/// Write content from buffer, return number of bytes written.122pub fn write(&self, buffer: &[u8]) -> Result<usize> {123let mut total_size = 0usize;124let mut offset = 0;125for atrb in &self.td {126let (guest_address, len) = self.get_trb_data(atrb)?;127let buffer_len = {128if offset == buffer.len() {129return Ok(total_size);130}131if buffer.len() > offset + len {132len133} else {134buffer.len() - offset135}136};137let buffer_end = offset + buffer_len;138let cur_buffer = &buffer[offset..buffer_end];139offset = buffer_end;140total_size += self141.mem142.write_at_addr(cur_buffer, guest_address)143.map_err(Error::WriteGuestMemory)?;144}145Ok(total_size)146}147}148149#[cfg(test)]150mod test {151use base::pagesize;152153use super::*;154use crate::usb::xhci::xhci_abi::AddressedTrb;155use crate::usb::xhci::xhci_abi::Trb;156157#[test]158fn scatter_gather_buffer_test() {159let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();160let mut trbs = Vec::new();161162// In this td, we are going to have scatter buffer at 0x100, length 4, 0x200 length 2 and163// 0x300 length 1.164165let mut trb = Trb::new();166let ntrb = trb.cast_mut::<NormalTrb>().unwrap();167ntrb.set_trb_type(TrbType::Normal);168ntrb.set_data_buffer_pointer(0x100);169ntrb.set_trb_transfer_length(4);170trbs.push(AddressedTrb { trb, gpa: 0 });171172let mut trb = Trb::new();173let ntrb = trb.cast_mut::<NormalTrb>().unwrap();174ntrb.set_trb_type(TrbType::Normal);175ntrb.set_data_buffer_pointer(0x200);176ntrb.set_trb_transfer_length(2);177trbs.push(AddressedTrb { trb, gpa: 0 });178179let mut trb = Trb::new();180let ntrb = trb.cast_mut::<NormalTrb>().unwrap();181ntrb.set_trb_type(TrbType::Normal);182ntrb.set_data_buffer_pointer(0x300);183ntrb.set_trb_transfer_length(1);184trbs.push(AddressedTrb { trb, gpa: 0 });185186let td = TransferDescriptor::new(trbs).unwrap();187let buffer = ScatterGatherBuffer::new(gm.clone(), td).unwrap();188189assert_eq!(buffer.len().unwrap(), 7);190let data_to_write: [u8; 7] = [7, 6, 5, 4, 3, 2, 1];191buffer.write(&data_to_write).unwrap();192193let mut d = [0; 4];194gm.read_exact_at_addr(&mut d, GuestAddress(0x100)).unwrap();195assert_eq!(d, [7, 6, 5, 4]);196gm.read_exact_at_addr(&mut d, GuestAddress(0x200)).unwrap();197assert_eq!(d, [3, 2, 0, 0]);198gm.read_exact_at_addr(&mut d, GuestAddress(0x300)).unwrap();199assert_eq!(d, [1, 0, 0, 0]);200201let mut data_read = [0; 7];202buffer.read(&mut data_read).unwrap();203assert_eq!(data_to_write, data_read);204}205206#[test]207fn immediate_data_test() {208let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();209210let expected_immediate_data: [u8; 8] = [0xDE, 0xAD, 0xBE, 0xEF, 0xF0, 0x0D, 0xCA, 0xFE];211212let mut trb = Trb::new();213let ntrb = trb.cast_mut::<NormalTrb>().unwrap();214ntrb.set_trb_type(TrbType::Normal);215ntrb.set_data_buffer_pointer(u64::from_le_bytes(expected_immediate_data));216ntrb.set_trb_transfer_length(8);217ntrb.set_immediate_data(1);218let td = TransferDescriptor::new(vec![AddressedTrb { trb, gpa: 0xC00 }]).unwrap();219220gm.write_obj_at_addr(trb, GuestAddress(0xc00)).unwrap();221222let buffer = ScatterGatherBuffer::new(gm, td).unwrap();223224let mut data_read = [0; 8];225buffer.read(&mut data_read).unwrap();226assert_eq!(data_read, expected_immediate_data);227}228}229230231