1 // Copyright 2018 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use byteorder::{ByteOrder, LittleEndian}; 6 7 use std; 8 use std::fmt::{self, Display}; 9 use std::os::unix::io::RawFd; 10 11 use kvm::Datamatch; 12 use resources::{Error as SystemAllocatorFaliure, SystemAllocator}; 13 use sys_util::EventFd; 14 15 use crate::pci::pci_configuration::{self, PciConfiguration}; 16 use crate::pci::PciInterruptPin; 17 use crate::BusDevice; 18 19 #[derive(Debug)] 20 pub enum Error { 21 /// Setup of the device capabilities failed. 22 CapabilitiesSetup(pci_configuration::Error), 23 /// Allocating space for an IO BAR failed. 24 IoAllocationFailed(u64, SystemAllocatorFaliure), 25 /// Registering an IO BAR failed. 26 IoRegistrationFailed(u64, pci_configuration::Error), 27 } 28 pub type Result<T> = std::result::Result<T, Error>; 29 30 impl Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 32 use self::Error::*; 33 34 match self { 35 CapabilitiesSetup(e) => write!(f, "failed to add capability {}", e), 36 IoAllocationFailed(size, e) => write!( 37 f, 38 "failed to allocate space for an IO BAR, size={}: {}", 39 size, e 40 ), 41 IoRegistrationFailed(addr, e) => { 42 write!(f, "failed to register an IO BAR, addr={} err={}", addr, e) 43 } 44 } 45 } 46 } 47 48 pub trait PciDevice: Send { 49 /// Returns a label suitable for debug output. debug_label(&self) -> String50 fn debug_label(&self) -> String; 51 /// Assign a unique bus and device number to this device. assign_bus_dev(&mut self, _bus: u8, _device: u8 )52 fn assign_bus_dev(&mut self, _bus: u8, _device: u8 /*u5*/) {} 53 /// A vector of device-specific file descriptors that must be kept open 54 /// after jailing. Must be called before the process is jailed. keep_fds(&self) -> Vec<RawFd>55 fn keep_fds(&self) -> Vec<RawFd>; 56 /// Assign a legacy PCI IRQ to this device. 57 /// The device may write to `irq_evt` to trigger an interrupt. 58 /// When `irq_resample_evt` is signaled, the device should re-assert `irq_evt` if necessary. assign_irq( &mut self, _irq_evt: EventFd, _irq_resample_evt: EventFd, _irq_num: u32, _irq_pin: PciInterruptPin, )59 fn assign_irq( 60 &mut self, 61 _irq_evt: EventFd, 62 _irq_resample_evt: EventFd, 63 _irq_num: u32, 64 _irq_pin: PciInterruptPin, 65 ) { 66 } 67 /// Allocates the needed IO BAR space using the `allocate` function which takes a size and 68 /// returns an address. Returns a Vec of (address, length) tuples. allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>>69 fn allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> { 70 Ok(Vec::new()) 71 } 72 73 /// Allocates the needed device BAR space. Returns a Vec of (address, length) tuples. 74 /// Unlike MMIO BARs (see allocate_io_bars), device BARs are not expected to incur VM exits 75 /// - these BARs represent normal memory. allocate_device_bars( &mut self, _resources: &mut SystemAllocator, ) -> Result<Vec<(u64, u64)>>76 fn allocate_device_bars( 77 &mut self, 78 _resources: &mut SystemAllocator, 79 ) -> Result<Vec<(u64, u64)>> { 80 Ok(Vec::new()) 81 } 82 83 /// Register any capabilties specified by the device. register_device_capabilities(&mut self) -> Result<()>84 fn register_device_capabilities(&mut self) -> Result<()> { 85 Ok(()) 86 } 87 88 /// Gets a list of ioeventfds that should be registered with the running VM. The list is 89 /// returned as a Vec of (eventfd, addr, datamatch) tuples. ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)>90 fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> { 91 Vec::new() 92 } 93 /// Gets the configuration registers of the Pci Device. config_registers(&self) -> &PciConfiguration94 fn config_registers(&self) -> &PciConfiguration; // TODO - remove these 95 /// Gets the configuration registers of the Pci Device for modification. config_registers_mut(&mut self) -> &mut PciConfiguration96 fn config_registers_mut(&mut self) -> &mut PciConfiguration; 97 /// Reads from a BAR region mapped in to the device. 98 /// * `addr` - The guest address inside the BAR. 99 /// * `data` - Filled with the data from `addr`. read_bar(&mut self, addr: u64, data: &mut [u8])100 fn read_bar(&mut self, addr: u64, data: &mut [u8]); 101 /// Writes to a BAR region mapped in to the device. 102 /// * `addr` - The guest address inside the BAR. 103 /// * `data` - The data to write. write_bar(&mut self, addr: u64, data: &[u8])104 fn write_bar(&mut self, addr: u64, data: &[u8]); 105 /// Invoked when the device is sandboxed. on_device_sandboxed(&mut self)106 fn on_device_sandboxed(&mut self) {} 107 } 108 109 impl<T: PciDevice> BusDevice for T { debug_label(&self) -> String110 fn debug_label(&self) -> String { 111 PciDevice::debug_label(self) 112 } 113 read(&mut self, offset: u64, data: &mut [u8])114 fn read(&mut self, offset: u64, data: &mut [u8]) { 115 self.read_bar(offset, data) 116 } 117 write(&mut self, offset: u64, data: &[u8])118 fn write(&mut self, offset: u64, data: &[u8]) { 119 self.write_bar(offset, data) 120 } 121 config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8])122 fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { 123 if offset as usize + data.len() > 4 { 124 return; 125 } 126 127 let regs = self.config_registers_mut(); 128 129 match data.len() { 130 1 => regs.write_byte(reg_idx * 4 + offset as usize, data[0]), 131 2 => regs.write_word( 132 reg_idx * 4 + offset as usize, 133 (data[0] as u16) | (data[1] as u16) << 8, 134 ), 135 4 => regs.write_reg(reg_idx, LittleEndian::read_u32(data)), 136 _ => (), 137 } 138 } 139 config_register_read(&self, reg_idx: usize) -> u32140 fn config_register_read(&self, reg_idx: usize) -> u32 { 141 self.config_registers().read_reg(reg_idx) 142 } 143 on_sandboxed(&mut self)144 fn on_sandboxed(&mut self) { 145 self.on_device_sandboxed(); 146 } 147 } 148 149 impl<T: PciDevice + ?Sized> PciDevice for Box<T> { 150 /// Returns a label suitable for debug output. debug_label(&self) -> String151 fn debug_label(&self) -> String { 152 (**self).debug_label() 153 } assign_bus_dev(&mut self, bus: u8, device: u8 )154 fn assign_bus_dev(&mut self, bus: u8, device: u8 /*u5*/) { 155 (**self).assign_bus_dev(bus, device) 156 } keep_fds(&self) -> Vec<RawFd>157 fn keep_fds(&self) -> Vec<RawFd> { 158 (**self).keep_fds() 159 } assign_irq( &mut self, irq_evt: EventFd, irq_resample_evt: EventFd, irq_num: u32, irq_pin: PciInterruptPin, )160 fn assign_irq( 161 &mut self, 162 irq_evt: EventFd, 163 irq_resample_evt: EventFd, 164 irq_num: u32, 165 irq_pin: PciInterruptPin, 166 ) { 167 (**self).assign_irq(irq_evt, irq_resample_evt, irq_num, irq_pin) 168 } allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>>169 fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> { 170 (**self).allocate_io_bars(resources) 171 } allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>>172 fn allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> { 173 (**self).allocate_device_bars(resources) 174 } register_device_capabilities(&mut self) -> Result<()>175 fn register_device_capabilities(&mut self) -> Result<()> { 176 (**self).register_device_capabilities() 177 } ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)>178 fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> { 179 (**self).ioeventfds() 180 } config_registers(&self) -> &PciConfiguration181 fn config_registers(&self) -> &PciConfiguration { 182 (**self).config_registers() 183 } config_registers_mut(&mut self) -> &mut PciConfiguration184 fn config_registers_mut(&mut self) -> &mut PciConfiguration { 185 (**self).config_registers_mut() 186 } read_bar(&mut self, addr: u64, data: &mut [u8])187 fn read_bar(&mut self, addr: u64, data: &mut [u8]) { 188 (**self).read_bar(addr, data) 189 } write_bar(&mut self, addr: u64, data: &[u8])190 fn write_bar(&mut self, addr: u64, data: &[u8]) { 191 (**self).write_bar(addr, data) 192 } 193 /// Invoked when the device is sandboxed. on_device_sandboxed(&mut self)194 fn on_device_sandboxed(&mut self) { 195 (**self).on_device_sandboxed() 196 } 197 } 198