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