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-BSD-3-Clause file. 4 5 use crate::configuration::{self, PciBarRegionType}; 6 use crate::PciBarConfiguration; 7 use std::any::Any; 8 use std::fmt::{self, Display}; 9 use std::sync::{Arc, Barrier, Mutex}; 10 use std::{self, io, result}; 11 use vm_allocator::{AddressAllocator, SystemAllocator}; 12 use vm_device::{BusDevice, Resource}; 13 14 #[derive(Debug)] 15 pub enum Error { 16 /// Setup of the device capabilities failed. 17 CapabilitiesSetup(configuration::Error), 18 /// Allocating space for an IO BAR failed. 19 IoAllocationFailed(u64), 20 /// Registering an IO BAR failed. 21 IoRegistrationFailed(u64, configuration::Error), 22 /// Expected resource not found. 23 MissingResource, 24 } 25 pub type Result<T> = std::result::Result<T, Error>; 26 27 impl Display for Error { 28 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 29 use self::Error::*; 30 31 match self { 32 CapabilitiesSetup(e) => write!(f, "failed to add capability {}", e), 33 IoAllocationFailed(size) => { 34 write!(f, "failed to allocate space for an IO BAR, size={}", size) 35 } 36 IoRegistrationFailed(addr, e) => { 37 write!(f, "failed to register an IO BAR, addr={} err={}", addr, e) 38 } 39 MissingResource => write!(f, "failed to find expected resource"), 40 } 41 } 42 } 43 44 #[derive(Clone, Copy)] 45 pub struct BarReprogrammingParams { 46 pub old_base: u64, 47 pub new_base: u64, 48 pub len: u64, 49 pub region_type: PciBarRegionType, 50 } 51 52 pub trait PciDevice: BusDevice { 53 /// Allocates the needed PCI BARs space using the `allocate` function which takes a size and 54 /// returns an address. Returns a Vec of (GuestAddress, GuestUsize) tuples. 55 fn allocate_bars( 56 &mut self, 57 _allocator: &Arc<Mutex<SystemAllocator>>, 58 _mmio_allocator: &mut AddressAllocator, 59 _resources: Option<Vec<Resource>>, 60 ) -> Result<Vec<PciBarConfiguration>> { 61 Ok(Vec::new()) 62 } 63 64 /// Frees the PCI BARs previously allocated with a call to allocate_bars(). 65 fn free_bars( 66 &mut self, 67 _allocator: &mut SystemAllocator, 68 _mmio_allocator: &mut AddressAllocator, 69 ) -> Result<()> { 70 Ok(()) 71 } 72 73 /// Sets a register in the configuration space. 74 /// * `reg_idx` - The index of the config register to modify. 75 /// * `offset` - Offset in to the register. 76 fn write_config_register( 77 &mut self, 78 reg_idx: usize, 79 offset: u64, 80 data: &[u8], 81 ) -> Option<Arc<Barrier>>; 82 /// Gets a register from the configuration space. 83 /// * `reg_idx` - The index of the config register to read. 84 fn read_config_register(&mut self, reg_idx: usize) -> u32; 85 /// Detects if a BAR is being reprogrammed. 86 fn detect_bar_reprogramming( 87 &mut self, 88 _reg_idx: usize, 89 _data: &[u8], 90 ) -> Option<BarReprogrammingParams> { 91 None 92 } 93 /// Reads from a BAR region mapped in to the device. 94 /// * `addr` - The guest address inside the BAR. 95 /// * `data` - Filled with the data from `addr`. 96 fn read_bar(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) {} 97 /// Writes to a BAR region mapped in to the device. 98 /// * `addr` - The guest address inside the BAR. 99 /// * `data` - The data to write. 100 fn write_bar(&mut self, _base: u64, _offset: u64, _data: &[u8]) -> Option<Arc<Barrier>> { 101 None 102 } 103 /// Relocates the BAR to a different address in guest address space. 104 fn move_bar(&mut self, _old_base: u64, _new_base: u64) -> result::Result<(), io::Error> { 105 Ok(()) 106 } 107 /// Provides a mutable reference to the Any trait. This is useful to let 108 /// the caller have access to the underlying type behind the trait. 109 fn as_any(&mut self) -> &mut dyn Any; 110 111 /// Optionally returns a unique identifier. 112 fn id(&self) -> Option<String>; 113 } 114 115 /// This trait defines a set of functions which can be triggered whenever a 116 /// PCI device is modified in any way. 117 pub trait DeviceRelocation: Send + Sync { 118 /// The BAR needs to be moved to a different location in the guest address 119 /// space. This follows a decision from the software running in the guest. 120 fn move_bar( 121 &self, 122 old_base: u64, 123 new_base: u64, 124 len: u64, 125 pci_dev: &mut dyn PciDevice, 126 region_type: PciBarRegionType, 127 ) -> result::Result<(), io::Error>; 128 } 129