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