mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-01 02:55:45 +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")]
|
#[cfg(feature = "acpi")]
|
||||||
use crate::memory_manager::MEMORY_MANAGER_ACPI_SIZE;
|
use crate::memory_manager::MEMORY_MANAGER_ACPI_SIZE;
|
||||||
use crate::memory_manager::{Error as MemoryManagerError, MemoryManager};
|
use crate::memory_manager::{Error as MemoryManagerError, MemoryManager};
|
||||||
|
use crate::pci_segment::PciSegment;
|
||||||
use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
||||||
use crate::serial_manager::{Error as SerialManagerError, SerialManager};
|
use crate::serial_manager::{Error as SerialManagerError, SerialManager};
|
||||||
use crate::sigwinch_listener::start_sigwinch_listener;
|
use crate::sigwinch_listener::start_sigwinch_listener;
|
||||||
@ -66,12 +67,12 @@ use libc::{
|
|||||||
isatty, tcgetattr, tcsetattr, termios, ECHO, ICANON, ISIG, MAP_NORESERVE, MAP_PRIVATE,
|
isatty, tcgetattr, tcsetattr, termios, ECHO, ICANON, ISIG, MAP_NORESERVE, MAP_PRIVATE,
|
||||||
MAP_SHARED, O_TMPFILE, PROT_READ, PROT_WRITE, TCSANOW,
|
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")]
|
#[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 seccompiler::SeccompAction;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
@ -530,11 +531,11 @@ impl Console {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AddressManager {
|
pub(crate) struct AddressManager {
|
||||||
allocator: Arc<Mutex<SystemAllocator>>,
|
pub(crate) allocator: Arc<Mutex<SystemAllocator>>,
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
io_bus: Arc<Bus>,
|
pub(crate) io_bus: Arc<Bus>,
|
||||||
mmio_bus: Arc<Bus>,
|
pub(crate) mmio_bus: Arc<Bus>,
|
||||||
vm: Arc<dyn hypervisor::Vm>,
|
vm: Arc<dyn hypervisor::Vm>,
|
||||||
device_tree: Arc<Mutex<DeviceTree>>,
|
device_tree: Arc<Mutex<DeviceTree>>,
|
||||||
}
|
}
|
||||||
@ -895,120 +896,6 @@ pub struct DeviceManager {
|
|||||||
restoring: bool,
|
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 {
|
impl DeviceManager {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
@ -46,6 +46,8 @@ use vm_migration::{protocol::*, Migratable};
|
|||||||
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
|
#[cfg(feature = "acpi")]
|
||||||
|
mod acpi;
|
||||||
pub mod api;
|
pub mod api;
|
||||||
mod clone3;
|
mod clone3;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
@ -55,14 +57,12 @@ pub mod device_tree;
|
|||||||
pub mod interrupt;
|
pub mod interrupt;
|
||||||
pub mod memory_manager;
|
pub mod memory_manager;
|
||||||
pub mod migration;
|
pub mod migration;
|
||||||
|
mod pci_segment;
|
||||||
pub mod seccomp_filters;
|
pub mod seccomp_filters;
|
||||||
mod sigwinch_listener;
|
|
||||||
pub mod vm;
|
|
||||||
|
|
||||||
#[cfg(feature = "acpi")]
|
|
||||||
mod acpi;
|
|
||||||
mod serial_buffer;
|
mod serial_buffer;
|
||||||
mod serial_manager;
|
mod serial_manager;
|
||||||
|
mod sigwinch_listener;
|
||||||
|
pub mod vm;
|
||||||
|
|
||||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||||
type GuestRegionMmap = vm_memory::GuestRegionMmap<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