2019-04-18 09:59:12 +00:00
|
|
|
// Copyright 2018 The Chromium OS Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
2019-05-08 10:22:53 +00:00
|
|
|
// found in the LICENSE-BSD-3-Clause file.
|
2019-04-18 09:59:12 +00:00
|
|
|
|
2019-07-19 17:50:30 +00:00
|
|
|
use crate::configuration::{self, PciBarRegionType};
|
2022-04-14 16:13:57 +00:00
|
|
|
use crate::PciBarConfiguration;
|
2019-10-30 15:15:38 +00:00
|
|
|
use std::any::Any;
|
2019-04-18 09:59:12 +00:00
|
|
|
use std::fmt::{self, Display};
|
2022-01-05 16:48:09 +00:00
|
|
|
use std::sync::{Arc, Barrier, Mutex};
|
2019-10-29 01:15:08 +00:00
|
|
|
use std::{self, io, result};
|
2021-10-15 10:38:06 +00:00
|
|
|
use vm_allocator::{AddressAllocator, SystemAllocator};
|
2022-04-07 12:22:07 +00:00
|
|
|
use vm_device::{BusDevice, Resource};
|
2019-04-18 09:59:12 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
|
|
|
/// Setup of the device capabilities failed.
|
|
|
|
CapabilitiesSetup(configuration::Error),
|
|
|
|
/// Allocating space for an IO BAR failed.
|
|
|
|
IoAllocationFailed(u64),
|
|
|
|
/// Registering an IO BAR failed.
|
|
|
|
IoRegistrationFailed(u64, configuration::Error),
|
2022-04-15 09:27:53 +00:00
|
|
|
/// Expected resource not found.
|
2022-04-07 12:22:07 +00:00
|
|
|
MissingResource,
|
2022-10-11 13:49:42 +00:00
|
|
|
/// Invalid resource.
|
|
|
|
InvalidResource(Resource),
|
2019-04-18 09:59:12 +00:00
|
|
|
}
|
|
|
|
pub type Result<T> = std::result::Result<T, Error>;
|
|
|
|
|
|
|
|
impl Display for Error {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
use self::Error::*;
|
|
|
|
|
|
|
|
match self {
|
2022-12-14 11:41:15 +00:00
|
|
|
CapabilitiesSetup(e) => write!(f, "failed to add capability {e}"),
|
2019-04-18 09:59:12 +00:00
|
|
|
IoAllocationFailed(size) => {
|
2022-12-14 11:41:15 +00:00
|
|
|
write!(f, "failed to allocate space for an IO BAR, size={size}")
|
2019-04-18 09:59:12 +00:00
|
|
|
}
|
|
|
|
IoRegistrationFailed(addr, e) => {
|
2022-12-14 11:41:15 +00:00
|
|
|
write!(f, "failed to register an IO BAR, addr={addr} err={e}")
|
2019-04-18 09:59:12 +00:00
|
|
|
}
|
2022-04-15 09:27:53 +00:00
|
|
|
MissingResource => write!(f, "failed to find expected resource"),
|
2022-12-14 11:41:15 +00:00
|
|
|
InvalidResource(r) => write!(f, "invalid resource {r:?}"),
|
2019-04-18 09:59:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-28 17:50:32 +00:00
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct BarReprogrammingParams {
|
|
|
|
pub old_base: u64,
|
|
|
|
pub new_base: u64,
|
|
|
|
pub len: u64,
|
|
|
|
pub region_type: PciBarRegionType,
|
|
|
|
}
|
|
|
|
|
2019-04-18 09:59:12 +00:00
|
|
|
pub trait PciDevice: BusDevice {
|
|
|
|
/// Allocates the needed PCI BARs space using the `allocate` function which takes a size and
|
|
|
|
/// returns an address. Returns a Vec of (GuestAddress, GuestUsize) tuples.
|
|
|
|
fn allocate_bars(
|
|
|
|
&mut self,
|
2022-01-05 16:48:09 +00:00
|
|
|
_allocator: &Arc<Mutex<SystemAllocator>>,
|
2023-11-14 19:31:57 +00:00
|
|
|
_mmio32_allocator: &mut AddressAllocator,
|
|
|
|
_mmio64_allocator: &mut AddressAllocator,
|
2022-04-07 12:22:07 +00:00
|
|
|
_resources: Option<Vec<Resource>>,
|
2022-04-14 16:13:57 +00:00
|
|
|
) -> Result<Vec<PciBarConfiguration>> {
|
2019-04-18 09:59:12 +00:00
|
|
|
Ok(Vec::new())
|
|
|
|
}
|
|
|
|
|
2020-03-11 08:25:26 +00:00
|
|
|
/// Frees the PCI BARs previously allocated with a call to allocate_bars().
|
2021-10-15 10:38:06 +00:00
|
|
|
fn free_bars(
|
|
|
|
&mut self,
|
|
|
|
_allocator: &mut SystemAllocator,
|
2023-11-14 19:31:57 +00:00
|
|
|
_mmio32_allocator: &mut AddressAllocator,
|
|
|
|
_mmio64_allocator: &mut AddressAllocator,
|
2021-10-15 10:38:06 +00:00
|
|
|
) -> Result<()> {
|
2020-03-11 08:25:26 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-06-05 09:24:18 +00:00
|
|
|
/// Sets a register in the configuration space.
|
|
|
|
/// * `reg_idx` - The index of the config register to modify.
|
|
|
|
/// * `offset` - Offset in to the register.
|
2020-12-04 09:41:21 +00:00
|
|
|
fn write_config_register(
|
|
|
|
&mut self,
|
|
|
|
reg_idx: usize,
|
|
|
|
offset: u64,
|
|
|
|
data: &[u8],
|
|
|
|
) -> Option<Arc<Barrier>>;
|
2019-06-05 09:24:18 +00:00
|
|
|
/// Gets a register from the configuration space.
|
|
|
|
/// * `reg_idx` - The index of the config register to read.
|
2020-01-29 16:16:33 +00:00
|
|
|
fn read_config_register(&mut self, reg_idx: usize) -> u32;
|
2019-10-28 17:50:32 +00:00
|
|
|
/// Detects if a BAR is being reprogrammed.
|
|
|
|
fn detect_bar_reprogramming(
|
|
|
|
&mut self,
|
|
|
|
_reg_idx: usize,
|
|
|
|
_data: &[u8],
|
|
|
|
) -> Option<BarReprogrammingParams> {
|
|
|
|
None
|
|
|
|
}
|
2019-04-18 09:59:12 +00:00
|
|
|
/// Reads from a BAR region mapped in to the device.
|
|
|
|
/// * `addr` - The guest address inside the BAR.
|
|
|
|
/// * `data` - Filled with the data from `addr`.
|
2019-06-04 06:51:00 +00:00
|
|
|
fn read_bar(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) {}
|
2019-04-18 09:59:12 +00:00
|
|
|
/// Writes to a BAR region mapped in to the device.
|
|
|
|
/// * `addr` - The guest address inside the BAR.
|
|
|
|
/// * `data` - The data to write.
|
2020-12-04 09:41:21 +00:00
|
|
|
fn write_bar(&mut self, _base: u64, _offset: u64, _data: &[u8]) -> Option<Arc<Barrier>> {
|
|
|
|
None
|
|
|
|
}
|
2019-10-28 15:47:35 +00:00
|
|
|
/// Relocates the BAR to a different address in guest address space.
|
2019-10-29 01:15:08 +00:00
|
|
|
fn move_bar(&mut self, _old_base: u64, _new_base: u64) -> result::Result<(), io::Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
2019-10-30 15:15:38 +00:00
|
|
|
/// Provides a mutable reference to the Any trait. This is useful to let
|
|
|
|
/// the caller have access to the underlying type behind the trait.
|
|
|
|
fn as_any(&mut self) -> &mut dyn Any;
|
2022-04-07 16:16:19 +00:00
|
|
|
|
|
|
|
/// Optionally returns a unique identifier.
|
|
|
|
fn id(&self) -> Option<String>;
|
2019-04-18 09:59:12 +00:00
|
|
|
}
|
2019-10-18 22:04:44 +00:00
|
|
|
|
|
|
|
/// This trait defines a set of functions which can be triggered whenever a
|
|
|
|
/// PCI device is modified in any way.
|
|
|
|
pub trait DeviceRelocation: Send + Sync {
|
|
|
|
/// The BAR needs to be moved to a different location in the guest address
|
|
|
|
/// space. This follows a decision from the software running in the guest.
|
|
|
|
fn move_bar(
|
|
|
|
&self,
|
|
|
|
old_base: u64,
|
|
|
|
new_base: u64,
|
|
|
|
len: u64,
|
|
|
|
pci_dev: &mut dyn PciDevice,
|
|
|
|
region_type: PciBarRegionType,
|
2019-10-29 01:15:08 +00:00
|
|
|
) -> result::Result<(), io::Error>;
|
2019-10-18 22:04:44 +00:00
|
|
|
}
|