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