diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index cfac818fa..41bc926a5 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -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>, +pub(crate) struct AddressManager { + pub(crate) allocator: Arc>, #[cfg(target_arch = "x86_64")] - io_bus: Arc, - mmio_bus: Arc, + pub(crate) io_bus: Arc, + pub(crate) mmio_bus: Arc, vm: Arc, device_tree: Arc>, } @@ -895,120 +896,6 @@ pub struct DeviceManager { restoring: bool, } -struct PciSegment { - id: u16, - pci_bus: Arc>, - pci_config_mmio: Arc>, - mmio_config_address: u64, - - #[cfg(target_arch = "x86_64")] - pci_config_io: Option>>, - - // 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, - ) -> DeviceManagerResult { - let pci_root = PciRoot::new(None); - let pci_bus = Arc::new(Mutex::new(PciBus::new( - pci_root, - Arc::clone(address_manager) as Arc, - ))); - - 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>, - 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 { - // 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, - ) -> DeviceManagerResult<()> { - // Reserve 8 IRQs which will be shared across all PCI devices. - let num_irqs = 8; - let mut irqs: Vec = 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( diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index dc1ee1a44..1443e19cb 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -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; type GuestRegionMmap = vm_memory::GuestRegionMmap; diff --git a/vmm/src/pci_segment.rs b/vmm/src/pci_segment.rs new file mode 100644 index 000000000..3859d9646 --- /dev/null +++ b/vmm/src/pci_segment.rs @@ -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>, + pub(crate) pci_config_mmio: Arc>, + mmio_config_address: u64, + + #[cfg(target_arch = "x86_64")] + pub(crate) pci_config_io: Option>>, + + // 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, + ) -> DeviceManagerResult { + let pci_root = PciRoot::new(None); + let pci_bus = Arc::new(Mutex::new(PciBus::new( + pci_root, + Arc::clone(address_manager) as Arc, + ))); + + 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>, + 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 { + // 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, + ) -> DeviceManagerResult<()> { + // Reserve 8 IRQs which will be shared across all PCI devices. + let num_irqs = 8; + let mut irqs: Vec = 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(()) + } +}