1
1
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
- use std:: sync:: Arc ;
4
+ use std:: collections:: HashMap ;
5
+ use std:: fmt:: Debug ;
6
+ use std:: sync:: { Arc , Mutex } ;
5
7
8
+ use event_manager:: MutEventSubscriber ;
9
+ use log:: debug;
10
+ use pci:: { PciBarRegionType , PciDevice , PciDeviceError , PciRootError } ;
6
11
use serde:: { Deserialize , Serialize } ;
7
12
use vm_device:: BusError ;
8
13
9
- use super :: resources:: ResourceAllocator ;
14
+ use crate :: Vm ;
15
+ use crate :: device_manager:: resources:: ResourceAllocator ;
10
16
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 ;
11
20
12
21
#[ derive( Debug , Default ) ]
13
22
pub struct PciDevices {
14
23
/// PCIe segment of the VMM, if PCI is enabled. We currently support a single PCIe segment.
15
24
pub pci_segment : Option < PciSegment > ,
25
+ /// All VirtIO PCI devices of the system
26
+ pub virtio_devices : HashMap < ( u32 , String ) , Arc < Mutex < VirtioPciDevice > > > ,
16
27
}
17
28
18
29
#[ derive( Debug , thiserror:: Error , displaydoc:: Display ) ]
@@ -21,6 +32,16 @@ pub enum PciManagerError {
21
32
ResourceAllocation ( #[ from] vm_allocator:: Error ) ,
22
33
/// Bus error: {0}
23
34
Bus ( #[ from] BusError ) ,
35
+ /// PCI root error: {0}
36
+ PciRoot ( #[ from] PciRootError ) ,
37
+ /// MSI error: {0}
38
+ Msi ( #[ from] InterruptError ) ,
39
+ /// VirtIO PCI device error: {0}
40
+ VirtioPciDevice ( #[ from] VirtioPciDeviceError ) ,
41
+ /// PCI device error: {0}
42
+ PciDeviceError ( #[ from] PciDeviceError ) ,
43
+ /// KVM error: {0}
44
+ Kvm ( #[ from] vmm_sys_util:: errno:: Error ) ,
24
45
}
25
46
26
47
impl PciDevices {
@@ -61,6 +82,112 @@ impl PciDevices {
61
82
62
83
Ok ( ( ) )
63
84
}
85
+
86
+ fn register_bars_with_bus (
87
+ resource_allocator : & ResourceAllocator ,
88
+ virtio_device : & Arc < Mutex < VirtioPciDevice > > ,
89
+ ) -> Result < ( ) , PciManagerError > {
90
+ for bar in & virtio_device. lock ( ) . expect ( "Poisoned lock" ) . bar_regions {
91
+ match bar. region_type ( ) {
92
+ PciBarRegionType :: IoRegion => {
93
+ debug ! (
94
+ "Inserting I/O BAR region: {:#x}:{:#x}" ,
95
+ bar. addr( ) ,
96
+ bar. size( )
97
+ ) ;
98
+ #[ cfg( target_arch = "x86_64" ) ]
99
+ resource_allocator. pio_bus . insert (
100
+ virtio_device. clone ( ) ,
101
+ bar. addr ( ) ,
102
+ bar. size ( ) ,
103
+ ) ?;
104
+ #[ cfg( target_arch = "aarch64" ) ]
105
+ log:: error!( "pci: We do not support I/O region allocation" )
106
+ }
107
+ PciBarRegionType :: Memory32BitRegion | PciBarRegionType :: Memory64BitRegion => {
108
+ debug ! (
109
+ "Inserting MMIO BAR region: {:#x}:{:#x}" ,
110
+ bar. addr( ) ,
111
+ bar. size( )
112
+ ) ;
113
+ resource_allocator. mmio_bus . insert (
114
+ virtio_device. clone ( ) ,
115
+ bar. addr ( ) ,
116
+ bar. size ( ) ,
117
+ ) ?;
118
+ }
119
+ }
120
+ }
121
+
122
+ Ok ( ( ) )
123
+ }
124
+
125
+ pub ( crate ) fn attach_pci_virtio_device <
126
+ T : ' static + VirtioDevice + MutEventSubscriber + Debug ,
127
+ > (
128
+ & mut self ,
129
+ vm : & Arc < Vm > ,
130
+ resource_allocator : & ResourceAllocator ,
131
+ id : String ,
132
+ device : Arc < Mutex < T > > ,
133
+ ) -> Result < ( ) , PciManagerError > {
134
+ // We should only be reaching this point if PCI is enabled
135
+ let pci_segment = self . pci_segment . as_ref ( ) . unwrap ( ) ;
136
+ let pci_device_bdf = pci_segment. next_device_bdf ( ) ?;
137
+ debug ! ( "Allocating BDF: {pci_device_bdf:?} for device" ) ;
138
+ let mem = vm. guest_memory ( ) . clone ( ) ;
139
+
140
+ // Allocate one MSI vector per queue, plus one for configuration
141
+ let msix_num =
142
+ u16:: try_from ( device. lock ( ) . expect ( "Poisoned lock" ) . queues ( ) . len ( ) + 1 ) . unwrap ( ) ;
143
+
144
+ let msix_vectors = Arc :: new ( Vm :: create_msix_group (
145
+ vm. clone ( ) ,
146
+ resource_allocator,
147
+ msix_num,
148
+ ) ?) ;
149
+
150
+ // Create the transport
151
+ let mut virtio_device =
152
+ VirtioPciDevice :: new ( id. clone ( ) , mem, device, msix_vectors, pci_device_bdf. into ( ) ) ?;
153
+
154
+ // Allocate bars
155
+ let mut mmio32_allocator = resource_allocator
156
+ . mmio32_memory
157
+ . lock ( )
158
+ . expect ( "Poisoned lock" ) ;
159
+ let mut mmio64_allocator = resource_allocator
160
+ . mmio64_memory
161
+ . lock ( )
162
+ . expect ( "Poisoned lock" ) ;
163
+
164
+ virtio_device. allocate_bars ( & mut mmio32_allocator, & mut mmio64_allocator, None ) ?;
165
+
166
+ let virtio_device = Arc :: new ( Mutex :: new ( virtio_device) ) ;
167
+ pci_segment
168
+ . pci_bus
169
+ . lock ( )
170
+ . expect ( "Poisoned lock" )
171
+ . add_device ( pci_device_bdf. device ( ) as u32 , virtio_device. clone ( ) ) ?;
172
+
173
+ Self :: register_bars_with_bus ( resource_allocator, & virtio_device) ?;
174
+ virtio_device
175
+ . lock ( )
176
+ . expect ( "Poisoned lock" )
177
+ . register_notification_ioevent ( vm) ?;
178
+
179
+ Ok ( ( ) )
180
+ }
181
+
182
+ /// Gets the specified device.
183
+ pub fn get_virtio_device (
184
+ & self ,
185
+ device_type : u32 ,
186
+ device_id : & str ,
187
+ ) -> Option < & Arc < Mutex < VirtioPciDevice > > > {
188
+ self . virtio_devices
189
+ . get ( & ( device_type, device_id. to_string ( ) ) )
190
+ }
64
191
}
65
192
66
193
#[ derive( Default , Debug , Clone , Serialize , Deserialize ) ]
0 commit comments