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