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