xref: /cloud-hypervisor/pci/src/device.rs (revision f6cd3bd86ded632da437b6dd6077f4237d2f71fe)
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::{BusDevice, 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: BusDevice {
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 in to 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 in to 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 in to 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