// Copyright 2018 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE-BSD-3-Clause file. // // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause use std::any::Any; use std::sync::{Arc, Barrier, Mutex}; use std::{io, result}; use thiserror::Error; use vm_allocator::{AddressAllocator, SystemAllocator}; use vm_device::Resource; use crate::PciBarConfiguration; use crate::configuration::{self, PciBarRegionType}; #[derive(Error, Debug)] pub enum Error { /// Setup of the device capabilities failed. #[error("Setup of the device capabilities failed")] CapabilitiesSetup(#[source] configuration::Error), /// Allocating space for an IO BAR failed. #[error("Allocating space for an IO BAR failed")] IoAllocationFailed(u64), /// Registering an IO BAR failed. #[error("Registering an IO BAR failed")] IoRegistrationFailed(u64, #[source] configuration::Error), /// Expected resource not found. #[error("Expected resource not found")] MissingResource, /// Invalid resource. #[error("Invalid resource: {0:?}")] InvalidResource(Resource), } pub type Result = std::result::Result; #[derive(Clone, Copy, Debug)] pub struct BarReprogrammingParams { pub old_base: u64, pub new_base: u64, pub len: u64, pub region_type: PciBarRegionType, } pub trait PciDevice: Send { /// 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, _allocator: &Arc>, _mmio32_allocator: &mut AddressAllocator, _mmio64_allocator: &mut AddressAllocator, _resources: Option>, ) -> Result> { Ok(Vec::new()) } /// Frees the PCI BARs previously allocated with a call to allocate_bars(). fn free_bars( &mut self, _allocator: &mut SystemAllocator, _mmio32_allocator: &mut AddressAllocator, _mmio64_allocator: &mut AddressAllocator, ) -> Result<()> { Ok(()) } /// Sets a register in the configuration space. /// * `reg_idx` - The index of the config register to modify. /// * `offset` - Offset into the register. fn write_config_register( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> (Vec, Option>); /// Gets a register from the configuration space. /// * `reg_idx` - The index of the config register to read. fn read_config_register(&mut self, reg_idx: usize) -> u32; /// Reads from a BAR region mapped into the device. /// * `addr` - The guest address inside the BAR. /// * `data` - Filled with the data from `addr`. fn read_bar(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) {} /// Writes to a BAR region mapped into the device. /// * `addr` - The guest address inside the BAR. /// * `data` - The data to write. fn write_bar(&mut self, _base: u64, _offset: u64, _data: &[u8]) -> Option> { None } /// Relocates the BAR to a different address in guest address space. fn move_bar(&mut self, _old_base: u64, _new_base: u64) -> result::Result<(), io::Error> { Ok(()) } /// 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(&mut self) -> &mut dyn Any; /// Optionally returns a unique identifier. fn id(&self) -> Option; } /// 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, ) -> result::Result<(), io::Error>; }