xref: /cloud-hypervisor/pci/src/device.rs (revision 3ce0fef7fd546467398c914dbc74d8542e45cf6f)
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