Skip to content

Commit b957bf0

Browse files
committed
pci: use VirtIO PCI transport when PCI is enabled
Create VirtIO devices using the PCI transport layer when user launched microVM with --enable-pci. Signed-off-by: Babis Chalios <bchalios@amazon.es>
1 parent a546f70 commit b957bf0

File tree

3 files changed

+154
-10
lines changed

3 files changed

+154
-10
lines changed

src/vmm/src/builder.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ pub fn build_microvm_for_boot(
169169
vm.register_memory_regions(guest_memory)
170170
.map_err(VmmError::Vm)?;
171171

172+
let vm = Arc::new(vm);
173+
172174
let entry_point = load_kernel(&boot_config.kernel_file, vm.guest_memory())?;
173175
let initrd = InitrdConfig::from_config(boot_config, vm.guest_memory())?;
174176

@@ -271,7 +273,7 @@ pub fn build_microvm_for_boot(
271273
instance_info: instance_info.clone(),
272274
shutdown_exit_code: None,
273275
kvm,
274-
vm: Arc::new(vm),
276+
vm,
275277
uffd: None,
276278
vcpus_handles: Vec::new(),
277279
vcpus_exit_evt,
@@ -554,7 +556,7 @@ fn setup_pvtime(
554556

555557
fn attach_entropy_device(
556558
device_manager: &mut DeviceManager,
557-
vm: &Vm,
559+
vm: &Arc<Vm>,
558560
cmdline: &mut LoaderKernelCmdline,
559561
entropy_device: &Arc<Mutex<Entropy>>,
560562
event_manager: &mut EventManager,
@@ -571,7 +573,7 @@ fn attach_entropy_device(
571573

572574
fn attach_block_devices<'a, I: Iterator<Item = &'a Arc<Mutex<Block>>> + Debug>(
573575
device_manager: &mut DeviceManager,
574-
vm: &Vm,
576+
vm: &Arc<Vm>,
575577
cmdline: &mut LoaderKernelCmdline,
576578
blocks: I,
577579
event_manager: &mut EventManager,
@@ -600,7 +602,7 @@ fn attach_block_devices<'a, I: Iterator<Item = &'a Arc<Mutex<Block>>> + Debug>(
600602

601603
fn attach_net_devices<'a, I: Iterator<Item = &'a Arc<Mutex<Net>>> + Debug>(
602604
device_manager: &mut DeviceManager,
603-
vm: &Vm,
605+
vm: &Arc<Vm>,
604606
cmdline: &mut LoaderKernelCmdline,
605607
net_devices: I,
606608
event_manager: &mut EventManager,
@@ -616,7 +618,7 @@ fn attach_net_devices<'a, I: Iterator<Item = &'a Arc<Mutex<Net>>> + Debug>(
616618

617619
fn attach_unixsock_vsock_device(
618620
device_manager: &mut DeviceManager,
619-
vm: &Vm,
621+
vm: &Arc<Vm>,
620622
cmdline: &mut LoaderKernelCmdline,
621623
unix_vsock: &Arc<Mutex<Vsock<VsockUnixBackend>>>,
622624
event_manager: &mut EventManager,
@@ -629,7 +631,7 @@ fn attach_unixsock_vsock_device(
629631

630632
fn attach_balloon_device(
631633
device_manager: &mut DeviceManager,
632-
vm: &Vm,
634+
vm: &Arc<Vm>,
633635
cmdline: &mut LoaderKernelCmdline,
634636
balloon: &Arc<Mutex<Balloon>>,
635637
event_manager: &mut EventManager,

src/vmm/src/device_manager/mod.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ pub enum AttachDeviceError {
7979
#[cfg(target_arch = "aarch64")]
8080
/// Error creating serial device: {0}
8181
CreateSerial(#[from] std::io::Error),
82+
/// Error attach PCI device: {0}
83+
PciTransport(#[from] PciManagerError),
8284
}
8385

8486
#[derive(Debug)]
@@ -160,8 +162,10 @@ impl DeviceManager {
160162
})
161163
}
162164

163-
/// Attaches a VirtioDevice device to the device manager and event manager.
164-
pub(crate) fn attach_virtio_device<T: 'static + VirtioDevice + MutEventSubscriber + Debug>(
165+
/// Attaches an MMIO VirtioDevice device to the device manager and event manager.
166+
pub(crate) fn attach_mmio_virtio_device<
167+
T: 'static + VirtioDevice + MutEventSubscriber + Debug,
168+
>(
165169
&mut self,
166170
vm: &Vm,
167171
id: String,
@@ -184,6 +188,25 @@ impl DeviceManager {
184188
Ok(())
185189
}
186190

191+
/// Attaches a VirtioDevice device to the device manager and event manager.
192+
pub(crate) fn attach_virtio_device<T: 'static + VirtioDevice + MutEventSubscriber + Debug>(
193+
&mut self,
194+
vm: &Arc<Vm>,
195+
id: String,
196+
device: Arc<Mutex<T>>,
197+
cmdline: &mut Cmdline,
198+
is_vhost_user: bool,
199+
) -> Result<(), AttachDeviceError> {
200+
if self.pci_devices.pci_segment.is_some() {
201+
self.pci_devices
202+
.attach_pci_virtio_device(vm, &self.resource_allocator, id, device)?;
203+
} else {
204+
self.attach_mmio_virtio_device(vm, id, device, cmdline, is_vhost_user)?;
205+
}
206+
207+
Ok(())
208+
}
209+
187210
/// Attaches a [`BootTimer`] to the VM
188211
pub(crate) fn attach_boot_timer_device(
189212
&mut self,

src/vmm/src/device_manager/pci_mngr.rs

Lines changed: 121 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
use std::sync::Arc;
4+
use std::fmt::Debug;
5+
use std::sync::{Arc, Mutex};
56

7+
use event_manager::MutEventSubscriber;
8+
use kvm_ioctls::{IoEventAddress, NoDatamatch};
9+
use log::debug;
10+
use pci::{PciBarRegionType, PciDevice, PciDeviceError, PciRootError};
611
use serde::{Deserialize, Serialize};
712
use vm_device::BusError;
813

9-
use super::resources::ResourceAllocator;
14+
use crate::Vm;
15+
use crate::device_manager::resources::ResourceAllocator;
1016
use crate::devices::pci::PciSegment;
17+
use crate::devices::virtio::device::VirtioDevice;
18+
use crate::devices::virtio::transport::pci::device::{VirtioPciDevice, VirtioPciDeviceError};
19+
use crate::vstate::vm::InterruptError;
1120

1221
#[derive(Debug, Default)]
1322
pub struct PciDevices {
@@ -21,6 +30,16 @@ pub enum PciManagerError {
2130
ResourceAllocation(#[from] vm_allocator::Error),
2231
/// Bus error: {0}
2332
Bus(#[from] BusError),
33+
/// PCI root error: {0}
34+
PciRoot(#[from] PciRootError),
35+
/// MSI error: {0}
36+
Msi(#[from] InterruptError),
37+
/// VirtIO PCI device error: {0}
38+
VirtioPciDevice(#[from] VirtioPciDeviceError),
39+
/// PCI device error: {0}
40+
PciDeviceError(#[from] PciDeviceError),
41+
/// KVM error: {0}
42+
Kvm(#[from] vmm_sys_util::errno::Error),
2443
}
2544

2645
impl PciDevices {
@@ -61,6 +80,106 @@ impl PciDevices {
6180

6281
Ok(())
6382
}
83+
84+
pub(crate) fn attach_pci_virtio_device<
85+
T: 'static + VirtioDevice + MutEventSubscriber + Debug,
86+
>(
87+
&mut self,
88+
vm: &Arc<Vm>,
89+
resource_allocator: &ResourceAllocator,
90+
id: String,
91+
device: Arc<Mutex<T>>,
92+
) -> Result<(), PciManagerError> {
93+
// We should only be reaching this point if PCI is enabled
94+
let pci_segment = self.pci_segment.as_ref().unwrap();
95+
let pci_device_bdf = pci_segment.next_device_bdf()?;
96+
debug!("Allocating BDF: {pci_device_bdf:?} for device");
97+
let mem = vm.guest_memory().clone();
98+
99+
// Allocate one MSI vector per queue, plus one for configuration
100+
let msix_num =
101+
u16::try_from(device.lock().expect("Poisoned lock").queues().len() + 1).unwrap();
102+
103+
let msix_vectors = Arc::new(Vm::create_msix_group(
104+
vm.clone(),
105+
resource_allocator,
106+
0,
107+
msix_num,
108+
)?);
109+
110+
// Create the transport
111+
let mut virtio_device = VirtioPciDevice::new(
112+
id.clone(),
113+
mem,
114+
device,
115+
msix_vectors,
116+
pci_device_bdf.into(),
117+
true,
118+
None,
119+
)?;
120+
121+
// Allocate bars
122+
let mut mmio32_allocator = resource_allocator
123+
.mmio32_memory
124+
.lock()
125+
.expect("Poisoned lock");
126+
let mut mmio64_allocator = resource_allocator
127+
.mmio64_memory
128+
.lock()
129+
.expect("Poisoned lock");
130+
131+
let bars =
132+
virtio_device.allocate_bars(&mut mmio32_allocator, &mut mmio64_allocator, None)?;
133+
134+
let virtio_device = Arc::new(Mutex::new(virtio_device));
135+
pci_segment
136+
.pci_bus
137+
.lock()
138+
.expect("Poisoned lock")
139+
.add_device(pci_device_bdf.device() as u32, virtio_device.clone())?;
140+
141+
for bar in &bars {
142+
match bar.region_type() {
143+
PciBarRegionType::IoRegion => {
144+
#[cfg(target_arch = "x86_64")]
145+
resource_allocator.pio_bus.insert(
146+
virtio_device.clone(),
147+
bar.addr(),
148+
bar.size(),
149+
)?;
150+
#[cfg(target_arch = "aarch64")]
151+
log::error!("pci: We do not support I/O region allocation")
152+
}
153+
PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
154+
resource_allocator.mmio_bus.insert(
155+
virtio_device.clone(),
156+
bar.addr(),
157+
bar.size(),
158+
)?;
159+
}
160+
}
161+
}
162+
163+
let locked_device = virtio_device.lock().expect("Poisoned lock");
164+
165+
let bar_addr = locked_device.config_bar_addr();
166+
for (i, queue_evt) in locked_device
167+
.virtio_device()
168+
.lock()
169+
.expect("Poisoned lock")
170+
.queue_events()
171+
.iter()
172+
.enumerate()
173+
{
174+
const NOTIFICATION_BAR_OFFSET: u64 = 0x6000;
175+
const NOTIFY_OFF_MULTIPLIER: u64 = 4;
176+
let notify_base = bar_addr + NOTIFICATION_BAR_OFFSET;
177+
let io_addr = IoEventAddress::Mmio(notify_base + i as u64 * NOTIFY_OFF_MULTIPLIER);
178+
vm.fd().register_ioevent(queue_evt, &io_addr, NoDatamatch)?;
179+
}
180+
181+
Ok(())
182+
}
64183
}
65184

66185
#[derive(Default, Debug, Clone, Serialize, Deserialize)]

0 commit comments

Comments
 (0)