vmm_core/
device_builder.rs1use anyhow::Context as _;
7use guestmem::DoorbellRegistration;
8use guestmem::GuestMemory;
9use pci_core::msi::MsiInterruptSet;
10use pci_core::msi::MsiInterruptTarget;
11use std::sync::Arc;
12use vm_resource::Resource;
13use vm_resource::ResourceResolver;
14use vm_resource::kind::PciDeviceHandleKind;
15use vmbus_server::Guid;
16use vmbus_server::VmbusServerControl;
17use vmcore::vm_task::VmTaskDriverSource;
18use vmcore::vpci_msi::VpciInterruptMapper;
19use vmotherboard::ChipsetBuilder;
20
21pub async fn build_vpci_device(
24 driver_source: &VmTaskDriverSource,
25 resolver: &ResourceResolver,
26 guest_memory: &GuestMemory,
27 vmbus: &VmbusServerControl,
28 instance_id: Guid,
29 resource: Resource<PciDeviceHandleKind>,
30 chipset_builder: &mut ChipsetBuilder<'_>,
31 doorbell_registration: Option<Arc<dyn DoorbellRegistration>>,
32 mapper: Option<&dyn guestmem::MemoryMapper>,
33 new_virtual_device: impl FnOnce(
34 u64,
35 ) -> anyhow::Result<(
36 Arc<dyn MsiInterruptTarget>,
37 VpciInterruptMapper,
38 )>,
39) -> anyhow::Result<()> {
40 let device_name = format!("{}:vpci-{instance_id}", resource.id());
41
42 let mut msi_set = MsiInterruptSet::new();
43
44 let device = {
45 chipset_builder
46 .arc_mutex_device(device_name)
47 .with_external_pci()
48 .try_add_async(async |services| {
49 resolver
50 .resolve(
51 resource,
52 pci_resources::ResolvePciDeviceHandleParams {
53 register_msi: &mut msi_set,
54 register_mmio: &mut services.register_mmio(),
55 driver_source,
56 guest_memory,
57 doorbell_registration,
58 shared_mem_mapper: mapper,
59 },
60 )
61 .await
62 .map(|r| r.0)
63 })
64 .await?
65 };
66
67 {
68 let device_id = (instance_id.data2 as u64) << 16 | (instance_id.data3 as u64 & 0xfff8);
69 let vpci_bus_name = format!("vpci:{instance_id}");
70 chipset_builder
71 .arc_mutex_device(vpci_bus_name)
72 .try_add_async(async |services| {
73 let (msi_controller, interrupt_mapper) =
74 new_virtual_device(device_id).context(format!(
75 "failed to create virtual device, device_id {device_id} = {} | {}",
76 instance_id.data2,
77 instance_id.data3 as u64 & 0xfff8
78 ))?;
79
80 msi_set.connect(msi_controller.as_ref());
81
82 let bus = vpci::bus::VpciBus::new(
83 driver_source,
84 instance_id,
85 device,
86 &mut services.register_mmio(),
87 vmbus,
88 interrupt_mapper,
89 )
90 .await?;
91
92 anyhow::Ok(bus)
93 })
94 .await?;
95 }
96
97 Ok(())
98}