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={addr} err={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 _mmio32_allocator: &mut AddressAllocator, 62 _mmio64_allocator: &mut AddressAllocator, 63 _resources: Option<Vec<Resource>>, 64 ) -> Result<Vec<PciBarConfiguration>> { 65 Ok(Vec::new()) 66 } 67 68 /// Frees the PCI BARs previously allocated with a call to allocate_bars(). 69 fn free_bars( 70 &mut self, 71 _allocator: &mut SystemAllocator, 72 _mmio32_allocator: &mut AddressAllocator, 73 _mmio64_allocator: &mut AddressAllocator, 74 ) -> Result<()> { 75 Ok(()) 76 } 77 78 /// Sets a register in the configuration space. 79 /// * `reg_idx` - The index of the config register to modify. 80 /// * `offset` - Offset in to the register. 81 fn write_config_register( 82 &mut self, 83 reg_idx: usize, 84 offset: u64, 85 data: &[u8], 86 ) -> Option<Arc<Barrier>>; 87 /// Gets a register from the configuration space. 88 /// * `reg_idx` - The index of the config register to read. 89 fn read_config_register(&mut self, reg_idx: usize) -> u32; 90 /// Detects if a BAR is being reprogrammed. 91 fn detect_bar_reprogramming( 92 &mut self, 93 _reg_idx: usize, 94 _data: &[u8], 95 ) -> Option<BarReprogrammingParams> { 96 None 97 } 98 /// Reads from a BAR region mapped in to the device. 99 /// * `addr` - The guest address inside the BAR. 100 /// * `data` - Filled with the data from `addr`. 101 fn read_bar(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) {} 102 /// Writes to a BAR region mapped in to the device. 103 /// * `addr` - The guest address inside the BAR. 104 /// * `data` - The data to write. 105 fn write_bar(&mut self, _base: u64, _offset: u64, _data: &[u8]) -> Option<Arc<Barrier>> { 106 None 107 } 108 /// Relocates the BAR to a different address in guest address space. 109 fn move_bar(&mut self, _old_base: u64, _new_base: u64) -> result::Result<(), io::Error> { 110 Ok(()) 111 } 112 /// Provides a mutable reference to the Any trait. This is useful to let 113 /// the caller have access to the underlying type behind the trait. 114 fn as_any(&mut self) -> &mut dyn Any; 115 116 /// Optionally returns a unique identifier. 117 fn id(&self) -> Option<String>; 118 } 119 120 /// This trait defines a set of functions which can be triggered whenever a 121 /// PCI device is modified in any way. 122 pub trait DeviceRelocation: Send + Sync { 123 /// The BAR needs to be moved to a different location in the guest address 124 /// space. This follows a decision from the software running in the guest. 125 fn move_bar( 126 &self, 127 old_base: u64, 128 new_base: u64, 129 len: u64, 130 pci_dev: &mut dyn PciDevice, 131 region_type: PciBarRegionType, 132 ) -> result::Result<(), io::Error>; 133 } 134