mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-23 06:05:21 +00:00
vmm: Move PciSegment to new file
Move the PciSegment struct and the associated code to a new file. This will allow some clearer separation between the core DeviceManager and PCI handling. Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
0eb78ab177
commit
84fc0e093d
@ -22,6 +22,7 @@ use crate::interrupt::LegacyUserspaceInterruptManager;
|
||||
#[cfg(feature = "acpi")]
|
||||
use crate::memory_manager::MEMORY_MANAGER_ACPI_SIZE;
|
||||
use crate::memory_manager::{Error as MemoryManagerError, MemoryManager};
|
||||
use crate::pci_segment::PciSegment;
|
||||
use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
||||
use crate::serial_manager::{Error as SerialManagerError, SerialManager};
|
||||
use crate::sigwinch_listener::start_sigwinch_listener;
|
||||
@ -66,12 +67,12 @@ use libc::{
|
||||
isatty, tcgetattr, tcsetattr, termios, ECHO, ICANON, ISIG, MAP_NORESERVE, MAP_PRIVATE,
|
||||
MAP_SHARED, O_TMPFILE, PROT_READ, PROT_WRITE, TCSANOW,
|
||||
};
|
||||
use pci::{
|
||||
DeviceRelocation, PciBarRegionType, PciBus, PciConfigMmio, PciDevice, PciRoot, VfioPciDevice,
|
||||
VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError,
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use pci::{PciConfigIo, PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
|
||||
use pci::PciConfigIo;
|
||||
use pci::{
|
||||
DeviceRelocation, PciBarRegionType, PciDevice, VfioPciDevice, VfioUserDmaMapping,
|
||||
VfioUserPciDevice, VfioUserPciDeviceError,
|
||||
};
|
||||
use seccompiler::SeccompAction;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
@ -530,11 +531,11 @@ impl Console {
|
||||
}
|
||||
}
|
||||
|
||||
struct AddressManager {
|
||||
allocator: Arc<Mutex<SystemAllocator>>,
|
||||
pub(crate) struct AddressManager {
|
||||
pub(crate) allocator: Arc<Mutex<SystemAllocator>>,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
io_bus: Arc<Bus>,
|
||||
mmio_bus: Arc<Bus>,
|
||||
pub(crate) io_bus: Arc<Bus>,
|
||||
pub(crate) mmio_bus: Arc<Bus>,
|
||||
vm: Arc<dyn hypervisor::Vm>,
|
||||
device_tree: Arc<Mutex<DeviceTree>>,
|
||||
}
|
||||
@ -895,120 +896,6 @@ pub struct DeviceManager {
|
||||
restoring: bool,
|
||||
}
|
||||
|
||||
struct PciSegment {
|
||||
id: u16,
|
||||
pci_bus: Arc<Mutex<PciBus>>,
|
||||
pci_config_mmio: Arc<Mutex<PciConfigMmio>>,
|
||||
mmio_config_address: u64,
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pci_config_io: Option<Arc<Mutex<PciConfigIo>>>,
|
||||
|
||||
// Bitmap of PCI devices to hotplug.
|
||||
pci_devices_up: u32,
|
||||
// Bitmap of PCI devices to hotunplug.
|
||||
pci_devices_down: u32,
|
||||
// List of allocated IRQs for each PCI slot.
|
||||
pci_irq_slots: [u8; 32],
|
||||
}
|
||||
|
||||
impl PciSegment {
|
||||
fn new_default_segment(
|
||||
address_manager: &Arc<AddressManager>,
|
||||
) -> DeviceManagerResult<PciSegment> {
|
||||
let pci_root = PciRoot::new(None);
|
||||
let pci_bus = Arc::new(Mutex::new(PciBus::new(
|
||||
pci_root,
|
||||
Arc::clone(address_manager) as Arc<dyn DeviceRelocation>,
|
||||
)));
|
||||
|
||||
let pci_config_mmio = Arc::new(Mutex::new(PciConfigMmio::new(Arc::clone(&pci_bus))));
|
||||
address_manager
|
||||
.mmio_bus
|
||||
.insert(
|
||||
Arc::clone(&pci_config_mmio) as Arc<Mutex<dyn BusDevice>>,
|
||||
arch::layout::PCI_MMCONFIG_START.0,
|
||||
arch::layout::PCI_MMCONFIG_SIZE,
|
||||
)
|
||||
.map_err(DeviceManagerError::BusError)?;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let pci_config_io = Arc::new(Mutex::new(PciConfigIo::new(Arc::clone(&pci_bus))));
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
address_manager
|
||||
.io_bus
|
||||
.insert(
|
||||
pci_config_io.clone(),
|
||||
PCI_CONFIG_IO_PORT,
|
||||
PCI_CONFIG_IO_PORT_SIZE,
|
||||
)
|
||||
.map_err(DeviceManagerError::BusError)?;
|
||||
|
||||
let mut segment = PciSegment {
|
||||
id: 0,
|
||||
pci_bus,
|
||||
pci_config_mmio,
|
||||
mmio_config_address: arch::layout::PCI_MMCONFIG_START.0,
|
||||
pci_devices_up: 0,
|
||||
pci_devices_down: 0,
|
||||
pci_irq_slots: [0; 32],
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pci_config_io: Some(pci_config_io),
|
||||
};
|
||||
|
||||
// Reserve some IRQs for PCI devices in case they need to support INTx.
|
||||
segment.reserve_legacy_interrupts_for_pci_devices(address_manager)?;
|
||||
|
||||
info!(
|
||||
"Adding PCI segment: id={}, PCI MMIO config address: 0x{:x}",
|
||||
segment.id, segment.mmio_config_address
|
||||
);
|
||||
Ok(segment)
|
||||
}
|
||||
|
||||
fn next_device_bdf(&self) -> DeviceManagerResult<u32> {
|
||||
// We need to shift the device id since the 3 first bits
|
||||
// are dedicated to the PCI function, and we know we don't
|
||||
// do multifunction. Also, because we only support one PCI
|
||||
// bus, the bus 0, we don't need to add anything to the
|
||||
// global device ID.
|
||||
Ok(self
|
||||
.pci_bus
|
||||
.lock()
|
||||
.unwrap()
|
||||
.next_device_id()
|
||||
.map_err(DeviceManagerError::NextPciDeviceId)?
|
||||
<< 3)
|
||||
}
|
||||
|
||||
fn reserve_legacy_interrupts_for_pci_devices(
|
||||
&mut self,
|
||||
address_manager: &Arc<AddressManager>,
|
||||
) -> DeviceManagerResult<()> {
|
||||
// Reserve 8 IRQs which will be shared across all PCI devices.
|
||||
let num_irqs = 8;
|
||||
let mut irqs: Vec<u8> = Vec::new();
|
||||
for _ in 0..num_irqs {
|
||||
irqs.push(
|
||||
address_manager
|
||||
.allocator
|
||||
.lock()
|
||||
.unwrap()
|
||||
.allocate_irq()
|
||||
.ok_or(DeviceManagerError::AllocateIrq)? as u8,
|
||||
);
|
||||
}
|
||||
|
||||
// There are 32 devices on the PCI bus, let's assign them an IRQ.
|
||||
for i in 0..32 {
|
||||
self.pci_irq_slots[i] = irqs[(i % num_irqs) as usize];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceManager {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
|
@ -46,6 +46,8 @@ use vm_migration::{protocol::*, Migratable};
|
||||
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
mod acpi;
|
||||
pub mod api;
|
||||
mod clone3;
|
||||
pub mod config;
|
||||
@ -55,14 +57,12 @@ pub mod device_tree;
|
||||
pub mod interrupt;
|
||||
pub mod memory_manager;
|
||||
pub mod migration;
|
||||
mod pci_segment;
|
||||
pub mod seccomp_filters;
|
||||
mod sigwinch_listener;
|
||||
pub mod vm;
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
mod acpi;
|
||||
mod serial_buffer;
|
||||
mod serial_manager;
|
||||
mod sigwinch_listener;
|
||||
pub mod vm;
|
||||
|
||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||
type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
|
||||
|
131
vmm/src/pci_segment.rs
Normal file
131
vmm/src/pci_segment.rs
Normal file
@ -0,0 +1,131 @@
|
||||
// Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
//
|
||||
// Portions Copyright 2017 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.
|
||||
//
|
||||
// Copyright © 2019 - 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
//
|
||||
|
||||
use crate::device_manager::{AddressManager, DeviceManagerError, DeviceManagerResult};
|
||||
use pci::{DeviceRelocation, PciBus, PciConfigMmio, PciRoot};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use pci::{PciConfigIo, PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vm_device::BusDevice;
|
||||
|
||||
pub(crate) struct PciSegment {
|
||||
id: u16,
|
||||
pub(crate) pci_bus: Arc<Mutex<PciBus>>,
|
||||
pub(crate) pci_config_mmio: Arc<Mutex<PciConfigMmio>>,
|
||||
mmio_config_address: u64,
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub(crate) pci_config_io: Option<Arc<Mutex<PciConfigIo>>>,
|
||||
|
||||
// Bitmap of PCI devices to hotplug.
|
||||
pub(crate) pci_devices_up: u32,
|
||||
// Bitmap of PCI devices to hotunplug.
|
||||
pub(crate) pci_devices_down: u32,
|
||||
// List of allocated IRQs for each PCI slot.
|
||||
pub(crate) pci_irq_slots: [u8; 32],
|
||||
}
|
||||
|
||||
impl PciSegment {
|
||||
pub(crate) fn new_default_segment(
|
||||
address_manager: &Arc<AddressManager>,
|
||||
) -> DeviceManagerResult<PciSegment> {
|
||||
let pci_root = PciRoot::new(None);
|
||||
let pci_bus = Arc::new(Mutex::new(PciBus::new(
|
||||
pci_root,
|
||||
Arc::clone(address_manager) as Arc<dyn DeviceRelocation>,
|
||||
)));
|
||||
|
||||
let pci_config_mmio = Arc::new(Mutex::new(PciConfigMmio::new(Arc::clone(&pci_bus))));
|
||||
address_manager
|
||||
.mmio_bus
|
||||
.insert(
|
||||
Arc::clone(&pci_config_mmio) as Arc<Mutex<dyn BusDevice>>,
|
||||
arch::layout::PCI_MMCONFIG_START.0,
|
||||
arch::layout::PCI_MMCONFIG_SIZE,
|
||||
)
|
||||
.map_err(DeviceManagerError::BusError)?;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let pci_config_io = Arc::new(Mutex::new(PciConfigIo::new(Arc::clone(&pci_bus))));
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
address_manager
|
||||
.io_bus
|
||||
.insert(
|
||||
pci_config_io.clone(),
|
||||
PCI_CONFIG_IO_PORT,
|
||||
PCI_CONFIG_IO_PORT_SIZE,
|
||||
)
|
||||
.map_err(DeviceManagerError::BusError)?;
|
||||
|
||||
let mut segment = PciSegment {
|
||||
id: 0,
|
||||
pci_bus,
|
||||
pci_config_mmio,
|
||||
mmio_config_address: arch::layout::PCI_MMCONFIG_START.0,
|
||||
pci_devices_up: 0,
|
||||
pci_devices_down: 0,
|
||||
pci_irq_slots: [0; 32],
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pci_config_io: Some(pci_config_io),
|
||||
};
|
||||
|
||||
// Reserve some IRQs for PCI devices in case they need to support INTx.
|
||||
segment.reserve_legacy_interrupts_for_pci_devices(address_manager)?;
|
||||
|
||||
info!(
|
||||
"Adding PCI segment: id={}, PCI MMIO config address: 0x{:x}",
|
||||
segment.id, segment.mmio_config_address
|
||||
);
|
||||
Ok(segment)
|
||||
}
|
||||
|
||||
pub(crate) fn next_device_bdf(&self) -> DeviceManagerResult<u32> {
|
||||
// We need to shift the device id since the 3 first bits
|
||||
// are dedicated to the PCI function, and we know we don't
|
||||
// do multifunction. Also, because we only support one PCI
|
||||
// bus, the bus 0, we don't need to add anything to the
|
||||
// global device ID.
|
||||
Ok(self
|
||||
.pci_bus
|
||||
.lock()
|
||||
.unwrap()
|
||||
.next_device_id()
|
||||
.map_err(DeviceManagerError::NextPciDeviceId)?
|
||||
<< 3)
|
||||
}
|
||||
|
||||
fn reserve_legacy_interrupts_for_pci_devices(
|
||||
&mut self,
|
||||
address_manager: &Arc<AddressManager>,
|
||||
) -> DeviceManagerResult<()> {
|
||||
// Reserve 8 IRQs which will be shared across all PCI devices.
|
||||
let num_irqs = 8;
|
||||
let mut irqs: Vec<u8> = Vec::new();
|
||||
for _ in 0..num_irqs {
|
||||
irqs.push(
|
||||
address_manager
|
||||
.allocator
|
||||
.lock()
|
||||
.unwrap()
|
||||
.allocate_irq()
|
||||
.ok_or(DeviceManagerError::AllocateIrq)? as u8,
|
||||
);
|
||||
}
|
||||
|
||||
// There are 32 devices on the PCI bus, let's assign them an IRQ.
|
||||
for i in 0..32 {
|
||||
self.pci_irq_slots[i] = irqs[(i % num_irqs) as usize];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user