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 std::fmt::{self, Display}; 6 7 use base::{Event, RawDescriptor}; 8 use hypervisor::Datamatch; 9 use resources::{Error as SystemAllocatorFaliure, SystemAllocator}; 10 11 use crate::bus::ConfigWriteResult; 12 use crate::pci::pci_configuration::{ 13 self, COMMAND_REG, COMMAND_REG_IO_SPACE_MASK, COMMAND_REG_MEMORY_SPACE_MASK, 14 }; 15 use crate::pci::{PciAddress, PciInterruptPin}; 16 #[cfg(feature = "audio")] 17 use crate::virtio::snd::vios_backend::Error as VioSError; 18 use crate::{BusAccessInfo, BusDevice}; 19 20 #[derive(Debug)] 21 pub enum Error { 22 /// Setup of the device capabilities failed. 23 CapabilitiesSetup(pci_configuration::Error), 24 /// Allocating space for an IO BAR failed. 25 IoAllocationFailed(u64, SystemAllocatorFaliure), 26 /// Registering an IO BAR failed. 27 IoRegistrationFailed(u64, pci_configuration::Error), 28 /// Create cras client failed. 29 #[cfg(feature = "audio")] 30 CreateCrasClientFailed(libcras::Error), 31 /// Create VioS client failed. 32 #[cfg(feature = "audio")] 33 CreateViosClientFailed(VioSError), 34 /// PCI Address allocation failure. 35 PciAllocationFailed, 36 /// PCI Address is not allocated. 37 PciAddressMissing, 38 } 39 pub type Result<T> = std::result::Result<T, Error>; 40 41 impl Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result42 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 43 use self::Error::*; 44 45 match self { 46 CapabilitiesSetup(e) => write!(f, "failed to add capability {}", e), 47 #[cfg(feature = "audio")] 48 CreateCrasClientFailed(e) => write!(f, "failed to create CRAS Client: {}", e), 49 #[cfg(feature = "audio")] 50 CreateViosClientFailed(e) => write!(f, "failed to create VioS Client: {}", e), 51 IoAllocationFailed(size, e) => write!( 52 f, 53 "failed to allocate space for an IO BAR, size={}: {}", 54 size, e 55 ), 56 IoRegistrationFailed(addr, e) => { 57 write!(f, "failed to register an IO BAR, addr={} err={}", addr, e) 58 } 59 PciAllocationFailed => write!(f, "failed to allocate PCI address"), 60 PciAddressMissing => write!(f, "PCI address is not allocated"), 61 } 62 } 63 } 64 65 pub trait PciDevice: Send { 66 /// Returns a label suitable for debug output. debug_label(&self) -> String67 fn debug_label(&self) -> String; 68 /// Allocate and return an unique bus, device and function number for this device. allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>69 fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>; 70 /// A vector of device-specific file descriptors that must be kept open 71 /// after jailing. Must be called before the process is jailed. keep_rds(&self) -> Vec<RawDescriptor>72 fn keep_rds(&self) -> Vec<RawDescriptor>; 73 /// Assign a legacy PCI IRQ to this device. 74 /// The device may write to `irq_evt` to trigger an interrupt. 75 /// When `irq_resample_evt` is signaled, the device should re-assert `irq_evt` if necessary. assign_irq( &mut self, _irq_evt: Event, _irq_resample_evt: Event, _irq_num: u32, _irq_pin: PciInterruptPin, )76 fn assign_irq( 77 &mut self, 78 _irq_evt: Event, 79 _irq_resample_evt: Event, 80 _irq_num: u32, 81 _irq_pin: PciInterruptPin, 82 ) { 83 } 84 /// Allocates the needed IO BAR space using the `allocate` function which takes a size and 85 /// returns an address. Returns a Vec of (address, length) tuples. allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>>86 fn allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> { 87 Ok(Vec::new()) 88 } 89 90 /// Allocates the needed device BAR space. Returns a Vec of (address, length) tuples. 91 /// Unlike MMIO BARs (see allocate_io_bars), device BARs are not expected to incur VM exits 92 /// - these BARs represent normal memory. allocate_device_bars( &mut self, _resources: &mut SystemAllocator, ) -> Result<Vec<(u64, u64)>>93 fn allocate_device_bars( 94 &mut self, 95 _resources: &mut SystemAllocator, 96 ) -> Result<Vec<(u64, u64)>> { 97 Ok(Vec::new()) 98 } 99 100 /// Register any capabilties specified by the device. register_device_capabilities(&mut self) -> Result<()>101 fn register_device_capabilities(&mut self) -> Result<()> { 102 Ok(()) 103 } 104 105 /// Gets a list of ioevents that should be registered with the running VM. The list is 106 /// returned as a Vec of (event, addr, datamatch) tuples. ioevents(&self) -> Vec<(&Event, u64, Datamatch)>107 fn ioevents(&self) -> Vec<(&Event, u64, Datamatch)> { 108 Vec::new() 109 } 110 111 /// Reads from a PCI configuration register. 112 /// * `reg_idx` - PCI register index (in units of 4 bytes). read_config_register(&self, reg_idx: usize) -> u32113 fn read_config_register(&self, reg_idx: usize) -> u32; 114 115 /// Writes to a PCI configuration register. 116 /// * `reg_idx` - PCI register index (in units of 4 bytes). 117 /// * `offset` - byte offset within 4-byte register. 118 /// * `data` - The data to write. write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])119 fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]); 120 121 /// Reads from a BAR region mapped in to the device. 122 /// * `addr` - The guest address inside the BAR. 123 /// * `data` - Filled with the data from `addr`. read_bar(&mut self, addr: u64, data: &mut [u8])124 fn read_bar(&mut self, addr: u64, data: &mut [u8]); 125 /// Writes to a BAR region mapped in to the device. 126 /// * `addr` - The guest address inside the BAR. 127 /// * `data` - The data to write. write_bar(&mut self, addr: u64, data: &[u8])128 fn write_bar(&mut self, addr: u64, data: &[u8]); 129 /// Invoked when the device is sandboxed. on_device_sandboxed(&mut self)130 fn on_device_sandboxed(&mut self) {} 131 } 132 133 impl<T: PciDevice> BusDevice for T { debug_label(&self) -> String134 fn debug_label(&self) -> String { 135 PciDevice::debug_label(self) 136 } 137 read(&mut self, info: BusAccessInfo, data: &mut [u8])138 fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) { 139 self.read_bar(info.address, data) 140 } 141 write(&mut self, info: BusAccessInfo, data: &[u8])142 fn write(&mut self, info: BusAccessInfo, data: &[u8]) { 143 self.write_bar(info.address, data) 144 } 145 config_register_write( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> ConfigWriteResult146 fn config_register_write( 147 &mut self, 148 reg_idx: usize, 149 offset: u64, 150 data: &[u8], 151 ) -> ConfigWriteResult { 152 let mut result = ConfigWriteResult { 153 ..Default::default() 154 }; 155 if offset as usize + data.len() > 4 { 156 return result; 157 } 158 159 if reg_idx == COMMAND_REG { 160 let old_command_reg = self.read_config_register(COMMAND_REG); 161 self.write_config_register(reg_idx, offset, data); 162 let new_command_reg = self.read_config_register(COMMAND_REG); 163 164 // Inform the caller of state changes. 165 if (old_command_reg ^ new_command_reg) & COMMAND_REG_MEMORY_SPACE_MASK != 0 { 166 result.mem_bus_new_state = 167 Some((new_command_reg & COMMAND_REG_MEMORY_SPACE_MASK) != 0); 168 } 169 if (old_command_reg ^ new_command_reg) & COMMAND_REG_IO_SPACE_MASK != 0 { 170 result.io_bus_new_state = Some((new_command_reg & COMMAND_REG_IO_SPACE_MASK) != 0); 171 } 172 } else { 173 self.write_config_register(reg_idx, offset, data); 174 } 175 176 result 177 } 178 config_register_read(&self, reg_idx: usize) -> u32179 fn config_register_read(&self, reg_idx: usize) -> u32 { 180 self.read_config_register(reg_idx) 181 } 182 on_sandboxed(&mut self)183 fn on_sandboxed(&mut self) { 184 self.on_device_sandboxed(); 185 } 186 } 187 188 impl<T: PciDevice + ?Sized> PciDevice for Box<T> { 189 /// Returns a label suitable for debug output. debug_label(&self) -> String190 fn debug_label(&self) -> String { 191 (**self).debug_label() 192 } allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>193 fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> { 194 (**self).allocate_address(resources) 195 } keep_rds(&self) -> Vec<RawDescriptor>196 fn keep_rds(&self) -> Vec<RawDescriptor> { 197 (**self).keep_rds() 198 } assign_irq( &mut self, irq_evt: Event, irq_resample_evt: Event, irq_num: u32, irq_pin: PciInterruptPin, )199 fn assign_irq( 200 &mut self, 201 irq_evt: Event, 202 irq_resample_evt: Event, 203 irq_num: u32, 204 irq_pin: PciInterruptPin, 205 ) { 206 (**self).assign_irq(irq_evt, irq_resample_evt, irq_num, irq_pin) 207 } allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>>208 fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> { 209 (**self).allocate_io_bars(resources) 210 } allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>>211 fn allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> { 212 (**self).allocate_device_bars(resources) 213 } register_device_capabilities(&mut self) -> Result<()>214 fn register_device_capabilities(&mut self) -> Result<()> { 215 (**self).register_device_capabilities() 216 } ioevents(&self) -> Vec<(&Event, u64, Datamatch)>217 fn ioevents(&self) -> Vec<(&Event, u64, Datamatch)> { 218 (**self).ioevents() 219 } read_config_register(&self, reg_idx: usize) -> u32220 fn read_config_register(&self, reg_idx: usize) -> u32 { 221 (**self).read_config_register(reg_idx) 222 } write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])223 fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { 224 (**self).write_config_register(reg_idx, offset, data) 225 } read_bar(&mut self, addr: u64, data: &mut [u8])226 fn read_bar(&mut self, addr: u64, data: &mut [u8]) { 227 (**self).read_bar(addr, data) 228 } write_bar(&mut self, addr: u64, data: &[u8])229 fn write_bar(&mut self, addr: u64, data: &[u8]) { 230 (**self).write_bar(addr, data) 231 } 232 /// Invoked when the device is sandboxed. on_device_sandboxed(&mut self)233 fn on_device_sandboxed(&mut self) { 234 (**self).on_device_sandboxed() 235 } 236 } 237 238 #[cfg(test)] 239 mod tests { 240 use super::*; 241 use pci_configuration::{PciClassCode, PciConfiguration, PciHeaderType, PciMultimediaSubclass}; 242 243 struct TestDev { 244 pub config_regs: PciConfiguration, 245 } 246 247 impl PciDevice for TestDev { debug_label(&self) -> String248 fn debug_label(&self) -> String { 249 "test".to_owned() 250 } 251 keep_rds(&self) -> Vec<RawDescriptor>252 fn keep_rds(&self) -> Vec<RawDescriptor> { 253 Vec::new() 254 } 255 read_config_register(&self, reg_idx: usize) -> u32256 fn read_config_register(&self, reg_idx: usize) -> u32 { 257 self.config_regs.read_reg(reg_idx) 258 } 259 write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])260 fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { 261 (&mut self.config_regs).write_reg(reg_idx, offset, data) 262 } 263 read_bar(&mut self, _addr: u64, _data: &mut [u8])264 fn read_bar(&mut self, _addr: u64, _data: &mut [u8]) {} 265 write_bar(&mut self, _addr: u64, _data: &[u8])266 fn write_bar(&mut self, _addr: u64, _data: &[u8]) {} 267 allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>268 fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> { 269 Err(Error::PciAllocationFailed) 270 } 271 } 272 273 #[test] config_write_result()274 fn config_write_result() { 275 let mut test_dev = TestDev { 276 config_regs: PciConfiguration::new( 277 0x1234, 278 0xABCD, 279 PciClassCode::MultimediaController, 280 &PciMultimediaSubclass::AudioDevice, 281 None, 282 PciHeaderType::Device, 283 0x5678, 284 0xEF01, 285 0, 286 ), 287 }; 288 289 // Initialize command register to an all-zeroes value. 290 test_dev.config_register_write(COMMAND_REG, 0, &0u32.to_le_bytes()); 291 292 // Enable IO space access (bit 0 of command register). 293 assert_eq!( 294 test_dev.config_register_write(COMMAND_REG, 0, &1u32.to_le_bytes()), 295 ConfigWriteResult { 296 mem_bus_new_state: None, 297 io_bus_new_state: Some(true), 298 } 299 ); 300 301 // Enable memory space access (bit 1 of command register). 302 assert_eq!( 303 test_dev.config_register_write(COMMAND_REG, 0, &3u32.to_le_bytes()), 304 ConfigWriteResult { 305 mem_bus_new_state: Some(true), 306 io_bus_new_state: None, 307 } 308 ); 309 310 // Rewrite the same IO + mem value again (result should be no change). 311 assert_eq!( 312 test_dev.config_register_write(COMMAND_REG, 0, &3u32.to_le_bytes()), 313 ConfigWriteResult { 314 mem_bus_new_state: None, 315 io_bus_new_state: None, 316 } 317 ); 318 319 // Disable IO space access, leaving mem enabled. 320 assert_eq!( 321 test_dev.config_register_write(COMMAND_REG, 0, &2u32.to_le_bytes()), 322 ConfigWriteResult { 323 mem_bus_new_state: None, 324 io_bus_new_state: Some(false), 325 } 326 ); 327 328 // Re-enable IO space and disable mem simultaneously. 329 assert_eq!( 330 test_dev.config_register_write(COMMAND_REG, 0, &1u32.to_le_bytes()), 331 ConfigWriteResult { 332 mem_bus_new_state: Some(false), 333 io_bus_new_state: Some(true), 334 } 335 ); 336 } 337 } 338