mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
This commit refactors the PCI bus struct. It has two major focuses. First, we change the type of `device_ids` in `PciBus` to an array. A fixed-size array better reflects real PCI bus constraints, especially its limited number of PCI devices. Moreover, it can't be grown accidentally. The second focus is changing the type of the key of `devices` in `PciBus` to `u8`, since device IDs are not allowed to exceed 31. We furthermore replace magic numbers with constants and make them publicly available so we can use them in a follow-up change when parsing user input. Signed-off-by: Pascal Scholz <pascal.scholz@cyberus-technology.de> On-behalf-of: SAP pascal.scholz@sap.com
206 lines
4.9 KiB
Rust
206 lines
4.9 KiB
Rust
// 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
|
|
|
|
//! Implements pci devices and busses.
|
|
|
|
mod bus;
|
|
mod configuration;
|
|
mod device;
|
|
mod mmap;
|
|
mod msi;
|
|
mod msix;
|
|
mod vfio;
|
|
mod vfio_user;
|
|
|
|
use std::fmt::{self, Debug, Display};
|
|
use std::num::ParseIntError;
|
|
use std::str::FromStr;
|
|
|
|
use serde::de::Visitor;
|
|
|
|
pub use self::bus::{
|
|
NUM_DEVICE_IDS, PCI_ROOT_DEVICE_ID, PciBus, PciConfigIo, PciConfigMmio, PciRoot, PciRootError,
|
|
};
|
|
pub use self::configuration::{
|
|
PCI_CONFIGURATION_ID, PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciCapability,
|
|
PciCapabilityId, PciClassCode, PciConfiguration, PciExpressCapabilityId, PciHeaderType,
|
|
PciMassStorageSubclass, PciNetworkControllerSubclass, PciProgrammingInterface,
|
|
PciSerialBusSubClass, PciSubclass,
|
|
};
|
|
pub use self::device::{
|
|
BarReprogrammingParams, DeviceRelocation, Error as PciDeviceError, PciDevice,
|
|
};
|
|
pub use self::msi::{MsiCap, MsiConfig, msi_num_enabled_vectors};
|
|
pub use self::msix::{
|
|
MSIX_CONFIG_ID, MSIX_TABLE_ENTRY_SIZE, MaybeMutInterruptSourceGroup, MsixCap, MsixConfig,
|
|
MsixTableEntry,
|
|
};
|
|
pub use self::vfio::{MmioRegion, VfioDmaMapping, VfioPciDevice, VfioPciError};
|
|
pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError};
|
|
|
|
/// PCI has four interrupt pins A->D.
|
|
#[derive(Copy, Clone)]
|
|
pub enum PciInterruptPin {
|
|
IntA,
|
|
IntB,
|
|
IntC,
|
|
IntD,
|
|
}
|
|
|
|
impl PciInterruptPin {
|
|
pub fn to_mask(self) -> u32 {
|
|
self as u32
|
|
}
|
|
}
|
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
pub const PCI_CONFIG_IO_PORT: u64 = 0xcf8;
|
|
#[cfg(target_arch = "x86_64")]
|
|
pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8;
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd)]
|
|
pub struct PciBdf(u32);
|
|
|
|
struct PciBdfVisitor;
|
|
|
|
impl Visitor<'_> for PciBdfVisitor {
|
|
type Value = PciBdf;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("struct PciBdf")
|
|
}
|
|
|
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
|
where
|
|
E: serde::de::Error,
|
|
{
|
|
Ok(v.into())
|
|
}
|
|
}
|
|
|
|
impl<'de> serde::Deserialize<'de> for PciBdf {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
deserializer.deserialize_str(PciBdfVisitor)
|
|
}
|
|
}
|
|
|
|
impl serde::Serialize for PciBdf {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: serde::Serializer,
|
|
{
|
|
serializer.collect_str(&self.to_string())
|
|
}
|
|
}
|
|
|
|
impl PciBdf {
|
|
pub fn segment(&self) -> u16 {
|
|
((self.0 >> 16) & 0xffff) as u16
|
|
}
|
|
|
|
pub fn bus(&self) -> u8 {
|
|
((self.0 >> 8) & 0xff) as u8
|
|
}
|
|
|
|
pub fn device(&self) -> u8 {
|
|
((self.0 >> 3) & 0x1f) as u8
|
|
}
|
|
|
|
pub fn function(&self) -> u8 {
|
|
(self.0 & 0x7) as u8
|
|
}
|
|
|
|
pub fn new(segment: u16, bus: u8, device: u8, function: u8) -> Self {
|
|
Self(
|
|
((segment as u32) << 16)
|
|
| ((bus as u32) << 8)
|
|
| (((device & 0x1f) as u32) << 3)
|
|
| (function & 0x7) as u32,
|
|
)
|
|
}
|
|
}
|
|
|
|
impl From<u32> for PciBdf {
|
|
fn from(bdf: u32) -> Self {
|
|
Self(bdf)
|
|
}
|
|
}
|
|
|
|
impl From<PciBdf> for u32 {
|
|
fn from(bdf: PciBdf) -> Self {
|
|
bdf.0
|
|
}
|
|
}
|
|
|
|
impl From<&PciBdf> for u32 {
|
|
fn from(bdf: &PciBdf) -> Self {
|
|
bdf.0
|
|
}
|
|
}
|
|
|
|
impl From<PciBdf> for u16 {
|
|
fn from(bdf: PciBdf) -> Self {
|
|
(bdf.0 & 0xffff) as u16
|
|
}
|
|
}
|
|
|
|
impl From<&PciBdf> for u16 {
|
|
fn from(bdf: &PciBdf) -> Self {
|
|
(bdf.0 & 0xffff) as u16
|
|
}
|
|
}
|
|
|
|
impl Debug for PciBdf {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(
|
|
f,
|
|
"{:04x}:{:02x}:{:02x}.{:01x}",
|
|
self.segment(),
|
|
self.bus(),
|
|
self.device(),
|
|
self.function()
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Display for PciBdf {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(
|
|
f,
|
|
"{:04x}:{:02x}:{:02x}.{:01x}",
|
|
self.segment(),
|
|
self.bus(),
|
|
self.device(),
|
|
self.function()
|
|
)
|
|
}
|
|
}
|
|
|
|
impl FromStr for PciBdf {
|
|
type Err = ParseIntError;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
let items: Vec<&str> = s.split('.').collect();
|
|
assert_eq!(items.len(), 2);
|
|
let function = u8::from_str_radix(items[1], 16)?;
|
|
let items: Vec<&str> = items[0].split(':').collect();
|
|
assert_eq!(items.len(), 3);
|
|
let segment = u16::from_str_radix(items[0], 16)?;
|
|
let bus = u8::from_str_radix(items[1], 16)?;
|
|
let device = u8::from_str_radix(items[2], 16)?;
|
|
Ok(PciBdf::new(segment, bus, device, function))
|
|
}
|
|
}
|
|
|
|
impl From<&str> for PciBdf {
|
|
fn from(bdf: &str) -> Self {
|
|
Self::from_str(bdf).unwrap()
|
|
}
|
|
}
|