1use std::cmp::max;
6use std::cmp::Reverse;
7use std::collections::BTreeMap;
8use std::collections::BTreeSet;
9use std::path::Path;
10use std::path::PathBuf;
11use std::str::FromStr;
12use std::sync::Arc;
13
14use acpi_tables::aml::Aml;
15use base::debug;
16use base::error;
17use base::pagesize;
18use base::warn;
19use base::AsRawDescriptor;
20use base::AsRawDescriptors;
21use base::Event;
22use base::EventToken;
23use base::MemoryMapping;
24use base::Protection;
25use base::RawDescriptor;
26use base::Tube;
27use base::WaitContext;
28use base::WorkerThread;
29use hypervisor::MemCacheType;
30use resources::AddressRange;
31use resources::Alloc;
32use resources::AllocOptions;
33use resources::MmioType;
34use resources::SystemAllocator;
35use sync::Mutex;
36use vfio_sys::vfio::VFIO_PCI_ACPI_NTFY_IRQ_INDEX;
37use vfio_sys::*;
38use vm_control::api::VmMemoryClient;
39use vm_control::DeviceControlRequest;
40use vm_control::DeviceControlResponse;
41use vm_control::HotPlugDeviceInfo;
42use vm_control::HotPlugDeviceType;
43use vm_control::PciId;
44use vm_control::VmMemoryDestination;
45use vm_control::VmMemoryRegionId;
46use vm_control::VmMemorySource;
47
48use crate::pci::acpi::DeviceVcfgRegister;
49use crate::pci::acpi::DsmMethod;
50use crate::pci::acpi::PowerResourceMethod;
51use crate::pci::acpi::SHM_OFFSET;
52use crate::pci::msi::MsiConfig;
53use crate::pci::msi::MsiStatus;
54use crate::pci::msi::PCI_MSI_FLAGS;
55use crate::pci::msi::PCI_MSI_FLAGS_64BIT;
56use crate::pci::msi::PCI_MSI_FLAGS_MASKBIT;
57use crate::pci::msi::PCI_MSI_NEXT_POINTER;
58use crate::pci::msix::MsixConfig;
59use crate::pci::msix::MsixStatus;
60use crate::pci::msix::BITS_PER_PBA_ENTRY;
61use crate::pci::msix::MSIX_PBA_ENTRIES_MODULO;
62use crate::pci::msix::MSIX_TABLE_ENTRIES_MODULO;
63use crate::pci::pci_device::BarRange;
64use crate::pci::pci_device::Error as PciDeviceError;
65use crate::pci::pci_device::PciDevice;
66use crate::pci::pci_device::PreferredIrq;
67use crate::pci::pm::PciPmCap;
68use crate::pci::pm::PmConfig;
69use crate::pci::pm::PM_CAP_LENGTH;
70use crate::pci::PciAddress;
71use crate::pci::PciBarConfiguration;
72use crate::pci::PciBarIndex;
73use crate::pci::PciBarPrefetchable;
74use crate::pci::PciBarRegionType;
75use crate::pci::PciCapabilityID;
76use crate::pci::PciClassCode;
77use crate::pci::PciInterruptPin;
78use crate::pci::PCI_VCFG_DSM;
79use crate::pci::PCI_VCFG_NOTY;
80use crate::pci::PCI_VCFG_PM;
81use crate::pci::PCI_VENDOR_ID_INTEL;
82use crate::vfio::VfioDevice;
83use crate::vfio::VfioError;
84use crate::vfio::VfioIrqType;
85use crate::vfio::VfioPciConfig;
86use crate::IrqLevelEvent;
87use crate::Suspendable;
88
89const PCI_VENDOR_ID: u32 = 0x0;
90const PCI_DEVICE_ID: u32 = 0x2;
91const PCI_COMMAND: u32 = 0x4;
92const PCI_COMMAND_MEMORY: u8 = 0x2;
93const PCI_BASE_CLASS_CODE: u32 = 0x0B;
94const PCI_INTERRUPT_NUM: u32 = 0x3C;
95const PCI_INTERRUPT_PIN: u32 = 0x3D;
96
97const PCI_CAPABILITY_LIST: u32 = 0x34;
98const PCI_CAP_ID_MSI: u8 = 0x05;
99const PCI_CAP_ID_MSIX: u8 = 0x11;
100const PCI_CAP_ID_PM: u8 = 0x01;
101
102const PCI_CONFIG_SPACE_SIZE: u32 = 0x100;
104const PCIE_CONFIG_SPACE_SIZE: u32 = 0x1000;
106
107const PCI_EXT_CAP_ID_CAC: u16 = 0x0C;
109const PCI_EXT_CAP_ID_ARI: u16 = 0x0E;
110const PCI_EXT_CAP_ID_SRIOV: u16 = 0x10;
111const PCI_EXT_CAP_ID_REBAR: u16 = 0x15;
112
113struct VfioPmCap {
114 offset: u32,
115 capabilities: u32,
116 config: PmConfig,
117}
118
119impl VfioPmCap {
120 fn new(config: &VfioPciConfig, cap_start: u32) -> Self {
121 let mut capabilities: u32 = config.read_config(cap_start);
122 capabilities |= (PciPmCap::default_cap() as u32) << 16;
123 VfioPmCap {
124 offset: cap_start,
125 capabilities,
126 config: PmConfig::new(false),
127 }
128 }
129
130 pub fn should_trigger_pme(&mut self) -> bool {
131 self.config.should_trigger_pme()
132 }
133
134 fn is_pm_reg(&self, offset: u32) -> bool {
135 (offset >= self.offset) && (offset < self.offset + PM_CAP_LENGTH as u32)
136 }
137
138 pub fn read(&self, offset: u32) -> u32 {
139 let offset = offset - self.offset;
140 if offset == 0 {
141 self.capabilities
142 } else {
143 let mut data = 0;
144 self.config.read(&mut data);
145 data
146 }
147 }
148
149 pub fn write(&mut self, offset: u64, data: &[u8]) {
150 let offset = offset - self.offset as u64;
151 if offset >= std::mem::size_of::<u32>() as u64 {
152 let offset = offset - std::mem::size_of::<u32>() as u64;
153 self.config.write(offset, data);
154 }
155 }
156}
157
158enum VfioMsiChange {
159 Disable,
160 Enable,
161 FunctionChanged,
162}
163
164struct VfioMsiCap {
165 config: MsiConfig,
166 offset: u32,
167}
168
169impl VfioMsiCap {
170 fn new(
171 config: &VfioPciConfig,
172 msi_cap_start: u32,
173 vm_socket_irq: Tube,
174 device_id: u32,
175 device_name: String,
176 ) -> Self {
177 let msi_ctl: u16 = config.read_config(msi_cap_start + PCI_MSI_FLAGS);
178 let is_64bit = (msi_ctl & PCI_MSI_FLAGS_64BIT) != 0;
179 let mask_cap = (msi_ctl & PCI_MSI_FLAGS_MASKBIT) != 0;
180
181 VfioMsiCap {
182 config: MsiConfig::new(is_64bit, mask_cap, vm_socket_irq, device_id, device_name),
183 offset: msi_cap_start,
184 }
185 }
186
187 fn is_msi_reg(&self, index: u64, len: usize) -> bool {
188 self.config.is_msi_reg(self.offset, index, len)
189 }
190
191 fn write_msi_reg(&mut self, index: u64, data: &[u8]) -> Option<VfioMsiChange> {
192 let offset = index as u32 - self.offset;
193 match self.config.write_msi_capability(offset, data) {
194 MsiStatus::Enabled => Some(VfioMsiChange::Enable),
195 MsiStatus::Disabled => Some(VfioMsiChange::Disable),
196 MsiStatus::NothingToDo => None,
197 }
198 }
199
200 fn get_msi_irqfd(&self) -> Option<&Event> {
201 self.config.get_irqfd()
202 }
203
204 fn destroy(&mut self) {
205 self.config.destroy()
206 }
207}
208
209const PCI_MSIX_FLAGS: u32 = 0x02; const PCI_MSIX_FLAGS_QSIZE: u16 = 0x07FF; const PCI_MSIX_TABLE: u32 = 0x04; const PCI_MSIX_TABLE_BIR: u32 = 0x07; const PCI_MSIX_TABLE_OFFSET: u32 = 0xFFFFFFF8; const PCI_MSIX_PBA: u32 = 0x08; const PCI_MSIX_PBA_BIR: u32 = 0x07; const PCI_MSIX_PBA_OFFSET: u32 = 0xFFFFFFF8; struct VfioMsixCap {
220 config: MsixConfig,
221 offset: u32,
222 table_size: u16,
223 table_pci_bar: PciBarIndex,
224 table_offset: u64,
225 table_size_bytes: u64,
226 pba_pci_bar: PciBarIndex,
227 pba_offset: u64,
228 pba_size_bytes: u64,
229 msix_interrupt_evt: Vec<Event>,
230}
231
232impl VfioMsixCap {
233 fn new(
234 config: &VfioPciConfig,
235 msix_cap_start: u32,
236 vm_socket_irq: Tube,
237 pci_id: u32,
238 device_name: String,
239 ) -> Self {
240 let msix_ctl: u16 = config.read_config(msix_cap_start + PCI_MSIX_FLAGS);
241 let table: u32 = config.read_config(msix_cap_start + PCI_MSIX_TABLE);
242 let table_pci_bar = (table & PCI_MSIX_TABLE_BIR) as PciBarIndex;
243 let table_offset = (table & PCI_MSIX_TABLE_OFFSET) as u64;
244 let pba: u32 = config.read_config(msix_cap_start + PCI_MSIX_PBA);
245 let pba_pci_bar = (pba & PCI_MSIX_PBA_BIR) as PciBarIndex;
246 let pba_offset = (pba & PCI_MSIX_PBA_OFFSET) as u64;
247
248 let mut table_size = (msix_ctl & PCI_MSIX_FLAGS_QSIZE) as u64 + 1;
249 if table_pci_bar == pba_pci_bar
250 && pba_offset > table_offset
251 && (table_offset + table_size * MSIX_TABLE_ENTRIES_MODULO) > pba_offset
252 {
253 table_size = (pba_offset - table_offset) / MSIX_TABLE_ENTRIES_MODULO;
254 }
255
256 let table_size_bytes = table_size * MSIX_TABLE_ENTRIES_MODULO;
257 let pba_size_bytes =
258 table_size.div_ceil(BITS_PER_PBA_ENTRY as u64) * MSIX_PBA_ENTRIES_MODULO;
259 let mut msix_interrupt_evt = Vec::new();
260 for _ in 0..table_size {
261 msix_interrupt_evt.push(Event::new().expect("failed to create msix interrupt"));
262 }
263 VfioMsixCap {
264 config: MsixConfig::new(table_size as u16, vm_socket_irq, pci_id, device_name),
265 offset: msix_cap_start,
266 table_size: table_size as u16,
267 table_pci_bar,
268 table_offset,
269 table_size_bytes,
270 pba_pci_bar,
271 pba_offset,
272 pba_size_bytes,
273 msix_interrupt_evt,
274 }
275 }
276
277 fn is_msix_control_reg(&self, offset: u32, size: u32) -> bool {
279 let control_start = self.offset + PCI_MSIX_FLAGS;
280 let control_end = control_start + 2;
281
282 offset < control_end && offset + size > control_start
283 }
284
285 fn read_msix_control(&self, data: &mut u32) {
286 *data = self.config.read_msix_capability(*data);
287 }
288
289 fn write_msix_control(&mut self, data: &[u8]) -> Option<VfioMsiChange> {
290 let old_enabled = self.config.enabled();
291 let old_masked = self.config.masked();
292
293 self.config
294 .write_msix_capability(PCI_MSIX_FLAGS.into(), data);
295
296 let new_enabled = self.config.enabled();
297 let new_masked = self.config.masked();
298
299 if !old_enabled && new_enabled {
300 Some(VfioMsiChange::Enable)
301 } else if old_enabled && !new_enabled {
302 Some(VfioMsiChange::Disable)
303 } else if new_enabled && old_masked != new_masked {
304 Some(VfioMsiChange::FunctionChanged)
305 } else {
306 None
307 }
308 }
309
310 fn is_msix_table(&self, bar_index: PciBarIndex, offset: u64) -> bool {
311 bar_index == self.table_pci_bar
312 && offset >= self.table_offset
313 && offset < self.table_offset + self.table_size_bytes
314 }
315
316 fn get_msix_table(&self, bar_index: PciBarIndex) -> Option<AddressRange> {
317 if bar_index == self.table_pci_bar {
318 AddressRange::from_start_and_size(self.table_offset, self.table_size_bytes)
319 } else {
320 None
321 }
322 }
323
324 fn read_table(&self, offset: u64, data: &mut [u8]) {
325 let offset = offset - self.table_offset;
326 self.config.read_msix_table(offset, data);
327 }
328
329 fn write_table(&mut self, offset: u64, data: &[u8]) -> MsixStatus {
330 let offset = offset - self.table_offset;
331 self.config.write_msix_table(offset, data)
332 }
333
334 fn is_msix_pba(&self, bar_index: PciBarIndex, offset: u64) -> bool {
335 bar_index == self.pba_pci_bar
336 && offset >= self.pba_offset
337 && offset < self.pba_offset + self.pba_size_bytes
338 }
339
340 fn get_msix_pba(&self, bar_index: PciBarIndex) -> Option<AddressRange> {
341 if bar_index == self.pba_pci_bar {
342 AddressRange::from_start_and_size(self.pba_offset, self.pba_size_bytes)
343 } else {
344 None
345 }
346 }
347
348 fn read_pba(&self, offset: u64, data: &mut [u8]) {
349 let offset = offset - self.pba_offset;
350 self.config.read_pba_entries(offset, data);
351 }
352
353 fn write_pba(&mut self, offset: u64, data: &[u8]) {
354 let offset = offset - self.pba_offset;
355 self.config.write_pba_entries(offset, data);
356 }
357
358 fn get_msix_irqfd(&self, index: usize) -> Option<&Event> {
359 let irqfd = self.config.get_irqfd(index);
360 if let Some(fd) = irqfd {
361 if self.msix_vector_masked(index) {
362 Some(&self.msix_interrupt_evt[index])
363 } else {
364 Some(fd)
365 }
366 } else {
367 None
368 }
369 }
370
371 fn get_msix_irqfds(&self) -> Vec<Option<&Event>> {
372 let mut irqfds = Vec::new();
373
374 for i in 0..self.table_size {
375 irqfds.push(self.get_msix_irqfd(i as usize));
376 }
377
378 irqfds
379 }
380
381 fn table_size(&self) -> usize {
382 self.table_size.into()
383 }
384
385 fn clone_msix_evt(&self) -> Vec<Event> {
386 self.msix_interrupt_evt
387 .iter()
388 .map(|irq| irq.try_clone().unwrap())
389 .collect()
390 }
391
392 fn msix_vector_masked(&self, index: usize) -> bool {
393 !self.config.enabled() || self.config.masked() || self.config.table_masked(index)
394 }
395
396 fn trigger(&mut self, index: usize) {
397 self.config.trigger(index as u16);
398 }
399
400 fn destroy(&mut self) {
401 self.config.destroy()
402 }
403}
404
405impl AsRawDescriptors for VfioMsixCap {
406 fn as_raw_descriptors(&self) -> Vec<RawDescriptor> {
407 let mut rds = vec![self.config.as_raw_descriptor()];
408 rds.extend(
409 self.msix_interrupt_evt
410 .iter()
411 .map(|evt| evt.as_raw_descriptor()),
412 );
413 rds
414 }
415}
416
417struct VfioResourceAllocator {
418 regions: BTreeSet<AddressRange>,
420}
421
422impl VfioResourceAllocator {
423 fn new(pool: AddressRange) -> Result<Self, PciDeviceError> {
429 if pool.is_empty() {
430 return Err(PciDeviceError::SizeZero);
431 }
432 let mut regions = BTreeSet::new();
433 regions.insert(pool);
434 Ok(VfioResourceAllocator { regions })
435 }
436
437 fn internal_allocate_from_slot(
438 &mut self,
439 slot: AddressRange,
440 range: AddressRange,
441 ) -> Result<u64, PciDeviceError> {
442 let slot_was_present = self.regions.remove(&slot);
443 assert!(slot_was_present);
444
445 let (before, after) = slot.non_overlapping_ranges(range);
446
447 if !before.is_empty() {
448 self.regions.insert(before);
449 }
450 if !after.is_empty() {
451 self.regions.insert(after);
452 }
453
454 Ok(range.start)
455 }
456
457 fn allocate_with_align(&mut self, size: u64, alignment: u64) -> Result<u64, PciDeviceError> {
461 if size == 0 {
462 return Err(PciDeviceError::SizeZero);
463 }
464 if !alignment.is_power_of_two() {
465 return Err(PciDeviceError::BadAlignment);
466 }
467
468 let region = self.regions.iter().find(|range| {
470 match range.start % alignment {
471 0 => range.start.checked_add(size - 1),
472 r => range.start.checked_add(size - 1 + alignment - r),
473 }
474 .is_some_and(|end| end <= range.end)
475 });
476
477 match region {
478 Some(&slot) => {
479 let start = match slot.start % alignment {
480 0 => slot.start,
481 r => slot.start + alignment - r,
482 };
483 let end = start + size - 1;
484 let range = AddressRange::from_start_and_end(start, end);
485
486 self.internal_allocate_from_slot(slot, range)
487 }
488 None => Err(PciDeviceError::OutOfSpace),
489 }
490 }
491
492 fn allocate_at_can_overlap(&mut self, range: AddressRange) -> Result<(), PciDeviceError> {
495 if range.is_empty() {
496 return Err(PciDeviceError::SizeZero);
497 }
498
499 while let Some(&slot) = self
500 .regions
501 .iter()
502 .find(|avail_range| avail_range.overlaps(range))
503 {
504 let _address = self.internal_allocate_from_slot(slot, range)?;
505 }
506 Ok(())
507 }
508}
509
510struct VfioPciWorker {
511 address: PciAddress,
512 sysfs_path: PathBuf,
513 vm_socket: Tube,
514 name: String,
515 pm_cap: Option<Arc<Mutex<VfioPmCap>>>,
516 msix_cap: Option<Arc<Mutex<VfioMsixCap>>>,
517}
518
519impl VfioPciWorker {
520 fn run(
521 &mut self,
522 req_irq_evt: Event,
523 wakeup_evt: Event,
524 acpi_notify_evt: Event,
525 kill_evt: Event,
526 msix_evt: Vec<Event>,
527 is_in_low_power: Arc<Mutex<bool>>,
528 gpe: Option<u32>,
529 notification_val: Arc<Mutex<Vec<u32>>>,
530 ) {
531 #[derive(EventToken, Debug)]
532 enum Token {
533 ReqIrq,
534 WakeUp,
535 AcpiNotifyEvent,
536 Kill,
537 MsixIrqi { index: usize },
538 }
539
540 let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
541 (&req_irq_evt, Token::ReqIrq),
542 (&wakeup_evt, Token::WakeUp),
543 (&acpi_notify_evt, Token::AcpiNotifyEvent),
544 (&kill_evt, Token::Kill),
545 ]) {
546 Ok(pc) => pc,
547 Err(e) => {
548 error!(
549 "{} failed creating vfio WaitContext: {}",
550 self.name.clone(),
551 e
552 );
553 return;
554 }
555 };
556
557 for (index, msix_int) in msix_evt.iter().enumerate() {
558 wait_ctx
559 .add(msix_int, Token::MsixIrqi { index })
560 .expect("Failed to create vfio WaitContext for msix interrupt event")
561 }
562
563 'wait: loop {
564 let events = match wait_ctx.wait() {
565 Ok(v) => v,
566 Err(e) => {
567 error!("{} failed polling vfio events: {}", self.name.clone(), e);
568 break;
569 }
570 };
571
572 for event in events.iter().filter(|e| e.is_readable) {
573 match event.token {
574 Token::MsixIrqi { index } => {
575 if let Some(msix_cap) = &self.msix_cap {
576 msix_cap.lock().trigger(index);
577 }
578 }
579 Token::ReqIrq => {
580 let device = HotPlugDeviceInfo {
581 device_type: HotPlugDeviceType::EndPoint,
582 path: self.sysfs_path.clone(),
583 hp_interrupt: false,
584 };
585
586 let request =
587 DeviceControlRequest::HotPlugVfioCommand { device, add: false };
588 if self.vm_socket.send(&request).is_ok() {
589 if let Err(e) = self.vm_socket.recv::<DeviceControlResponse>() {
590 error!("{} failed to remove vfio_device: {}", self.name.clone(), e);
591 } else {
592 break 'wait;
593 }
594 }
595 }
596 Token::WakeUp => {
597 let _ = wakeup_evt.wait();
598
599 if *is_in_low_power.lock() {
600 if let Some(pm_cap) = &self.pm_cap {
601 if pm_cap.lock().should_trigger_pme() {
602 let request = DeviceControlRequest::PciPme(
603 self.address.pme_requester_id(),
604 );
605 if self.vm_socket.send(&request).is_ok() {
606 if let Err(e) =
607 self.vm_socket.recv::<DeviceControlResponse>()
608 {
609 error!(
610 "{} failed to send PME: {}",
611 self.name.clone(),
612 e
613 );
614 }
615 }
616 }
617 }
618 }
619 }
620 Token::AcpiNotifyEvent => {
621 if let Some(gpe) = gpe {
622 if let Ok(val) = base::EventExt::read_count(&acpi_notify_evt) {
623 notification_val.lock().push(val as u32);
624 let request = DeviceControlRequest::Gpe {
625 gpe,
626 clear_evt: None,
627 };
628 if self.vm_socket.send(&request).is_ok() {
629 if let Err(e) = self.vm_socket.recv::<DeviceControlResponse>() {
630 error!("{} failed to send GPE: {}", self.name.clone(), e);
631 }
632 }
633 } else {
634 error!("{} failed to read acpi_notify_evt", self.name.clone());
635 }
636 }
637 }
638 Token::Kill => break 'wait,
639 }
640 }
641 }
642 }
643}
644
645fn get_next_from_extcap_header(cap_header: u32) -> u32 {
646 (cap_header >> 20) & 0xffc
647}
648
649fn is_skipped_ext_cap(cap_id: u16) -> bool {
650 matches!(
651 cap_id,
652 PCI_EXT_CAP_ID_ARI | PCI_EXT_CAP_ID_SRIOV | PCI_EXT_CAP_ID_REBAR
654 )
655}
656
657enum DeviceData {
658 IntelGfxData { opregion_index: u32 },
659}
660
661#[derive(Copy, Clone)]
663struct ExtCap {
664 offset: u32,
666 size: u32,
668 next: u16,
670 is_skipped: bool,
672}
673
674pub struct VfioPciDevice {
676 device: Arc<VfioDevice>,
677 config: VfioPciConfig,
678 hotplug: bool,
679 hotplug_bus_number: Option<u8>,
680 preferred_address: PciAddress,
681 pci_address: Option<PciAddress>,
682 interrupt_evt: Option<IrqLevelEvent>,
683 acpi_notification_evt: Option<Event>,
684 mmio_regions: Vec<PciBarConfiguration>,
685 io_regions: Vec<PciBarConfiguration>,
686 pm_cap: Option<Arc<Mutex<VfioPmCap>>>,
687 msi_cap: Option<VfioMsiCap>,
688 msix_cap: Option<Arc<Mutex<VfioMsixCap>>>,
689 irq_type: Option<VfioIrqType>,
690 vm_memory_client: VmMemoryClient,
691 device_data: Option<DeviceData>,
692 pm_evt: Option<Event>,
693 is_in_low_power: Arc<Mutex<bool>>,
694 worker_thread: Option<WorkerThread<VfioPciWorker>>,
695 vm_socket_vm: Option<Tube>,
696 sysfs_path: PathBuf,
697 ext_caps: Vec<ExtCap>,
699 vcfg_shm_mmap: Option<MemoryMapping>,
700 mapped_mmio_bars: BTreeMap<PciBarIndex, (u64, Vec<VmMemoryRegionId>)>,
701 activated: bool,
702 acpi_notifier_val: Arc<Mutex<Vec<u32>>>,
703 gpe: Option<u32>,
704 base_class_code: PciClassCode,
705}
706
707impl VfioPciDevice {
708 pub fn new(
710 sysfs_path: &Path,
711 device: VfioDevice,
712 hotplug: bool,
713 hotplug_bus_number: Option<u8>,
714 guest_address: Option<PciAddress>,
715 vfio_device_socket_msi: Tube,
716 vfio_device_socket_msix: Tube,
717 vm_memory_client: VmMemoryClient,
718 vfio_device_socket_vm: Tube,
719 ) -> Result<Self, PciDeviceError> {
720 let preferred_address = if let Some(bus_num) = hotplug_bus_number {
721 debug!("hotplug bus {}", bus_num);
722 PciAddress {
723 bus: bus_num,
725 dev: 0,
727 func: 0,
728 }
729 } else if let Some(guest_address) = guest_address {
730 debug!("guest PCI address {}", guest_address);
731 guest_address
732 } else {
733 let addr = PciAddress::from_str(device.device_name()).map_err(|e| {
734 PciDeviceError::PciAddressParseFailure(device.device_name().clone(), e)
735 })?;
736 debug!("parsed device PCI address {}", addr);
737 addr
738 };
739
740 let dev = Arc::new(device);
741 let config = VfioPciConfig::new(Arc::clone(&dev));
742 let mut msi_socket = Some(vfio_device_socket_msi);
743 let mut msix_socket = Some(vfio_device_socket_msix);
744 let mut msi_cap: Option<VfioMsiCap> = None;
745 let mut msix_cap: Option<Arc<Mutex<VfioMsixCap>>> = None;
746 let mut pm_cap: Option<Arc<Mutex<VfioPmCap>>> = None;
747
748 let mut is_pcie = false;
749 let mut cap_next: u32 = config.read_config::<u8>(PCI_CAPABILITY_LIST).into();
750 let vendor_id: u16 = config.read_config(PCI_VENDOR_ID);
751 let device_id: u16 = config.read_config(PCI_DEVICE_ID);
752 let base_class_code = PciClassCode::try_from(config.read_config::<u8>(PCI_BASE_CLASS_CODE))
753 .unwrap_or(PciClassCode::Other);
754
755 let pci_id = PciId::new(vendor_id, device_id);
756
757 while cap_next != 0 {
758 let cap_id: u8 = config.read_config(cap_next);
759 if cap_id == PCI_CAP_ID_PM {
760 pm_cap = Some(Arc::new(Mutex::new(VfioPmCap::new(&config, cap_next))));
761 } else if cap_id == PCI_CAP_ID_MSI {
762 if let Some(msi_socket) = msi_socket.take() {
763 msi_cap = Some(VfioMsiCap::new(
764 &config,
765 cap_next,
766 msi_socket,
767 pci_id.into(),
768 dev.device_name().to_string(),
769 ));
770 }
771 } else if cap_id == PCI_CAP_ID_MSIX {
772 if let Some(msix_socket) = msix_socket.take() {
773 msix_cap = Some(Arc::new(Mutex::new(VfioMsixCap::new(
774 &config,
775 cap_next,
776 msix_socket,
777 pci_id.into(),
778 dev.device_name().to_string(),
779 ))));
780 }
781 } else if cap_id == PciCapabilityID::PciExpress as u8 {
782 is_pcie = true;
783 }
784 let offset = cap_next + PCI_MSI_NEXT_POINTER;
785 cap_next = config.read_config::<u8>(offset).into();
786 }
787
788 let mut ext_caps: Vec<ExtCap> = Vec::new();
789 if is_pcie {
790 let mut ext_cap_next: u32 = PCI_CONFIG_SPACE_SIZE;
791 while ext_cap_next != 0 {
792 let ext_cap_config: u32 = config.read_config::<u32>(ext_cap_next);
793 if ext_cap_config == 0 {
794 break;
795 }
796 ext_caps.push(ExtCap {
797 offset: ext_cap_next,
798 size: 0,
800 next: get_next_from_extcap_header(ext_cap_config) as u16,
802 is_skipped: is_skipped_ext_cap((ext_cap_config & 0xffff) as u16),
803 });
804 ext_cap_next = get_next_from_extcap_header(ext_cap_config);
805 }
806
807 ext_caps.sort_by(|a, b| b.offset.cmp(&a.offset));
818 let mut next_offset: u32 = PCIE_CONFIG_SPACE_SIZE;
819 let mut non_skipped_next: u16 = 0;
820 for ext_cap in ext_caps.iter_mut() {
821 if !ext_cap.is_skipped {
822 ext_cap.next = non_skipped_next;
823 non_skipped_next = ext_cap.offset as u16;
824 } else if ext_cap.offset == PCI_CONFIG_SPACE_SIZE {
825 ext_cap.next = non_skipped_next;
826 }
827 ext_cap.size = next_offset - ext_cap.offset;
828 next_offset = ext_cap.offset;
829 }
830 ext_caps.reverse();
832 }
833
834 let is_intel_gfx =
835 base_class_code == PciClassCode::DisplayController && vendor_id == PCI_VENDOR_ID_INTEL;
836 let device_data = if is_intel_gfx {
837 Some(DeviceData::IntelGfxData {
838 opregion_index: u32::MAX,
839 })
840 } else {
841 None
842 };
843
844 Ok(VfioPciDevice {
845 device: dev,
846 config,
847 hotplug,
848 hotplug_bus_number,
849 preferred_address,
850 pci_address: None,
851 interrupt_evt: None,
852 acpi_notification_evt: None,
853 mmio_regions: Vec::new(),
854 io_regions: Vec::new(),
855 pm_cap,
856 msi_cap,
857 msix_cap,
858 irq_type: None,
859 vm_memory_client,
860 device_data,
861 pm_evt: None,
862 is_in_low_power: Arc::new(Mutex::new(false)),
863 worker_thread: None,
864 vm_socket_vm: Some(vfio_device_socket_vm),
865 sysfs_path: sysfs_path.to_path_buf(),
866 ext_caps,
867 vcfg_shm_mmap: None,
868 mapped_mmio_bars: BTreeMap::new(),
869 activated: false,
870 acpi_notifier_val: Arc::new(Mutex::new(Vec::new())),
871 gpe: None,
872 base_class_code,
873 })
874 }
875
876 pub fn pci_address(&self) -> Option<PciAddress> {
878 self.pci_address
879 }
880
881 pub fn is_gfx(&self) -> bool {
882 self.base_class_code == PciClassCode::DisplayController
883 }
884
885 fn is_intel_gfx(&self) -> bool {
886 matches!(self.device_data, Some(DeviceData::IntelGfxData { .. }))
887 }
888
889 fn enable_acpi_notification(&mut self) -> Result<(), PciDeviceError> {
890 if let Some(ref acpi_notification_evt) = self.acpi_notification_evt {
891 return self
892 .device
893 .acpi_notification_evt_enable(acpi_notification_evt, VFIO_PCI_ACPI_NTFY_IRQ_INDEX)
894 .map_err(|_| PciDeviceError::AcpiNotifySetupFailed);
895 }
896 Err(PciDeviceError::AcpiNotifySetupFailed)
897 }
898
899 #[allow(dead_code)]
900 fn disable_acpi_notification(&mut self) -> Result<(), PciDeviceError> {
901 if let Some(ref _acpi_notification_evt) = self.acpi_notification_evt {
902 return self
903 .device
904 .acpi_notification_disable(VFIO_PCI_ACPI_NTFY_IRQ_INDEX)
905 .map_err(|_| PciDeviceError::AcpiNotifyDeactivationFailed);
906 }
907 Err(PciDeviceError::AcpiNotifyDeactivationFailed)
908 }
909
910 #[allow(dead_code)]
911 fn test_acpi_notification(&mut self, val: u32) -> Result<(), PciDeviceError> {
912 if let Some(ref _acpi_notification_evt) = self.acpi_notification_evt {
913 return self
914 .device
915 .acpi_notification_test(VFIO_PCI_ACPI_NTFY_IRQ_INDEX, val)
916 .map_err(|_| PciDeviceError::AcpiNotifyTestFailed);
917 }
918 Err(PciDeviceError::AcpiNotifyTestFailed)
919 }
920
921 fn enable_intx(&mut self) {
922 if let Some(ref interrupt_evt) = self.interrupt_evt {
923 if let Err(e) = self.device.irq_enable(
924 &[Some(interrupt_evt.get_trigger())],
925 VFIO_PCI_INTX_IRQ_INDEX,
926 0,
927 ) {
928 error!("{} Intx enable failed: {}", self.debug_label(), e);
929 return;
930 }
931 if let Err(e) = self.device.irq_mask(VFIO_PCI_INTX_IRQ_INDEX) {
932 error!("{} Intx mask failed: {}", self.debug_label(), e);
933 self.disable_intx();
934 return;
935 }
936 if let Err(e) = self
937 .device
938 .resample_virq_enable(interrupt_evt.get_resample(), VFIO_PCI_INTX_IRQ_INDEX)
939 {
940 error!("{} resample enable failed: {}", self.debug_label(), e);
941 self.disable_intx();
942 return;
943 }
944 if let Err(e) = self.device.irq_unmask(VFIO_PCI_INTX_IRQ_INDEX) {
945 error!("{} Intx unmask failed: {}", self.debug_label(), e);
946 self.disable_intx();
947 return;
948 }
949 self.irq_type = Some(VfioIrqType::Intx);
950 }
951 }
952
953 fn disable_intx(&mut self) {
954 if let Err(e) = self.device.irq_disable(VFIO_PCI_INTX_IRQ_INDEX) {
955 error!("{} Intx disable failed: {}", self.debug_label(), e);
956 }
957 self.irq_type = None;
958 }
959
960 fn disable_irqs(&mut self) {
961 match self.irq_type {
962 Some(VfioIrqType::Msi) => self.disable_msi(),
963 Some(VfioIrqType::Msix) => self.disable_msix(),
964 _ => (),
965 }
966
967 if let Some(VfioIrqType::Intx) = self.irq_type {
970 self.disable_intx();
971 }
972 }
973
974 fn enable_msi(&mut self) {
975 self.disable_irqs();
976
977 let irqfd = match &self.msi_cap {
978 Some(cap) => {
979 if let Some(fd) = cap.get_msi_irqfd() {
980 fd
981 } else {
982 self.enable_intx();
983 return;
984 }
985 }
986 None => {
987 self.enable_intx();
988 return;
989 }
990 };
991
992 if let Err(e) = self
993 .device
994 .irq_enable(&[Some(irqfd)], VFIO_PCI_MSI_IRQ_INDEX, 0)
995 {
996 error!("{} failed to enable msi: {}", self.debug_label(), e);
997 self.enable_intx();
998 return;
999 }
1000
1001 self.irq_type = Some(VfioIrqType::Msi);
1002 }
1003
1004 fn disable_msi(&mut self) {
1005 if let Err(e) = self.device.irq_disable(VFIO_PCI_MSI_IRQ_INDEX) {
1006 error!("{} failed to disable msi: {}", self.debug_label(), e);
1007 return;
1008 }
1009 self.irq_type = None;
1010
1011 self.enable_intx();
1012 }
1013
1014 fn enable_msix(&mut self) {
1015 if self.msix_cap.is_none() {
1016 return;
1017 }
1018
1019 self.disable_irqs();
1020 let cap = self.msix_cap.as_ref().unwrap().lock();
1021 let vector_in_use = cap.get_msix_irqfds().iter().any(|&irq| irq.is_some());
1022
1023 let mut failed = false;
1024 if !vector_in_use {
1025 let fd = Event::new().expect("failed to create event");
1030 let table_size = cap.table_size();
1031 let mut irqfds = vec![None; table_size];
1032 irqfds[0] = Some(&fd);
1033 for fd in irqfds.iter_mut().skip(1) {
1034 *fd = None;
1035 }
1036 if let Err(e) = self.device.irq_enable(&irqfds, VFIO_PCI_MSIX_IRQ_INDEX, 0) {
1037 error!("{} failed to enable msix: {}", self.debug_label(), e);
1038 failed = true;
1039 }
1040 irqfds[0] = None;
1041 if let Err(e) = self.device.irq_enable(&irqfds, VFIO_PCI_MSIX_IRQ_INDEX, 0) {
1042 error!("{} failed to enable msix: {}", self.debug_label(), e);
1043 failed = true;
1044 }
1045 } else {
1046 let result = self
1047 .device
1048 .irq_enable(&cap.get_msix_irqfds(), VFIO_PCI_MSIX_IRQ_INDEX, 0);
1049 if let Err(e) = result {
1050 error!("{} failed to enable msix: {}", self.debug_label(), e);
1051 failed = true;
1052 }
1053 }
1054
1055 std::mem::drop(cap);
1056 if failed {
1057 self.enable_intx();
1058 return;
1059 }
1060 self.irq_type = Some(VfioIrqType::Msix);
1061 }
1062
1063 fn disable_msix(&mut self) {
1064 if self.msix_cap.is_none() {
1065 return;
1066 }
1067 if let Err(e) = self.device.irq_disable(VFIO_PCI_MSIX_IRQ_INDEX) {
1068 error!("{} failed to disable msix: {}", self.debug_label(), e);
1069 return;
1070 }
1071 self.irq_type = None;
1072 self.enable_intx();
1073 }
1074
1075 fn msix_vectors_update(&self) -> Result<(), VfioError> {
1076 if let Some(cap) = &self.msix_cap {
1077 self.device
1078 .irq_enable(&cap.lock().get_msix_irqfds(), VFIO_PCI_MSIX_IRQ_INDEX, 0)?;
1079 }
1080 Ok(())
1081 }
1082
1083 fn msix_vector_update(&self, index: usize, irqfd: Option<&Event>) {
1084 if let Err(e) = self
1085 .device
1086 .irq_enable(&[irqfd], VFIO_PCI_MSIX_IRQ_INDEX, index as u32)
1087 {
1088 error!(
1089 "{} failed to update msix vector {}: {}",
1090 self.debug_label(),
1091 index,
1092 e
1093 );
1094 }
1095 }
1096
1097 fn adjust_bar_mmap(
1098 &self,
1099 bar_mmaps: Vec<vfio_region_sparse_mmap_area>,
1100 remove_mmaps: &[AddressRange],
1101 ) -> Vec<vfio_region_sparse_mmap_area> {
1102 let mut mmaps: Vec<vfio_region_sparse_mmap_area> = Vec::with_capacity(bar_mmaps.len());
1103 let pgmask = (pagesize() as u64) - 1;
1104
1105 for mmap in bar_mmaps.iter() {
1106 let mmap_range = if let Some(mmap_range) =
1107 AddressRange::from_start_and_size(mmap.offset, mmap.size)
1108 {
1109 mmap_range
1110 } else {
1111 continue;
1112 };
1113 let mut to_mmap = match VfioResourceAllocator::new(mmap_range) {
1114 Ok(a) => a,
1115 Err(e) => {
1116 error!("{} adjust_bar_mmap failed: {}", self.debug_label(), e);
1117 mmaps.clear();
1118 return mmaps;
1119 }
1120 };
1121
1122 for &(mut remove_range) in remove_mmaps.iter() {
1123 remove_range = remove_range.intersect(mmap_range);
1124 if !remove_range.is_empty() {
1125 let begin = remove_range.start & !pgmask;
1127 let end = ((remove_range.end + 1 + pgmask) & !pgmask) - 1;
1128 let remove_range = AddressRange::from_start_and_end(begin, end);
1129 if let Err(e) = to_mmap.allocate_at_can_overlap(remove_range) {
1130 error!("{} adjust_bar_mmap failed: {}", self.debug_label(), e);
1131 }
1132 }
1133 }
1134
1135 for mmap in to_mmap.regions {
1136 mmaps.push(vfio_region_sparse_mmap_area {
1137 offset: mmap.start,
1138 size: mmap.end - mmap.start + 1,
1139 });
1140 }
1141 }
1142
1143 mmaps
1144 }
1145
1146 fn remove_bar_mmap_msix(
1147 &self,
1148 bar_index: PciBarIndex,
1149 bar_mmaps: Vec<vfio_region_sparse_mmap_area>,
1150 ) -> Vec<vfio_region_sparse_mmap_area> {
1151 let msix_cap = &self.msix_cap.as_ref().unwrap().lock();
1152 let mut msix_regions = Vec::new();
1153
1154 if let Some(t) = msix_cap.get_msix_table(bar_index) {
1155 msix_regions.push(t);
1156 }
1157 if let Some(p) = msix_cap.get_msix_pba(bar_index) {
1158 msix_regions.push(p);
1159 }
1160
1161 if msix_regions.is_empty() {
1162 return bar_mmaps;
1163 }
1164
1165 self.adjust_bar_mmap(bar_mmaps, &msix_regions)
1166 }
1167
1168 fn add_bar_mmap(&self, index: PciBarIndex, bar_addr: u64) -> Vec<VmMemoryRegionId> {
1169 let mut mmaps_ids: Vec<VmMemoryRegionId> = Vec::new();
1170 if self.device.get_region_flags(index) & VFIO_REGION_INFO_FLAG_MMAP != 0 {
1171 let mut mmaps = self.device.get_region_mmap(index);
1174
1175 if self.msix_cap.is_some() && !self.device.get_region_msix_mmappable(index) {
1176 mmaps = self.remove_bar_mmap_msix(index, mmaps);
1177 }
1178 if mmaps.is_empty() {
1179 return mmaps_ids;
1180 }
1181
1182 for mmap in mmaps.iter() {
1183 let mmap_offset = mmap.offset;
1184 let mmap_size = mmap.size;
1185 let guest_map_start = bar_addr + mmap_offset;
1186 let region_offset = self.device.get_region_offset(index);
1187 let offset = region_offset + mmap_offset;
1188 let descriptor = match self.device.device_file().try_clone() {
1189 Ok(device_file) => device_file.into(),
1190 Err(_) => break,
1191 };
1192 match self.vm_memory_client.register_memory(
1193 VmMemorySource::Descriptor {
1194 descriptor,
1195 offset,
1196 size: mmap_size,
1197 },
1198 VmMemoryDestination::GuestPhysicalAddress(guest_map_start),
1199 Protection::read_write(),
1200 MemCacheType::CacheCoherent,
1201 ) {
1202 Ok(id) => {
1203 mmaps_ids.push(id);
1204 }
1205 Err(e) => {
1206 error!("register_memory failed: {}", e);
1207 break;
1208 }
1209 }
1210 }
1211 }
1212
1213 mmaps_ids
1214 }
1215
1216 fn remove_bar_mmap(&self, mmap_ids: &[VmMemoryRegionId]) {
1217 for mmap_id in mmap_ids {
1218 if let Err(e) = self.vm_memory_client.unregister_memory(*mmap_id) {
1219 error!("unregister_memory failed: {}", e);
1220 }
1221 }
1222 }
1223
1224 fn disable_bars_mmap(&mut self) {
1225 for (_, (_, mmap_ids)) in self.mapped_mmio_bars.iter() {
1226 self.remove_bar_mmap(mmap_ids);
1227 }
1228 self.mapped_mmio_bars.clear();
1229 }
1230
1231 fn commit_bars_mmap(&mut self) {
1232 let mut needs_map = Vec::new();
1234 for mmio_info in self.mmio_regions.iter() {
1235 let bar_idx = mmio_info.bar_index();
1236 let addr = mmio_info.address();
1237
1238 if let Some((cur_addr, ids)) = self.mapped_mmio_bars.remove(&bar_idx) {
1239 if cur_addr == addr {
1240 self.mapped_mmio_bars.insert(bar_idx, (cur_addr, ids));
1241 continue;
1242 } else {
1243 self.remove_bar_mmap(&ids);
1244 }
1245 }
1246
1247 if addr != 0 {
1248 needs_map.push((bar_idx, addr));
1249 }
1250 }
1251
1252 for (bar_idx, addr) in needs_map.iter() {
1253 let ids = self.add_bar_mmap(*bar_idx, *addr);
1254 self.mapped_mmio_bars.insert(*bar_idx, (*addr, ids));
1255 }
1256 }
1257
1258 fn close(&mut self) {
1259 if let Some(msi) = self.msi_cap.as_mut() {
1260 msi.destroy();
1261 }
1262 if let Some(msix) = &self.msix_cap {
1263 msix.lock().destroy();
1264 }
1265 self.disable_bars_mmap();
1266 self.device.close();
1267 }
1268
1269 fn start_work_thread(&mut self) {
1270 let vm_socket = match self.vm_socket_vm.take() {
1271 Some(socket) => socket,
1272 None => return,
1273 };
1274
1275 let req_evt = match Event::new() {
1276 Ok(evt) => {
1277 if let Err(e) = self
1278 .device
1279 .irq_enable(&[Some(&evt)], VFIO_PCI_REQ_IRQ_INDEX, 0)
1280 {
1281 error!("{} enable req_irq failed: {}", self.debug_label(), e);
1282 return;
1283 }
1284 evt
1285 }
1286 Err(_) => return,
1287 };
1288
1289 let (self_pm_evt, pm_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
1290 Ok(v) => v,
1291 Err(e) => {
1292 error!(
1293 "{} failed creating PM Event pair: {}",
1294 self.debug_label(),
1295 e
1296 );
1297 return;
1298 }
1299 };
1300 self.pm_evt = Some(self_pm_evt);
1301
1302 let (self_acpi_notify_evt, acpi_notify_evt) =
1303 match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
1304 Ok(v) => v,
1305 Err(e) => {
1306 error!(
1307 "{} failed creating ACPI Event pair: {}",
1308 self.debug_label(),
1309 e
1310 );
1311 return;
1312 }
1313 };
1314 self.acpi_notification_evt = Some(self_acpi_notify_evt);
1315
1316 if let Err(e) = self.enable_acpi_notification() {
1317 error!("{}: {}", self.debug_label(), e);
1318 }
1319
1320 let mut msix_evt = Vec::new();
1321 if let Some(msix_cap) = &self.msix_cap {
1322 msix_evt = msix_cap.lock().clone_msix_evt();
1323 }
1324
1325 let name = self.device.device_name().to_string();
1326 let address = self.pci_address.expect("Unassigned PCI Address.");
1327 let sysfs_path = self.sysfs_path.clone();
1328 let pm_cap = self.pm_cap.clone();
1329 let msix_cap = self.msix_cap.clone();
1330 let is_in_low_power = self.is_in_low_power.clone();
1331 let gpe_nr = self.gpe;
1332 let notification_val = self.acpi_notifier_val.clone();
1333 self.worker_thread = Some(WorkerThread::start("vfio_pci", move |kill_evt| {
1334 let mut worker = VfioPciWorker {
1335 address,
1336 sysfs_path,
1337 vm_socket,
1338 name,
1339 pm_cap,
1340 msix_cap,
1341 };
1342 worker.run(
1343 req_evt,
1344 pm_evt,
1345 acpi_notify_evt,
1346 kill_evt,
1347 msix_evt,
1348 is_in_low_power,
1349 gpe_nr,
1350 notification_val,
1351 );
1352 worker
1353 }));
1354 self.activated = true;
1355 }
1356
1357 fn collect_bars(&mut self) -> Vec<PciBarConfiguration> {
1358 let mut i = VFIO_PCI_BAR0_REGION_INDEX;
1359 let mut mem_bars: Vec<PciBarConfiguration> = Vec::new();
1360
1361 while i <= VFIO_PCI_ROM_REGION_INDEX {
1362 let mut low: u32 = 0xffffffff;
1363 let offset: u32 = if i == VFIO_PCI_ROM_REGION_INDEX {
1364 0x30
1365 } else {
1366 0x10 + i * 4
1367 };
1368 self.config.write_config(low, offset);
1369 low = self.config.read_config(offset);
1370
1371 let low_flag = low & 0xf;
1372 let is_64bit = low_flag & 0x4 == 0x4;
1373 if (low_flag & 0x1 == 0 || i == VFIO_PCI_ROM_REGION_INDEX) && low != 0 {
1374 let mut upper: u32 = 0xffffffff;
1375 if is_64bit {
1376 self.config.write_config(upper, offset + 4);
1377 upper = self.config.read_config(offset + 4);
1378 }
1379
1380 low &= 0xffff_fff0;
1381 let mut size: u64 = u64::from(upper);
1382 size <<= 32;
1383 size |= u64::from(low);
1384 size = !size + 1;
1385 let region_type = if is_64bit {
1386 PciBarRegionType::Memory64BitRegion
1387 } else {
1388 PciBarRegionType::Memory32BitRegion
1389 };
1390 let prefetch = if low_flag & 0x8 == 0x8 {
1391 PciBarPrefetchable::Prefetchable
1392 } else {
1393 PciBarPrefetchable::NotPrefetchable
1394 };
1395 mem_bars.push(PciBarConfiguration::new(
1396 i as usize,
1397 size,
1398 region_type,
1399 prefetch,
1400 ));
1401 } else if low_flag & 0x1 == 0x1 {
1402 let size = !(low & 0xffff_fffc) + 1;
1403 self.io_regions.push(PciBarConfiguration::new(
1404 i as usize,
1405 size.into(),
1406 PciBarRegionType::IoRegion,
1407 PciBarPrefetchable::NotPrefetchable,
1408 ));
1409 }
1410
1411 if is_64bit {
1412 i += 2;
1413 } else {
1414 i += 1;
1415 }
1416 }
1417 mem_bars
1418 }
1419
1420 fn configure_barmem(&mut self, bar_info: &PciBarConfiguration, bar_addr: u64) {
1421 let offset: u32 = bar_info.reg_index() as u32 * 4;
1422 let mmio_region = *bar_info;
1423 self.mmio_regions.push(mmio_region.set_address(bar_addr));
1424
1425 let val: u32 = self.config.read_config(offset);
1426 let low = ((bar_addr & !0xf) as u32) | (val & 0xf);
1427 self.config.write_config(low, offset);
1428 if bar_info.is_64bit_memory() {
1429 let upper = (bar_addr >> 32) as u32;
1430 self.config.write_config(upper, offset + 4);
1431 }
1432 }
1433
1434 fn allocate_root_barmem(
1435 &mut self,
1436 mem_bars: &[PciBarConfiguration],
1437 resources: &mut SystemAllocator,
1438 ) -> Result<Vec<BarRange>, PciDeviceError> {
1439 let address = self.pci_address.unwrap();
1440 let mut ranges: Vec<BarRange> = Vec::new();
1441 for mem_bar in mem_bars {
1442 let bar_size = mem_bar.size();
1443 let mut bar_addr: u64 = 0;
1444 if !self.hotplug {
1447 bar_addr = resources
1448 .allocate_mmio(
1449 bar_size,
1450 Alloc::PciBar {
1451 bus: address.bus,
1452 dev: address.dev,
1453 func: address.func,
1454 bar: mem_bar.bar_index() as u8,
1455 },
1456 "vfio_bar".to_string(),
1457 AllocOptions::new()
1458 .prefetchable(mem_bar.is_prefetchable())
1459 .max_address(if mem_bar.is_64bit_memory() {
1460 u64::MAX
1461 } else {
1462 u32::MAX.into()
1463 })
1464 .align(bar_size),
1465 )
1466 .map_err(|e| PciDeviceError::IoAllocationFailed(bar_size, e))?;
1467 ranges.push(BarRange {
1468 addr: bar_addr,
1469 size: bar_size,
1470 prefetchable: mem_bar.is_prefetchable(),
1471 });
1472 }
1473 self.configure_barmem(mem_bar, bar_addr);
1474 }
1475 Ok(ranges)
1476 }
1477
1478 fn allocate_nonroot_barmem(
1479 &mut self,
1480 mem_bars: &mut [PciBarConfiguration],
1481 resources: &mut SystemAllocator,
1482 ) -> Result<Vec<BarRange>, PciDeviceError> {
1483 const NON_PREFETCHABLE: usize = 0;
1484 const PREFETCHABLE: usize = 1;
1485 const ARRAY_SIZE: usize = 2;
1486 let mut membars: [Vec<PciBarConfiguration>; ARRAY_SIZE] = [Vec::new(), Vec::new()];
1487 let mut allocator: [VfioResourceAllocator; ARRAY_SIZE] = [
1488 match VfioResourceAllocator::new(AddressRange::from_start_and_end(0, u32::MAX as u64)) {
1489 Ok(a) => a,
1490 Err(e) => {
1491 error!(
1492 "{} init nonroot VfioResourceAllocator failed: {}",
1493 self.debug_label(),
1494 e
1495 );
1496 return Err(e);
1497 }
1498 },
1499 match VfioResourceAllocator::new(AddressRange::from_start_and_end(0, u64::MAX)) {
1500 Ok(a) => a,
1501 Err(e) => {
1502 error!(
1503 "{} init nonroot VfioResourceAllocator failed: {}",
1504 self.debug_label(),
1505 e
1506 );
1507 return Err(e);
1508 }
1509 },
1510 ];
1511 let mut memtype: [MmioType; ARRAY_SIZE] = [MmioType::Low, MmioType::High];
1512 let mut window_sz: [u64; ARRAY_SIZE] = [0; 2];
1514 let mut alignment: [u64; ARRAY_SIZE] = [0x100000; 2];
1515
1516 mem_bars.sort_by_key(|a| Reverse(a.size()));
1518 for mem_bar in mem_bars {
1519 let prefetchable = mem_bar.is_prefetchable();
1520 let is_64bit = mem_bar.is_64bit_memory();
1521
1522 if prefetchable && !is_64bit {
1525 memtype[PREFETCHABLE] = MmioType::Low;
1526 }
1527 let i = if prefetchable {
1528 PREFETCHABLE
1529 } else {
1530 NON_PREFETCHABLE
1531 };
1532 let bar_size = mem_bar.size();
1533 let start = match allocator[i].allocate_with_align(bar_size, bar_size) {
1534 Ok(s) => s,
1535 Err(e) => {
1536 error!(
1537 "{} nonroot allocate_wit_align failed: {}",
1538 self.debug_label(),
1539 e
1540 );
1541 return Err(e);
1542 }
1543 };
1544 window_sz[i] = max(window_sz[i], start + bar_size);
1545 alignment[i] = max(alignment[i], bar_size);
1546 let mem_info = (*mem_bar).set_address(start);
1547 membars[i].push(mem_info);
1548 }
1549
1550 let address = self.pci_address.unwrap();
1551 let mut ranges: Vec<BarRange> = Vec::new();
1552 for (index, bars) in membars.iter().enumerate() {
1553 if bars.is_empty() {
1554 continue;
1555 }
1556
1557 let i = if index == 1 {
1558 PREFETCHABLE
1559 } else {
1560 NON_PREFETCHABLE
1561 };
1562 let mut window_addr: u64 = 0;
1563 if !self.hotplug {
1566 window_sz[i] = (window_sz[i] + 0xfffff) & !0xfffff;
1567 let alloc = if i == NON_PREFETCHABLE {
1568 Alloc::PciBridgeWindow {
1569 bus: address.bus,
1570 dev: address.dev,
1571 func: address.func,
1572 }
1573 } else {
1574 Alloc::PciBridgePrefetchWindow {
1575 bus: address.bus,
1576 dev: address.dev,
1577 func: address.func,
1578 }
1579 };
1580 window_addr = resources
1581 .mmio_allocator(memtype[i])
1582 .allocate_with_align(
1583 window_sz[i],
1584 alloc,
1585 "vfio_bar_window".to_string(),
1586 alignment[i],
1587 )
1588 .map_err(|e| PciDeviceError::IoAllocationFailed(window_sz[i], e))?;
1589 for mem_info in bars {
1590 let bar_addr = window_addr + mem_info.address();
1591 ranges.push(BarRange {
1592 addr: bar_addr,
1593 size: mem_info.size(),
1594 prefetchable: mem_info.is_prefetchable(),
1595 });
1596 }
1597 }
1598
1599 for mem_info in bars {
1600 let bar_addr = window_addr + mem_info.address();
1601 self.configure_barmem(mem_info, bar_addr);
1602 }
1603 }
1604 Ok(ranges)
1605 }
1606
1607 pub fn get_max_iova(&self) -> u64 {
1609 self.device.get_max_addr()
1610 }
1611
1612 fn get_ext_cap_by_reg(&self, reg: u32) -> Option<ExtCap> {
1613 self.ext_caps
1614 .iter()
1615 .find(|ext_cap| reg >= ext_cap.offset && reg < ext_cap.offset + ext_cap.size)
1616 .cloned()
1617 }
1618
1619 fn is_skipped_reg(&self, reg: u32) -> bool {
1620 if reg < PCI_CONFIG_SPACE_SIZE {
1622 return false;
1623 }
1624
1625 self.get_ext_cap_by_reg(reg)
1626 .is_some_and(|cap| cap.is_skipped)
1627 }
1628}
1629
1630impl PciDevice for VfioPciDevice {
1631 fn debug_label(&self) -> String {
1632 format!("vfio {} device", self.device.device_name())
1633 }
1634
1635 fn preferred_address(&self) -> Option<PciAddress> {
1636 Some(self.preferred_address)
1637 }
1638
1639 fn allocate_address(
1640 &mut self,
1641 resources: &mut SystemAllocator,
1642 ) -> Result<PciAddress, PciDeviceError> {
1643 if self.pci_address.is_none() {
1644 let mut address = self.preferred_address;
1645 while address.func < 8 {
1646 if resources.reserve_pci(address, self.debug_label()) {
1647 self.pci_address = Some(address);
1648 break;
1649 } else if self.hotplug_bus_number.is_none() {
1650 break;
1651 } else {
1652 address.func += 1;
1653 }
1654 }
1655 if let Some(msi_cap) = &mut self.msi_cap {
1656 msi_cap.config.set_pci_address(self.pci_address.unwrap());
1657 }
1658 if let Some(msix_cap) = &mut self.msix_cap {
1659 msix_cap
1660 .lock()
1661 .config
1662 .set_pci_address(self.pci_address.unwrap());
1663 }
1664 }
1665 self.pci_address.ok_or(PciDeviceError::PciAllocationFailed)
1666 }
1667
1668 fn keep_rds(&self) -> Vec<RawDescriptor> {
1669 let mut rds = self.device.keep_rds();
1670 if let Some(ref interrupt_evt) = self.interrupt_evt {
1671 rds.extend(interrupt_evt.as_raw_descriptors());
1672 }
1673 rds.push(self.vm_memory_client.as_raw_descriptor());
1674 if let Some(vm_socket_vm) = &self.vm_socket_vm {
1675 rds.push(vm_socket_vm.as_raw_descriptor());
1676 }
1677 if let Some(msi_cap) = &self.msi_cap {
1678 rds.push(msi_cap.config.get_msi_socket());
1679 }
1680 if let Some(msix_cap) = &self.msix_cap {
1681 rds.extend(msix_cap.lock().as_raw_descriptors());
1682 }
1683 rds
1684 }
1685
1686 fn preferred_irq(&self) -> PreferredIrq {
1687 PreferredIrq::Any
1692 }
1693
1694 fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
1695 self.interrupt_evt = Some(irq_evt);
1697
1698 self.enable_intx();
1700
1701 self.config
1702 .write_config(pin.to_mask() as u8, PCI_INTERRUPT_PIN);
1703 self.config.write_config(irq_num as u8, PCI_INTERRUPT_NUM);
1704 }
1705
1706 fn allocate_io_bars(
1707 &mut self,
1708 resources: &mut SystemAllocator,
1709 ) -> Result<Vec<BarRange>, PciDeviceError> {
1710 let address = self
1711 .pci_address
1712 .expect("allocate_address must be called prior to allocate_device_bars");
1713
1714 let mut mem_bars = self.collect_bars();
1715
1716 let ranges = if address.bus == 0 {
1717 self.allocate_root_barmem(&mem_bars, resources)?
1718 } else {
1719 self.allocate_nonroot_barmem(&mut mem_bars, resources)?
1720 };
1721
1722 if self.is_intel_gfx() {
1725 let mut cmd = self.config.read_config::<u8>(PCI_COMMAND);
1726 cmd |= PCI_COMMAND_MEMORY;
1727 self.config.write_config(cmd, PCI_COMMAND);
1728 }
1729 Ok(ranges)
1730 }
1731
1732 fn allocate_device_bars(
1733 &mut self,
1734 resources: &mut SystemAllocator,
1735 ) -> Result<Vec<BarRange>, PciDeviceError> {
1736 let mut ranges: Vec<BarRange> = Vec::new();
1737
1738 if !self.is_intel_gfx() {
1739 return Ok(ranges);
1740 }
1741
1742 if let Some((index, size)) = self.device.get_cap_type_info(
1745 VFIO_REGION_TYPE_PCI_VENDOR_TYPE | (PCI_VENDOR_ID_INTEL as u32),
1746 VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION,
1747 ) {
1748 let address = self
1749 .pci_address
1750 .expect("allocate_address must be called prior to allocate_device_bars");
1751 let bar_addr = resources
1752 .allocate_mmio(
1753 size,
1754 Alloc::PciBar {
1755 bus: address.bus,
1756 dev: address.dev,
1757 func: address.func,
1758 bar: (index * 4) as u8,
1759 },
1760 "vfio_bar".to_string(),
1761 AllocOptions::new().max_address(u32::MAX.into()),
1762 )
1763 .map_err(|e| PciDeviceError::IoAllocationFailed(size, e))?;
1764 ranges.push(BarRange {
1765 addr: bar_addr,
1766 size,
1767 prefetchable: false,
1768 });
1769 self.device_data = Some(DeviceData::IntelGfxData {
1770 opregion_index: index,
1771 });
1772
1773 self.mmio_regions.push(
1774 PciBarConfiguration::new(
1775 index as usize,
1776 size,
1777 PciBarRegionType::Memory32BitRegion,
1778 PciBarPrefetchable::NotPrefetchable,
1779 )
1780 .set_address(bar_addr),
1781 );
1782 self.config.write_config(bar_addr as u32, 0xFC);
1783 }
1784
1785 Ok(ranges)
1786 }
1787
1788 fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
1789 for region in self.mmio_regions.iter().chain(self.io_regions.iter()) {
1790 if region.bar_index() == bar_num {
1791 let command: u8 = self.config.read_config(PCI_COMMAND);
1792 if (region.is_memory() && (command & PCI_COMMAND_MEMORY == 0)) || region.is_io() {
1793 return None;
1794 } else {
1795 return Some(*region);
1796 }
1797 }
1798 }
1799
1800 None
1801 }
1802
1803 fn register_device_capabilities(&mut self) -> Result<(), PciDeviceError> {
1804 Ok(())
1805 }
1806
1807 fn read_config_register(&self, reg_idx: usize) -> u32 {
1808 let reg: u32 = (reg_idx * 4) as u32;
1809 let mut config: u32 = self.config.read_config(reg);
1810
1811 if reg >= PCI_CONFIG_SPACE_SIZE {
1813 let ext_cap = self.get_ext_cap_by_reg(reg);
1814 if let Some(ext_cap) = ext_cap {
1815 if ext_cap.offset == reg {
1816 config = (config & !(0xffc << 20)) | (((ext_cap.next & 0xffc) as u32) << 20);
1817 }
1818
1819 if ext_cap.is_skipped {
1820 if reg == PCI_CONFIG_SPACE_SIZE {
1821 config = (config & (0xffc << 20)) | (PCI_EXT_CAP_ID_CAC as u32);
1822 } else {
1823 config = 0;
1824 }
1825 }
1826 }
1827 }
1828
1829 if (0x10..=0x24).contains(®) {
1831 let bar_idx = (reg as usize - 0x10) / 4;
1832 if let Some(bar) = self.get_bar_configuration(bar_idx) {
1833 if bar.is_io() {
1834 config = 0;
1835 }
1836 }
1837 } else if let Some(msix_cap) = &self.msix_cap {
1838 let msix_cap = msix_cap.lock();
1839 if msix_cap.is_msix_control_reg(reg, 4) {
1840 msix_cap.read_msix_control(&mut config);
1841 }
1842 } else if let Some(pm_cap) = &self.pm_cap {
1843 let pm_cap = pm_cap.lock();
1844 if pm_cap.is_pm_reg(reg) {
1845 config = pm_cap.read(reg);
1846 }
1847 }
1848
1849 if self.is_intel_gfx() && reg == 0x50 {
1851 config &= 0xffff00ff;
1852 }
1853
1854 config
1855 }
1856
1857 fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
1858 if self.worker_thread.is_none() && self.vm_socket_vm.is_some() {
1860 self.start_work_thread();
1861 };
1862
1863 let start = (reg_idx * 4) as u64 + offset;
1864
1865 if let Some(pm_cap) = self.pm_cap.as_mut() {
1866 let mut pm_cap = pm_cap.lock();
1867 if pm_cap.is_pm_reg(start as u32) {
1868 pm_cap.write(start, data);
1869 }
1870 }
1871
1872 let mut msi_change: Option<VfioMsiChange> = None;
1873 if let Some(msi_cap) = self.msi_cap.as_mut() {
1874 if msi_cap.is_msi_reg(start, data.len()) {
1875 msi_change = msi_cap.write_msi_reg(start, data);
1876 }
1877 }
1878
1879 match msi_change {
1880 Some(VfioMsiChange::Enable) => self.enable_msi(),
1881 Some(VfioMsiChange::Disable) => self.disable_msi(),
1882 _ => (),
1883 }
1884
1885 msi_change = None;
1886 if let Some(msix_cap) = &self.msix_cap {
1887 let mut msix_cap = msix_cap.lock();
1888 if msix_cap.is_msix_control_reg(start as u32, data.len() as u32) {
1889 msi_change = msix_cap.write_msix_control(data);
1890 }
1891 }
1892
1893 match msi_change {
1894 Some(VfioMsiChange::Enable) => self.enable_msix(),
1895 Some(VfioMsiChange::Disable) => self.disable_msix(),
1896 Some(VfioMsiChange::FunctionChanged) => {
1897 if let Err(e) = self.msix_vectors_update() {
1898 error!("update msix vectors failed: {}", e);
1899 }
1900 }
1901 _ => (),
1902 }
1903
1904 if !self.is_skipped_reg(start as u32) {
1905 self.device
1906 .region_write(VFIO_PCI_CONFIG_REGION_INDEX as usize, data, start);
1907 }
1908
1909 if start == PCI_COMMAND as u64
1911 && data.len() == 2
1912 && data[0] & PCI_COMMAND_MEMORY == PCI_COMMAND_MEMORY
1913 {
1914 self.commit_bars_mmap();
1915 } else if (0x10..=0x24).contains(&start) && data.len() == 4 {
1916 let bar_idx = (start as u32 - 0x10) / 4;
1917 let value: [u8; 4] = [data[0], data[1], data[2], data[3]];
1918 let val = u32::from_le_bytes(value);
1919 let mut modify = false;
1920 for region in self.mmio_regions.iter_mut() {
1921 if region.bar_index() == bar_idx as usize {
1922 let old_addr = region.address();
1923 let new_addr = val & 0xFFFFFFF0;
1924 if !region.is_64bit_memory() && (old_addr as u32) != new_addr {
1925 *region = region.set_address(u64::from(new_addr));
1927 modify = true;
1928 } else if region.is_64bit_memory() && (old_addr as u32) != new_addr {
1929 *region =
1931 region.set_address(u64::from(new_addr) | ((old_addr >> 32) << 32));
1932 modify = true;
1933 }
1934 break;
1935 } else if region.is_64bit_memory()
1936 && ((bar_idx % 2) == 1)
1937 && (region.bar_index() + 1 == bar_idx as usize)
1938 {
1939 let old_addr = region.address();
1941 if val != (old_addr >> 32) as u32 {
1942 let mut new_addr = (u64::from(val)) << 32;
1943 new_addr |= old_addr & 0xFFFFFFFF;
1944 *region = region.set_address(new_addr);
1945 modify = true;
1946 }
1947 break;
1948 }
1949 }
1950 if modify {
1951 let cmd = self.config.read_config::<u8>(PCI_COMMAND);
1954 if cmd & PCI_COMMAND_MEMORY == PCI_COMMAND_MEMORY {
1955 self.commit_bars_mmap();
1956 }
1957 }
1958 }
1959 }
1960
1961 fn read_virtual_config_register(&self, reg_idx: usize) -> u32 {
1962 if reg_idx == PCI_VCFG_NOTY {
1963 let mut q = self.acpi_notifier_val.lock();
1964 let mut val = 0;
1965 if !q.is_empty() {
1966 val = q.remove(0);
1967 }
1968 drop(q);
1969 return val;
1970 }
1971
1972 warn!(
1973 "{} read unsupported vcfg register {}",
1974 self.debug_label(),
1975 reg_idx
1976 );
1977 0xFFFF_FFFF
1978 }
1979
1980 fn write_virtual_config_register(&mut self, reg_idx: usize, value: u32) {
1981 match reg_idx {
1982 PCI_VCFG_PM => {
1983 match value {
1984 0 => {
1985 if let Some(pm_evt) =
1986 self.pm_evt.as_ref().map(|evt| evt.try_clone().unwrap())
1987 {
1988 *self.is_in_low_power.lock() = true;
1989 let _ = self.device.pm_low_power_enter_with_wakeup(pm_evt);
1990 } else {
1991 let _ = self.device.pm_low_power_enter();
1992 }
1993 }
1994 _ => {
1995 *self.is_in_low_power.lock() = false;
1996 let _ = self.device.pm_low_power_exit();
1997 }
1998 };
1999 }
2000 PCI_VCFG_DSM => {
2001 if let Some(shm) = &self.vcfg_shm_mmap {
2002 let mut args = [0u8; 4096];
2003 if let Err(e) = shm.read_slice(&mut args, 0) {
2004 error!("failed to read DSM Args: {}", e);
2005 return;
2006 }
2007 let res = match self.device.acpi_dsm(&args) {
2008 Ok(r) => r,
2009 Err(e) => {
2010 error!("failed to call DSM: {}", e);
2011 return;
2012 }
2013 };
2014 if let Err(e) = shm.write_slice(&res, 0) {
2015 error!("failed to write DSM result: {}", e);
2016 return;
2017 }
2018 if let Err(e) = shm.msync() {
2019 error!("failed to msync: {}", e)
2020 }
2021 }
2022 }
2023 _ => warn!(
2024 "{} write unsupported vcfg register {}",
2025 self.debug_label(),
2026 reg_idx
2027 ),
2028 };
2029 }
2030
2031 fn read_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &mut [u8]) {
2032 if let Some(msix_cap) = &self.msix_cap {
2033 let msix_cap = msix_cap.lock();
2034 if msix_cap.is_msix_table(bar_index, offset) {
2035 msix_cap.read_table(offset, data);
2036 return;
2037 } else if msix_cap.is_msix_pba(bar_index, offset) {
2038 msix_cap.read_pba(offset, data);
2039 return;
2040 }
2041 }
2042 self.device.region_read(bar_index, data, offset);
2043 }
2044
2045 fn write_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &[u8]) {
2046 if let Some(device_data) = &self.device_data {
2048 match *device_data {
2049 DeviceData::IntelGfxData { opregion_index } => {
2050 if opregion_index == bar_index as u32 {
2051 return;
2052 }
2053 }
2054 }
2055 }
2056
2057 if let Some(msix_cap) = &self.msix_cap {
2058 let mut msix_cap = msix_cap.lock();
2059 if msix_cap.is_msix_table(bar_index, offset) {
2060 let behavior = msix_cap.write_table(offset, data);
2061 if let MsixStatus::EntryChanged(index) = behavior {
2062 let irqfd = msix_cap.get_msix_irqfd(index);
2063 self.msix_vector_update(index, irqfd);
2064 }
2065 return;
2066 } else if msix_cap.is_msix_pba(bar_index, offset) {
2067 msix_cap.write_pba(offset, data);
2068 return;
2069 }
2070 }
2071
2072 self.device.region_write(bar_index, data, offset);
2073 }
2074
2075 fn destroy_device(&mut self) {
2076 self.close();
2077 }
2078
2079 fn generate_acpi_methods(&mut self) -> (Vec<u8>, Option<(u32, MemoryMapping)>) {
2080 let mut amls = Vec::new();
2081 let mut shm = None;
2082 if let Some(pci_address) = self.pci_address {
2083 let vcfg_offset = pci_address.to_config_address(0, 13);
2084 if let Ok(vcfg_register) = DeviceVcfgRegister::new(vcfg_offset) {
2085 vcfg_register.to_aml_bytes(&mut amls);
2086 shm = vcfg_register
2087 .create_shm_mmap()
2088 .map(|shm| (vcfg_offset + SHM_OFFSET, shm));
2089 self.vcfg_shm_mmap = vcfg_register.create_shm_mmap();
2090 PowerResourceMethod {}.to_aml_bytes(&mut amls);
2095 let acpi_path = self.sysfs_path.join("firmware_node/path");
2101 if acpi_path.exists() {
2102 DsmMethod {}.to_aml_bytes(&mut amls);
2103 }
2104 }
2105 }
2106
2107 (amls, shm)
2108 }
2109
2110 fn set_gpe(&mut self, resources: &mut SystemAllocator) -> Option<u32> {
2111 if let Some(gpe_nr) = resources.allocate_gpe() {
2112 base::debug!("set_gpe: gpe-nr {} addr {:?}", gpe_nr, self.pci_address);
2113 self.gpe = Some(gpe_nr);
2114 }
2115 self.gpe
2116 }
2117}
2118
2119impl Suspendable for VfioPciDevice {
2120 fn sleep(&mut self) -> anyhow::Result<()> {
2121 if let Some(worker_thread) = self.worker_thread.take() {
2122 let res = worker_thread.stop();
2123 self.pci_address = Some(res.address);
2124 self.sysfs_path = res.sysfs_path;
2125 self.pm_cap = res.pm_cap;
2126 self.msix_cap = res.msix_cap;
2127 self.vm_socket_vm = Some(res.vm_socket);
2128 }
2129 Ok(())
2130 }
2131
2132 fn wake(&mut self) -> anyhow::Result<()> {
2133 if self.activated {
2134 self.start_work_thread();
2135 }
2136 Ok(())
2137 }
2138}
2139
2140#[cfg(test)]
2141mod tests {
2142 use resources::AddressRange;
2143
2144 use super::VfioResourceAllocator;
2145
2146 #[test]
2147 fn no_overlap() {
2148 let mut memory =
2150 VfioResourceAllocator::new(AddressRange::from_start_and_end(32, 95)).unwrap();
2151 memory
2152 .allocate_at_can_overlap(AddressRange::from_start_and_end(0, 15))
2153 .unwrap();
2154 memory
2155 .allocate_at_can_overlap(AddressRange::from_start_and_end(100, 115))
2156 .unwrap();
2157
2158 let mut iter = memory.regions.iter();
2159 assert_eq!(iter.next(), Some(&AddressRange::from_start_and_end(32, 95)));
2160 }
2161
2162 #[test]
2163 fn complete_overlap() {
2164 let mut memory =
2166 VfioResourceAllocator::new(AddressRange::from_start_and_end(32, 95)).unwrap();
2167 memory
2169 .allocate_at_can_overlap(AddressRange::from_start_and_end(48, 63))
2170 .unwrap();
2171 memory
2173 .allocate_at_can_overlap(AddressRange::from_start_and_end(32, 47))
2174 .unwrap();
2175
2176 let mut iter = memory.regions.iter();
2177 assert_eq!(iter.next(), Some(&AddressRange::from_start_and_end(64, 95)));
2178 }
2179
2180 #[test]
2181 fn partial_overlap_one() {
2182 let mut memory =
2184 VfioResourceAllocator::new(AddressRange::from_start_and_end(32, 95)).unwrap();
2185 memory
2187 .allocate_at_can_overlap(AddressRange::from_start_and_end(48, 63))
2188 .unwrap();
2189 memory
2191 .allocate_at_can_overlap(AddressRange::from_start_and_end(40, 55))
2192 .unwrap();
2193
2194 let mut iter = memory.regions.iter();
2195 assert_eq!(iter.next(), Some(&AddressRange::from_start_and_end(32, 39)));
2196 assert_eq!(iter.next(), Some(&AddressRange::from_start_and_end(64, 95)));
2197 }
2198
2199 #[test]
2200 fn partial_overlap_two() {
2201 let mut memory =
2203 VfioResourceAllocator::new(AddressRange::from_start_and_end(32, 95)).unwrap();
2204 memory
2206 .allocate_at_can_overlap(AddressRange::from_start_and_end(48, 63))
2207 .unwrap();
2208 memory
2210 .allocate_at_can_overlap(AddressRange::from_start_and_end(40, 71))
2211 .unwrap();
2212
2213 let mut iter = memory.regions.iter();
2214 assert_eq!(iter.next(), Some(&AddressRange::from_start_and_end(32, 39)));
2215 assert_eq!(iter.next(), Some(&AddressRange::from_start_and_end(72, 95)));
2216 }
2217
2218 #[test]
2219 fn partial_overlap_three() {
2220 let mut memory =
2222 VfioResourceAllocator::new(AddressRange::from_start_and_end(32, 95)).unwrap();
2223 memory
2225 .allocate_at_can_overlap(AddressRange::from_start_and_end(40, 47))
2226 .unwrap();
2227 memory
2229 .allocate_at_can_overlap(AddressRange::from_start_and_end(64, 71))
2230 .unwrap();
2231 memory
2233 .allocate_at_can_overlap(AddressRange::from_start_and_end(36, 75))
2234 .unwrap();
2235
2236 let mut iter = memory.regions.iter();
2237 assert_eq!(iter.next(), Some(&AddressRange::from_start_and_end(32, 35)));
2238 assert_eq!(iter.next(), Some(&AddressRange::from_start_and_end(76, 95)));
2239 }
2240}