devices/pci/
vfio_pci.rs

1// Copyright 2019 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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
102// Size of the standard PCI config space
103const PCI_CONFIG_SPACE_SIZE: u32 = 0x100;
104// Size of the standard PCIe config space: 4KB
105const PCIE_CONFIG_SPACE_SIZE: u32 = 0x1000;
106
107// Extended Capabilities
108const 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
209// MSI-X registers in MSI-X capability
210const PCI_MSIX_FLAGS: u32 = 0x02; // Message Control
211const PCI_MSIX_FLAGS_QSIZE: u16 = 0x07FF; // Table size
212const PCI_MSIX_TABLE: u32 = 0x04; // Table offset
213const PCI_MSIX_TABLE_BIR: u32 = 0x07; // BAR index
214const PCI_MSIX_TABLE_OFFSET: u32 = 0xFFFFFFF8; // Offset into specified BAR
215const PCI_MSIX_PBA: u32 = 0x08; // Pending bit Array offset
216const PCI_MSIX_PBA_BIR: u32 = 0x07; // BAR index
217const PCI_MSIX_PBA_OFFSET: u32 = 0xFFFFFFF8; // Offset into specified BAR
218
219struct 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    // only msix control register is writable and need special handle in pci r/w
278    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    // The region that is not allocated yet.
419    regions: BTreeSet<AddressRange>,
420}
421
422impl VfioResourceAllocator {
423    // Creates a new `VfioResourceAllocator` for managing VFIO resources.
424    // Can return `Err` if `base` + `size` overflows a u64.
425    //
426    // * `base` - The starting address of the range to manage.
427    // * `size` - The size of the address range in bytes.
428    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    // Allocates a range of addresses from the managed region with a minimal alignment.
458    // Overlapping with a previous allocation is _not_ allowed.
459    // Returns allocated address.
460    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        // finds first region matching alignment and size.
469        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    // Allocates a range of addresses from the managed region with a required location.
493    // Overlapping with a previous allocation is allowed.
494    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        // SR-IOV/ARI/Resizable_BAR capabilities are not well handled and should not be exposed
653        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/// PCI Express Extended Capabilities information
662#[derive(Copy, Clone)]
663struct ExtCap {
664    /// cap offset in Configuration Space
665    offset: u32,
666    /// cap size
667    size: u32,
668    /// next offset, set next non-skipped offset for non-skipped ext cap
669    next: u16,
670    /// whether to be exposed to guest
671    is_skipped: bool,
672}
673
674/// Implements the Vfio Pci device, then a pci device is added into vm
675pub 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    // PCI Express Extended Capabilities
698    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    /// Constructs a new Vfio Pci device for the give Vfio device
709    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                // Caller specify pcie bus number for hotplug device
724                bus: bus_num,
725                // devfn should be 0, otherwise pcie root port couldn't detect it
726                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                    // Calculate the size later
799                    size: 0,
800                    // init as the real value
801                    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            // Manage extended caps
808            //
809            // Extended capabilities are chained with each pointing to the next, so
810            // we can drop anything other than the head of the chain simply by
811            // modifying the previous next pointer. For the head of the chain, we
812            // can modify the capability ID to something that cannot match a valid
813            // capability. ID PCI_EXT_CAP_ID_CAC is for this since it is no longer
814            // supported.
815            //
816            // reverse order by offset
817            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            // order by offset
831            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    /// Gets the pci address of the device, if one has already been allocated.
877    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        // Above disable_msi() or disable_msix() will enable intx again.
968        // so disable_intx here again.
969        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            // If there are no msix vectors currently in use, we explicitly assign a new eventfd
1026            // to vector 0. Then we enable it and immediately disable it, so that vfio will
1027            // activate physical device. If there are available msix vectors, just enable them
1028            // instead.
1029            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                    // align offsets to page size
1126                    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            // the bar storing msix table and pba couldn't mmap.
1172            // these bars should be trapped, so that msix could be emulated.
1173            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        // Unmap all bars before remapping bars, to prevent issues with overlap
1233        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            // Don't allocate mmio for hotplug device, OS will allocate it from
1445            // its parent's bridge window.
1446            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        // the window must be 1M-aligned as per the PCI spec
1513        let mut window_sz: [u64; ARRAY_SIZE] = [0; 2];
1514        let mut alignment: [u64; ARRAY_SIZE] = [0x100000; 2];
1515
1516        // Descend by bar size, this could reduce allocated size for all the bars.
1517        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 one prefetchable bar is 32bit, all the prefetchable bars should be in Low MMIO,
1523            // as all the prefetchable bars should be in one region
1524            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            // Don't allocate mmio for hotplug device, OS will allocate it from
1564            // its parent's bridge window.
1565            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    /// Return the supported iova max address of the Vfio Pci device
1608    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        // fast handle for pci config space
1621        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        // Do not use a fixed IRQ for VFIO devices. The sysfs "irq" file reports a host-assigned IRQ
1688        // number that is not meaningful for the guest and can exceed the u8 range required by the
1689        // MP table. Let the VMM allocate a guest IRQ instead; VFIO handles host/guest
1690        // interrupt mapping regardless of the guest IRQ number chosen.
1691        PreferredIrq::Any
1692    }
1693
1694    fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
1695        // Keep event/resample event references.
1696        self.interrupt_evt = Some(irq_evt);
1697
1698        // enable INTX
1699        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        // Quirk, enable igd memory for guest vga arbitrate, otherwise kernel vga arbitrate
1723        // driver doesn't claim this vga device, then xorg couldn't boot up.
1724        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        // Make intel gfx's opregion as mmio bar, and allocate a gpa for it
1743        // then write this gpa into pci cfg register
1744        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        // See VfioPciDevice::new for details how extended caps are managed
1812        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        // Ignore IO bar
1830        if (0x10..=0x24).contains(&reg) {
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        // Quirk for intel graphic, set stolen memory size to 0 in pci_cfg[0x51]
1850        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        // When guest write config register at the first time, start worker thread
1859        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 guest enable memory access, then enable bar mappable once
1910        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                        // Change 32bit bar address
1926                        *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                        // Change 64bit bar low address
1930                        *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                    // Change 64bit bar high address
1940                    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                // if bar is changed under memory enabled, mmap the
1952                // new bar immediately.
1953                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        // Ignore igd opregion's write
2047        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                // All vfio-pci devices should have virtual _PRx method, otherwise
2091                // host couldn't know whether device has enter into suspend state,
2092                // host would always think it is in active state, so its parent PCIe
2093                // switch couldn't enter into suspend state.
2094                PowerResourceMethod {}.to_aml_bytes(&mut amls);
2095                // TODO: WIP: Ideally, we should generate DSM only if the physical
2096                // device has a _DSM; however, such information is not provided by
2097                // Linux. As a temporary workaround, we chech whether there is an
2098                // associated ACPI companion device node and skip generating guest
2099                // _DSM if there is none.
2100                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        // regions [32, 95]
2149        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        // regions [32, 95]
2165        let mut memory =
2166            VfioResourceAllocator::new(AddressRange::from_start_and_end(32, 95)).unwrap();
2167        // regions [32, 47], [64, 95]
2168        memory
2169            .allocate_at_can_overlap(AddressRange::from_start_and_end(48, 63))
2170            .unwrap();
2171        // regions [64, 95]
2172        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        // regions [32, 95]
2183        let mut memory =
2184            VfioResourceAllocator::new(AddressRange::from_start_and_end(32, 95)).unwrap();
2185        // regions [32, 47], [64, 95]
2186        memory
2187            .allocate_at_can_overlap(AddressRange::from_start_and_end(48, 63))
2188            .unwrap();
2189        // regions [32, 39], [64, 95]
2190        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        // regions [32, 95]
2202        let mut memory =
2203            VfioResourceAllocator::new(AddressRange::from_start_and_end(32, 95)).unwrap();
2204        // regions [32, 47], [64, 95]
2205        memory
2206            .allocate_at_can_overlap(AddressRange::from_start_and_end(48, 63))
2207            .unwrap();
2208        // regions [32, 39], [72, 95]
2209        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        // regions [32, 95]
2221        let mut memory =
2222            VfioResourceAllocator::new(AddressRange::from_start_and_end(32, 95)).unwrap();
2223        // regions [32, 39], [48, 95]
2224        memory
2225            .allocate_at_can_overlap(AddressRange::from_start_and_end(40, 47))
2226            .unwrap();
2227        // regions [32, 39], [48, 63], [72, 95]
2228        memory
2229            .allocate_at_can_overlap(AddressRange::from_start_and_end(64, 71))
2230            .unwrap();
2231        // regions [32, 35], [76, 95]
2232        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}