• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 
5 use std::collections::HashMap;
6 use std::collections::HashSet;
7 use std::sync::Arc;
8 
9 #[cfg(target_arch = "x86_64")]
10 use acpi_tables::sdt::SDT;
11 use anyhow::bail;
12 use base::error;
13 use base::trace;
14 use base::warn;
15 use base::MemoryMapping;
16 use base::RawDescriptor;
17 use base::SharedMemory;
18 use remain::sorted;
19 use resources::Error as SystemAllocatorFaliure;
20 use resources::SystemAllocator;
21 use sync::Mutex;
22 use thiserror::Error;
23 use vm_control::api::VmMemoryClient;
24 
25 use super::PciId;
26 use crate::bus::BusDeviceObj;
27 use crate::bus::BusRange;
28 use crate::bus::BusType;
29 use crate::bus::ConfigWriteResult;
30 use crate::pci::pci_configuration;
31 use crate::pci::pci_configuration::PciBarConfiguration;
32 use crate::pci::pci_configuration::COMMAND_REG;
33 use crate::pci::pci_configuration::COMMAND_REG_IO_SPACE_MASK;
34 use crate::pci::pci_configuration::COMMAND_REG_MEMORY_SPACE_MASK;
35 use crate::pci::pci_configuration::NUM_BAR_REGS;
36 use crate::pci::pci_configuration::PCI_ID_REG;
37 use crate::pci::PciAddress;
38 use crate::pci::PciAddressError;
39 use crate::pci::PciBarIndex;
40 use crate::pci::PciInterruptPin;
41 use crate::virtio::ipc_memory_mapper::IpcMemoryMapper;
42 #[cfg(all(unix, feature = "audio"))]
43 use crate::virtio::snd::vios_backend::Error as VioSError;
44 use crate::BusAccessInfo;
45 use crate::BusDevice;
46 use crate::DeviceId;
47 use crate::IrqLevelEvent;
48 use crate::Suspendable;
49 use crate::VirtioPciDevice;
50 
51 #[sorted]
52 #[derive(Error, Debug)]
53 pub enum Error {
54     /// Deactivation of ACPI notifications failed
55     #[error("failed to disable ACPI notifications")]
56     AcpiNotifyDeactivationFailed,
57     /// Setup of ACPI notifications failed
58     #[error("failed to enable ACPI notifications")]
59     AcpiNotifySetupFailed,
60     /// Simulating ACPI notifications hardware triggering failed
61     #[error("failed to test ACPI notifications")]
62     AcpiNotifyTestFailed,
63     /// Added pci device's parent bus does not belong to this bus
64     #[error("pci device {0}'s parent bus does not belong to bus {1}")]
65     AddedDeviceBusNotExist(PciAddress, u8),
66     /// Invalid alignment encountered.
67     #[error("Alignment must be a power of 2")]
68     BadAlignment,
69     /// The new bus has already been added to this bus
70     #[error("Added bus {0} already existed on bus {1}")]
71     BusAlreadyExist(u8, u8),
72     /// Target bus not exists on this bus
73     #[error("pci bus {0} does not exist on bus {1}")]
74     BusNotExist(u8, u8),
75     /// Setup of the device capabilities failed.
76     #[error("failed to add capability {0}")]
77     CapabilitiesSetup(pci_configuration::Error),
78     /// Create cras client failed.
79     #[cfg(all(unix, feature = "audio", feature = "audio_cras"))]
80     #[error("failed to create CRAS Client: {0}")]
81     CreateCrasClientFailed(libcras::Error),
82     /// Create VioS client failed.
83     #[cfg(all(unix, feature = "audio"))]
84     #[error("failed to create VioS Client: {0}")]
85     CreateViosClientFailed(VioSError),
86     /// Device is already on this bus
87     #[error("pci device {0} has already been added to bus {1}")]
88     DeviceAlreadyExist(PciAddress, u8),
89     /// Device not exist on this bus
90     #[error("pci device {0} does not located on bus {1}")]
91     DeviceNotExist(PciAddress, u8),
92     /// Allocating space for an IO BAR failed.
93     #[error("failed to allocate space for an IO BAR, size={0}: {1}")]
94     IoAllocationFailed(u64, SystemAllocatorFaliure),
95     /// ioevent registration failed.
96     #[error("IoEvent registration failed: {0}")]
97     IoEventRegisterFailed(IoEventError),
98     /// supports_iommu is false.
99     #[error("Iommu is not supported")]
100     IommuNotSupported,
101     /// Registering an IO BAR failed.
102     #[error("failed to register an IO BAR, addr={0} err={1}")]
103     IoRegistrationFailed(u64, pci_configuration::Error),
104     /// Setting up MMIO mapping
105     #[error("failed to set up MMIO mapping: {0}")]
106     MmioSetup(anyhow::Error),
107     /// Out-of-space encountered
108     #[error("Out-of-space detected")]
109     OutOfSpace,
110     /// Overflow encountered
111     #[error("base={0} + size={1} overflows")]
112     Overflow(u64, u64),
113     /// The new added bus does not located on this bus
114     #[error("Added bus {0} does not located on bus {1}")]
115     ParentBusNotExist(u8, u8),
116     /// PCI Address is not allocated.
117     #[error("PCI address is not allocated")]
118     PciAddressMissing,
119     /// PCI Address parsing failure.
120     #[error("PCI address '{0}' could not be parsed: {1}")]
121     PciAddressParseFailure(String, PciAddressError),
122     /// PCI Address allocation failure.
123     #[error("failed to allocate PCI address")]
124     PciAllocationFailed,
125     /// PCI Bus window allocation failure.
126     #[error("failed to allocate window for PCI bus: {0}")]
127     PciBusWindowAllocationFailure(String),
128     /// Size of zero encountered
129     #[error("Size of zero detected")]
130     SizeZero,
131 }
132 
133 /// Errors when io event registration fails:
134 #[derive(Clone, Debug, Error)]
135 pub enum IoEventError {
136     /// Event clone failed.
137     #[error("Event clone failed: {0}")]
138     CloneFail(base::Error),
139     /// Failed due to system error.
140     #[error("System error: {0}")]
141     SystemError(base::Error),
142     /// Tube for ioevent register failed.
143     #[error("IoEvent register Tube failed")]
144     TubeFail,
145     /// ioevent_register_request not implemented for PciDevice emitting it.
146     #[error("ioevent register not implemented")]
147     Unsupported,
148 }
149 
150 pub type Result<T> = std::result::Result<T, Error>;
151 
152 /// Pci Bar Range information
153 #[derive(Clone, Debug)]
154 pub struct BarRange {
155     /// pci bar start address
156     pub addr: u64,
157     /// pci bar size
158     pub size: u64,
159     /// pci bar is prefetchable or not, it used to set parent's bridge window
160     pub prefetchable: bool,
161 }
162 
163 /// Pci Bus information
164 #[derive(Debug)]
165 pub struct PciBus {
166     // bus number
167     bus_num: u8,
168     // parent bus number
169     parent_bus_num: u8,
170     // devices located on this bus
171     child_devices: HashSet<PciAddress>,
172     // Hash map that stores all direct child buses of this bus.
173     // It maps from child bus number to its pci bus structure.
174     child_buses: HashMap<u8, Arc<Mutex<PciBus>>>,
175     // Is hotplug bus
176     hotplug_bus: bool,
177 }
178 
179 impl PciBus {
180     // Creates a new pci bus
new(bus_num: u8, parent_bus_num: u8, hotplug_bus: bool) -> Self181     pub fn new(bus_num: u8, parent_bus_num: u8, hotplug_bus: bool) -> Self {
182         PciBus {
183             bus_num,
184             parent_bus_num,
185             child_devices: HashSet::new(),
186             child_buses: HashMap::new(),
187             hotplug_bus,
188         }
189     }
190 
get_bus_num(&self) -> u8191     pub fn get_bus_num(&self) -> u8 {
192         self.bus_num
193     }
194 
195     // Find all PCI buses from this PCI bus to a given PCI bus
path_to(&self, bus_num: u8) -> Vec<u8>196     pub fn path_to(&self, bus_num: u8) -> Vec<u8> {
197         if self.bus_num == bus_num {
198             return vec![self.bus_num];
199         }
200 
201         for (_, child_bus) in self.child_buses.iter() {
202             let mut path = child_bus.lock().path_to(bus_num);
203             if !path.is_empty() {
204                 path.insert(0, self.bus_num);
205                 return path;
206             }
207         }
208         Vec::new()
209     }
210 
211     // Add a new child device to this pci bus tree.
add_child_device(&mut self, add_device: PciAddress) -> Result<()>212     pub fn add_child_device(&mut self, add_device: PciAddress) -> Result<()> {
213         if self.bus_num == add_device.bus {
214             if !self.child_devices.insert(add_device) {
215                 return Err(Error::DeviceAlreadyExist(add_device, self.bus_num));
216             }
217             return Ok(());
218         }
219 
220         for child_bus in self.child_buses.values() {
221             match child_bus.lock().add_child_device(add_device) {
222                 Ok(()) => return Ok(()),
223                 Err(e) => {
224                     if let Error::DeviceAlreadyExist(_, _) = e {
225                         return Err(e);
226                     }
227                 }
228             }
229         }
230         Err(Error::AddedDeviceBusNotExist(add_device, self.bus_num))
231     }
232 
233     // Remove one child device from this pci bus tree
remove_child_device(&mut self, device: PciAddress) -> Result<()>234     pub fn remove_child_device(&mut self, device: PciAddress) -> Result<()> {
235         if self.child_devices.remove(&device) {
236             return Ok(());
237         }
238         for child_bus in self.child_buses.values() {
239             if child_bus.lock().remove_child_device(device).is_ok() {
240                 return Ok(());
241             }
242         }
243         Err(Error::DeviceNotExist(device, self.bus_num))
244     }
245 
246     // Add a new child bus to this pci bus tree.
add_child_bus(&mut self, add_bus: Arc<Mutex<PciBus>>) -> Result<()>247     pub fn add_child_bus(&mut self, add_bus: Arc<Mutex<PciBus>>) -> Result<()> {
248         let add_bus_num = add_bus.lock().bus_num;
249         let add_bus_parent = add_bus.lock().parent_bus_num;
250         if self.bus_num == add_bus_parent {
251             if self.child_buses.contains_key(&add_bus_num) {
252                 return Err(Error::BusAlreadyExist(self.bus_num, add_bus_num));
253             }
254             self.child_buses.insert(add_bus_num, add_bus);
255             return Ok(());
256         }
257 
258         for child_bus in self.child_buses.values() {
259             match child_bus.lock().add_child_bus(add_bus.clone()) {
260                 Ok(_) => return Ok(()),
261                 Err(e) => {
262                     if let Error::BusAlreadyExist(_, _) = e {
263                         return Err(e);
264                     }
265                 }
266             }
267         }
268         Err(Error::ParentBusNotExist(add_bus_num, self.bus_num))
269     }
270 
271     // Remove one child bus from this pci bus tree.
remove_child_bus(&mut self, bus_no: u8) -> Result<()>272     pub fn remove_child_bus(&mut self, bus_no: u8) -> Result<()> {
273         if self.child_buses.remove(&bus_no).is_some() {
274             return Ok(());
275         }
276         for (_, child_bus) in self.child_buses.iter() {
277             if child_bus.lock().remove_child_bus(bus_no).is_ok() {
278                 return Ok(());
279             }
280         }
281         Err(Error::BusNotExist(bus_no, self.bus_num))
282     }
283 
284     // Find all downstream devices under the given bus
find_downstream_devices(&self, bus_no: u8) -> Vec<PciAddress>285     pub fn find_downstream_devices(&self, bus_no: u8) -> Vec<PciAddress> {
286         if self.bus_num == bus_no {
287             return self.get_downstream_devices();
288         }
289         for (_, child_bus) in self.child_buses.iter() {
290             let res = child_bus.lock().find_downstream_devices(bus_no);
291             if !res.is_empty() {
292                 return res;
293             }
294         }
295 
296         Vec::new()
297     }
298 
299     // Get all devices in this pci bus tree by level-order traversal (BFS)
get_downstream_devices(&self) -> Vec<PciAddress>300     pub fn get_downstream_devices(&self) -> Vec<PciAddress> {
301         let mut devices = Vec::new();
302         devices.extend(self.child_devices.clone());
303         for child_bus in self.child_buses.values() {
304             devices.extend(child_bus.lock().get_downstream_devices());
305         }
306         devices
307     }
308 
309     // Check if given device is located in the device tree
contains(&self, device: PciAddress) -> bool310     pub fn contains(&self, device: PciAddress) -> bool {
311         if self.child_devices.contains(&device) {
312             return true;
313         }
314 
315         for (_, child_bus) in self.child_buses.iter() {
316             if child_bus.lock().contains(device) {
317                 return true;
318             }
319         }
320 
321         false
322     }
323 
324     // Returns the hotplug bus that this device is on.
get_hotplug_bus(&self, device: PciAddress) -> Option<u8>325     pub fn get_hotplug_bus(&self, device: PciAddress) -> Option<u8> {
326         if self.hotplug_bus && self.contains(device) {
327             return Some(self.bus_num);
328         }
329         for (_, child_bus) in self.child_buses.iter() {
330             let hotplug_bus = child_bus.lock().get_hotplug_bus(device);
331             if hotplug_bus.is_some() {
332                 return hotplug_bus;
333             }
334         }
335         None
336     }
337 }
338 
339 pub enum PreferredIrq {
340     None,
341     Any,
342     Fixed { pin: PciInterruptPin, gsi: u32 },
343 }
344 
345 pub trait PciDevice: Send + Suspendable {
346     /// Returns a label suitable for debug output.
debug_label(&self) -> String347     fn debug_label(&self) -> String;
348 
349     /// Preferred PCI address for this device, if any.
preferred_address(&self) -> Option<PciAddress>350     fn preferred_address(&self) -> Option<PciAddress> {
351         None
352     }
353 
354     /// Allocate and return an unique bus, device and function number for this device.
355     /// May be called multiple times; on subsequent calls, the device should return the same
356     /// address it returned from the first call.
allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>357     fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>;
358 
359     /// A vector of device-specific file descriptors that must be kept open
360     /// after jailing. Must be called before the process is jailed.
keep_rds(&self) -> Vec<RawDescriptor>361     fn keep_rds(&self) -> Vec<RawDescriptor>;
362 
363     /// Preferred IRQ for this device.
364     /// The device may request a specific pin and IRQ number by returning a `Fixed` value.
365     /// If a device does not support INTx# interrupts at all, it should return `None`.
366     /// Otherwise, an appropriate IRQ will be allocated automatically.
367     /// The device's `assign_irq` function will be called with its assigned IRQ either way.
preferred_irq(&self) -> PreferredIrq368     fn preferred_irq(&self) -> PreferredIrq {
369         PreferredIrq::Any
370     }
371 
372     /// Assign a legacy PCI IRQ to this device.
373     /// The device may write to `irq_evt` to trigger an interrupt.
374     /// When `irq_resample_evt` is signaled, the device should re-assert `irq_evt` if necessary.
assign_irq(&mut self, _irq_evt: IrqLevelEvent, _pin: PciInterruptPin, _irq_num: u32)375     fn assign_irq(&mut self, _irq_evt: IrqLevelEvent, _pin: PciInterruptPin, _irq_num: u32) {}
376 
377     /// Allocates the needed IO BAR space using the `allocate` function which takes a size and
378     /// returns an address. Returns a Vec of BarRange{addr, size, prefetchable}.
allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<BarRange>>379     fn allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<BarRange>> {
380         Ok(Vec::new())
381     }
382 
383     /// Allocates the needed device BAR space. Returns a Vec of BarRange{addr, size, prefetchable}.
384     /// Unlike MMIO BARs (see allocate_io_bars), device BARs are not expected to incur VM exits
385     /// - these BARs represent normal memory.
allocate_device_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<BarRange>>386     fn allocate_device_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<BarRange>> {
387         Ok(Vec::new())
388     }
389 
390     /// Returns the configuration of a base address register, if present.
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>391     fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>;
392 
393     /// Register any capabilties specified by the device.
register_device_capabilities(&mut self) -> Result<()>394     fn register_device_capabilities(&mut self) -> Result<()> {
395         Ok(())
396     }
397 
398     /// Gets a reference to the API client for sending VmMemoryRequest. Any devices that uses
399     /// ioevents must provide this.
get_vm_memory_client(&self) -> Option<&VmMemoryClient>400     fn get_vm_memory_client(&self) -> Option<&VmMemoryClient> {
401         None
402     }
403 
404     /// Reads from a PCI configuration register.
405     /// * `reg_idx` - PCI register index (in units of 4 bytes).
read_config_register(&self, reg_idx: usize) -> u32406     fn read_config_register(&self, reg_idx: usize) -> u32;
407 
408     /// Writes to a PCI configuration register.
409     /// * `reg_idx` - PCI register index (in units of 4 bytes).
410     /// * `offset`  - byte offset within 4-byte register.
411     /// * `data`    - The data to write.
write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])412     fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]);
413 
414     /// Provides a memory region to back MMIO access to the configuration
415     /// space. If the device can keep the memory region up to date, then it
416     /// should return Ok(true), after which no more calls to read_config_register
417     /// will be made. If support isn't implemented, it should return Ok(false).
418     /// Otherwise, it should return an error (a failure here is not treated as
419     /// a fatal setup error).
420     ///
421     /// The device must set the header type register (0x0E) before returning
422     /// from this function, and must make no further modifications to it
423     /// after returning. This is to allow the caller to manage the multi-
424     /// function device bit without worrying about race conditions.
425     ///
426     /// * `shmem` - The shared memory to use for the configuration space.
427     /// * `base` - The base address of the memory region in shmem.
428     /// * `len` - The length of the memory region.
setup_pci_config_mapping( &mut self, _shmem: &SharedMemory, _base: usize, _len: usize, ) -> Result<bool>429     fn setup_pci_config_mapping(
430         &mut self,
431         _shmem: &SharedMemory,
432         _base: usize,
433         _len: usize,
434     ) -> Result<bool> {
435         Ok(false)
436     }
437 
438     /// Reads from a virtual config register.
439     /// * `reg_idx` - virtual config register index (in units of 4 bytes).
read_virtual_config_register(&self, _reg_idx: usize) -> u32440     fn read_virtual_config_register(&self, _reg_idx: usize) -> u32 {
441         0
442     }
443 
444     /// Writes to a virtual config register.
445     /// * `reg_idx` - virtual config register index (in units of 4 bytes).
446     /// * `value`   - the value to be written.
write_virtual_config_register(&mut self, _reg_idx: usize, _value: u32)447     fn write_virtual_config_register(&mut self, _reg_idx: usize, _value: u32) {}
448 
449     /// Reads from a BAR region mapped in to the device.
450     /// * `bar_index` - The index of the PCI BAR.
451     /// * `offset` - The starting offset in bytes inside the BAR.
452     /// * `data` - Filled with the data from `offset`.
read_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &mut [u8])453     fn read_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &mut [u8]);
454 
455     /// Writes to a BAR region mapped in to the device.
456     /// * `bar_index` - The index of the PCI BAR.
457     /// * `offset` - The starting offset in bytes inside the BAR.
458     /// * `data` - The data to write.
write_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &[u8])459     fn write_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &[u8]);
460 
461     /// Invoked when the device is sandboxed.
on_device_sandboxed(&mut self)462     fn on_device_sandboxed(&mut self) {}
463 
464     #[cfg(target_arch = "x86_64")]
generate_acpi(&mut self, sdts: Vec<SDT>) -> Option<Vec<SDT>>465     fn generate_acpi(&mut self, sdts: Vec<SDT>) -> Option<Vec<SDT>> {
466         Some(sdts)
467     }
468 
469     /// Construct customized acpi method, and return the AML code and
470     /// shared memory
generate_acpi_methods(&mut self) -> (Vec<u8>, Option<(u32, MemoryMapping)>)471     fn generate_acpi_methods(&mut self) -> (Vec<u8>, Option<(u32, MemoryMapping)>) {
472         (Vec::new(), None)
473     }
474 
set_gpe(&mut self, _resources: &mut SystemAllocator) -> Option<u32>475     fn set_gpe(&mut self, _resources: &mut SystemAllocator) -> Option<u32> {
476         None
477     }
478 
479     /// Invoked when the device is destroyed
destroy_device(&mut self)480     fn destroy_device(&mut self) {}
481 
482     /// Get the removed children devices under pci bridge
get_removed_children_devices(&self) -> Vec<PciAddress>483     fn get_removed_children_devices(&self) -> Vec<PciAddress> {
484         Vec::new()
485     }
486 
487     /// Get the pci bus generated by this pci device
get_new_pci_bus(&self) -> Option<Arc<Mutex<PciBus>>>488     fn get_new_pci_bus(&self) -> Option<Arc<Mutex<PciBus>>> {
489         None
490     }
491 
492     /// if device is a pci brdige, configure pci bridge window
configure_bridge_window( &mut self, _resources: &mut SystemAllocator, _bar_ranges: &[BarRange], ) -> Result<Vec<BarRange>>493     fn configure_bridge_window(
494         &mut self,
495         _resources: &mut SystemAllocator,
496         _bar_ranges: &[BarRange],
497     ) -> Result<Vec<BarRange>> {
498         Ok(Vec::new())
499     }
500 
501     /// if device is a pci bridge, configure subordinate bus number
set_subordinate_bus(&mut self, _bus_no: u8)502     fn set_subordinate_bus(&mut self, _bus_no: u8) {}
503 
504     /// Indicates whether the device supports IOMMU
supports_iommu(&self) -> bool505     fn supports_iommu(&self) -> bool {
506         false
507     }
508 
509     /// Sets the IOMMU for the device if `supports_iommu()`
set_iommu(&mut self, _iommu: IpcMemoryMapper) -> anyhow::Result<()>510     fn set_iommu(&mut self, _iommu: IpcMemoryMapper) -> anyhow::Result<()> {
511         bail!("Iommu not supported.");
512     }
513 
514     // Used for bootorder
as_virtio_pci_device(&self) -> Option<&VirtioPciDevice>515     fn as_virtio_pci_device(&self) -> Option<&VirtioPciDevice> {
516         None
517     }
518 }
519 
update_ranges( old_enabled: bool, new_enabled: bool, bus_type_filter: BusType, old_ranges: &[(BusRange, BusType)], new_ranges: &[(BusRange, BusType)], ) -> (Vec<BusRange>, Vec<BusRange>)520 fn update_ranges(
521     old_enabled: bool,
522     new_enabled: bool,
523     bus_type_filter: BusType,
524     old_ranges: &[(BusRange, BusType)],
525     new_ranges: &[(BusRange, BusType)],
526 ) -> (Vec<BusRange>, Vec<BusRange>) {
527     let mut remove_ranges = Vec::new();
528     let mut add_ranges = Vec::new();
529 
530     let old_ranges_filtered = old_ranges
531         .iter()
532         .filter(|(_range, bus_type)| *bus_type == bus_type_filter)
533         .map(|(range, _bus_type)| *range);
534     let new_ranges_filtered = new_ranges
535         .iter()
536         .filter(|(_range, bus_type)| *bus_type == bus_type_filter)
537         .map(|(range, _bus_type)| *range);
538 
539     if old_enabled && !new_enabled {
540         // Bus type was enabled and is now disabled; remove all old ranges.
541         remove_ranges.extend(old_ranges_filtered);
542     } else if !old_enabled && new_enabled {
543         // Bus type was disabled and is now enabled; add all new ranges.
544         add_ranges.extend(new_ranges_filtered);
545     } else if old_enabled && new_enabled {
546         // Bus type was enabled before and is still enabled; diff old and new ranges.
547         for (old_range, new_range) in old_ranges_filtered.zip(new_ranges_filtered) {
548             if old_range.base != new_range.base {
549                 remove_ranges.push(old_range);
550                 add_ranges.push(new_range);
551             }
552         }
553     }
554 
555     (remove_ranges, add_ranges)
556 }
557 
558 // Debug-only helper function to convert a slice of bytes into a u32.
559 // This can be lossy - only use it for logging!
trace_data(data: &[u8], offset: u64) -> u32560 fn trace_data(data: &[u8], offset: u64) -> u32 {
561     let mut data4 = [0u8; 4];
562     for (d, s) in data4.iter_mut().skip(offset as usize).zip(data.iter()) {
563         *d = *s;
564     }
565     u32::from_le_bytes(data4)
566 }
567 
568 /// Find the BAR containing an access specified by `address` and `size`.
569 ///
570 /// If found, returns the BAR index and offset in bytes within that BAR corresponding to `address`.
571 ///
572 /// The BAR must fully contain the access region; partial overlaps will return `None`. Zero-sized
573 /// accesses should not normally happen, but in case one does, this function will return `None`.
574 ///
575 /// This function only finds memory BARs, not I/O BARs. If a device with a BAR in I/O address space
576 /// is ever added, address space information will need to be added to `BusDevice::read()` and
577 /// `BusDevice::write()` and passed along to this function.
find_bar_and_offset( device: &impl PciDevice, address: u64, size: usize, ) -> Option<(PciBarIndex, u64)>578 fn find_bar_and_offset(
579     device: &impl PciDevice,
580     address: u64,
581     size: usize,
582 ) -> Option<(PciBarIndex, u64)> {
583     if size == 0 {
584         return None;
585     }
586 
587     for bar_index in 0..NUM_BAR_REGS {
588         if let Some(bar_info) = device.get_bar_configuration(bar_index) {
589             if !bar_info.is_memory() {
590                 continue;
591             }
592 
593             // If access address >= BAR address, calculate the offset of the access in bytes from
594             // the start of the BAR. If underflow occurs, the access begins before this BAR, so it
595             // cannot be fully contained in the BAR; skip to the next BAR.
596             let Some(offset) = address.checked_sub(bar_info.address()) else {
597                 continue;
598             };
599 
600             // Calculate the largest valid offset given the BAR size and access size. If underflow
601             // occurs, the access size is larger than the BAR size, so the access is definitely not
602             // fully contained in the BAR; skip to the next BAR.
603             let Some(max_offset) = bar_info.size().checked_sub(size as u64) else {
604                 continue;
605             };
606 
607             // If offset <= max_offset, then the access is entirely contained within the BAR.
608             if offset <= max_offset {
609                 return Some((bar_index, offset));
610             }
611         }
612     }
613 
614     None
615 }
616 
617 impl<T: PciDevice> BusDevice for T {
debug_label(&self) -> String618     fn debug_label(&self) -> String {
619         PciDevice::debug_label(self)
620     }
621 
device_id(&self) -> DeviceId622     fn device_id(&self) -> DeviceId {
623         // Use the PCI ID for PCI devices, which contains the PCI vendor ID and the PCI device ID
624         let pci_id: PciId = PciDevice::read_config_register(self, PCI_ID_REG).into();
625         pci_id.into()
626     }
627 
read(&mut self, info: BusAccessInfo, data: &mut [u8])628     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
629         if let Some((bar_index, offset)) = find_bar_and_offset(self, info.address, data.len()) {
630             self.read_bar(bar_index, offset, data);
631         } else {
632             error!("PciDevice::read({:#x}) did not match a BAR", info.address);
633         }
634     }
635 
write(&mut self, info: BusAccessInfo, data: &[u8])636     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
637         if let Some((bar_index, offset)) = find_bar_and_offset(self, info.address, data.len()) {
638             self.write_bar(bar_index, offset, data);
639         } else {
640             error!("PciDevice::write({:#x}) did not match a BAR", info.address);
641         }
642     }
643 
config_register_write( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> ConfigWriteResult644     fn config_register_write(
645         &mut self,
646         reg_idx: usize,
647         offset: u64,
648         data: &[u8],
649     ) -> ConfigWriteResult {
650         if offset as usize + data.len() > 4 {
651             return Default::default();
652         }
653 
654         trace!(
655             "reg_idx {:02X} data {:08X}",
656             reg_idx,
657             trace_data(data, offset)
658         );
659 
660         let old_command_reg = self.read_config_register(COMMAND_REG);
661         let old_ranges =
662             if old_command_reg & (COMMAND_REG_MEMORY_SPACE_MASK | COMMAND_REG_IO_SPACE_MASK) != 0 {
663                 self.get_ranges()
664             } else {
665                 Vec::new()
666             };
667 
668         self.write_config_register(reg_idx, offset, data);
669 
670         let new_command_reg = self.read_config_register(COMMAND_REG);
671         let new_ranges =
672             if new_command_reg & (COMMAND_REG_MEMORY_SPACE_MASK | COMMAND_REG_IO_SPACE_MASK) != 0 {
673                 self.get_ranges()
674             } else {
675                 Vec::new()
676             };
677 
678         let (mmio_remove, mmio_add) = update_ranges(
679             old_command_reg & COMMAND_REG_MEMORY_SPACE_MASK != 0,
680             new_command_reg & COMMAND_REG_MEMORY_SPACE_MASK != 0,
681             BusType::Mmio,
682             &old_ranges,
683             &new_ranges,
684         );
685 
686         let (io_remove, io_add) = update_ranges(
687             old_command_reg & COMMAND_REG_IO_SPACE_MASK != 0,
688             new_command_reg & COMMAND_REG_IO_SPACE_MASK != 0,
689             BusType::Io,
690             &old_ranges,
691             &new_ranges,
692         );
693 
694         ConfigWriteResult {
695             mmio_remove,
696             mmio_add,
697             io_remove,
698             io_add,
699             removed_pci_devices: self.get_removed_children_devices(),
700         }
701     }
702 
config_register_read(&self, reg_idx: usize) -> u32703     fn config_register_read(&self, reg_idx: usize) -> u32 {
704         self.read_config_register(reg_idx)
705     }
706 
init_pci_config_mapping(&mut self, shmem: &SharedMemory, base: usize, len: usize) -> bool707     fn init_pci_config_mapping(&mut self, shmem: &SharedMemory, base: usize, len: usize) -> bool {
708         match self.setup_pci_config_mapping(shmem, base, len) {
709             Ok(res) => res,
710             Err(err) => {
711                 warn!("Failed to create PCI mapping: {:#}", err);
712                 false
713             }
714         }
715     }
716 
virtual_config_register_write(&mut self, reg_idx: usize, value: u32)717     fn virtual_config_register_write(&mut self, reg_idx: usize, value: u32) {
718         self.write_virtual_config_register(reg_idx, value);
719     }
720 
virtual_config_register_read(&self, reg_idx: usize) -> u32721     fn virtual_config_register_read(&self, reg_idx: usize) -> u32 {
722         self.read_virtual_config_register(reg_idx)
723     }
724 
on_sandboxed(&mut self)725     fn on_sandboxed(&mut self) {
726         self.on_device_sandboxed();
727     }
728 
get_ranges(&self) -> Vec<(BusRange, BusType)>729     fn get_ranges(&self) -> Vec<(BusRange, BusType)> {
730         let mut ranges = Vec::new();
731         for bar_num in 0..NUM_BAR_REGS {
732             if let Some(bar) = self.get_bar_configuration(bar_num) {
733                 let bus_type = if bar.is_memory() {
734                     BusType::Mmio
735                 } else {
736                     BusType::Io
737                 };
738                 ranges.push((
739                     BusRange {
740                         base: bar.address(),
741                         len: bar.size(),
742                     },
743                     bus_type,
744                 ));
745             }
746         }
747         ranges
748     }
749 
750     // Invoked when the device is destroyed
destroy_device(&mut self)751     fn destroy_device(&mut self) {
752         self.destroy_device()
753     }
754 
is_bridge(&self) -> Option<u8>755     fn is_bridge(&self) -> Option<u8> {
756         self.get_new_pci_bus().map(|bus| bus.lock().get_bus_num())
757     }
758 }
759 
760 impl<T: PciDevice + ?Sized> PciDevice for Box<T> {
761     /// Returns a label suitable for debug output.
debug_label(&self) -> String762     fn debug_label(&self) -> String {
763         (**self).debug_label()
764     }
preferred_address(&self) -> Option<PciAddress>765     fn preferred_address(&self) -> Option<PciAddress> {
766         (**self).preferred_address()
767     }
allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>768     fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> {
769         (**self).allocate_address(resources)
770     }
keep_rds(&self) -> Vec<RawDescriptor>771     fn keep_rds(&self) -> Vec<RawDescriptor> {
772         (**self).keep_rds()
773     }
preferred_irq(&self) -> PreferredIrq774     fn preferred_irq(&self) -> PreferredIrq {
775         (**self).preferred_irq()
776     }
assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32)777     fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
778         (**self).assign_irq(irq_evt, pin, irq_num)
779     }
allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<BarRange>>780     fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<BarRange>> {
781         (**self).allocate_io_bars(resources)
782     }
allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<BarRange>>783     fn allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<BarRange>> {
784         (**self).allocate_device_bars(resources)
785     }
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>786     fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
787         (**self).get_bar_configuration(bar_num)
788     }
register_device_capabilities(&mut self) -> Result<()>789     fn register_device_capabilities(&mut self) -> Result<()> {
790         (**self).register_device_capabilities()
791     }
read_virtual_config_register(&self, reg_idx: usize) -> u32792     fn read_virtual_config_register(&self, reg_idx: usize) -> u32 {
793         (**self).read_virtual_config_register(reg_idx)
794     }
write_virtual_config_register(&mut self, reg_idx: usize, value: u32)795     fn write_virtual_config_register(&mut self, reg_idx: usize, value: u32) {
796         (**self).write_virtual_config_register(reg_idx, value)
797     }
get_vm_memory_client(&self) -> Option<&VmMemoryClient>798     fn get_vm_memory_client(&self) -> Option<&VmMemoryClient> {
799         (**self).get_vm_memory_client()
800     }
read_config_register(&self, reg_idx: usize) -> u32801     fn read_config_register(&self, reg_idx: usize) -> u32 {
802         (**self).read_config_register(reg_idx)
803     }
write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])804     fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
805         (**self).write_config_register(reg_idx, offset, data)
806     }
setup_pci_config_mapping( &mut self, shmem: &SharedMemory, base: usize, len: usize, ) -> Result<bool>807     fn setup_pci_config_mapping(
808         &mut self,
809         shmem: &SharedMemory,
810         base: usize,
811         len: usize,
812     ) -> Result<bool> {
813         (**self).setup_pci_config_mapping(shmem, base, len)
814     }
read_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &mut [u8])815     fn read_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &mut [u8]) {
816         (**self).read_bar(bar_index, offset, data)
817     }
write_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &[u8])818     fn write_bar(&mut self, bar_index: PciBarIndex, offset: u64, data: &[u8]) {
819         (**self).write_bar(bar_index, offset, data)
820     }
821     /// Invoked when the device is sandboxed.
on_device_sandboxed(&mut self)822     fn on_device_sandboxed(&mut self) {
823         (**self).on_device_sandboxed()
824     }
825 
826     #[cfg(target_arch = "x86_64")]
generate_acpi(&mut self, sdts: Vec<SDT>) -> Option<Vec<SDT>>827     fn generate_acpi(&mut self, sdts: Vec<SDT>) -> Option<Vec<SDT>> {
828         (**self).generate_acpi(sdts)
829     }
830 
generate_acpi_methods(&mut self) -> (Vec<u8>, Option<(u32, MemoryMapping)>)831     fn generate_acpi_methods(&mut self) -> (Vec<u8>, Option<(u32, MemoryMapping)>) {
832         (**self).generate_acpi_methods()
833     }
834 
set_gpe(&mut self, resources: &mut SystemAllocator) -> Option<u32>835     fn set_gpe(&mut self, resources: &mut SystemAllocator) -> Option<u32> {
836         (**self).set_gpe(resources)
837     }
838 
destroy_device(&mut self)839     fn destroy_device(&mut self) {
840         (**self).destroy_device();
841     }
get_new_pci_bus(&self) -> Option<Arc<Mutex<PciBus>>>842     fn get_new_pci_bus(&self) -> Option<Arc<Mutex<PciBus>>> {
843         (**self).get_new_pci_bus()
844     }
get_removed_children_devices(&self) -> Vec<PciAddress>845     fn get_removed_children_devices(&self) -> Vec<PciAddress> {
846         (**self).get_removed_children_devices()
847     }
848 
configure_bridge_window( &mut self, resources: &mut SystemAllocator, bar_ranges: &[BarRange], ) -> Result<Vec<BarRange>>849     fn configure_bridge_window(
850         &mut self,
851         resources: &mut SystemAllocator,
852         bar_ranges: &[BarRange],
853     ) -> Result<Vec<BarRange>> {
854         (**self).configure_bridge_window(resources, bar_ranges)
855     }
856 }
857 
858 impl<T: PciDevice + ?Sized> Suspendable for Box<T> {
snapshot(&mut self) -> anyhow::Result<serde_json::Value>859     fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
860         (**self).snapshot()
861     }
862 
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>863     fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
864         (**self).restore(data)
865     }
866 
sleep(&mut self) -> anyhow::Result<()>867     fn sleep(&mut self) -> anyhow::Result<()> {
868         (**self).sleep()
869     }
870 
wake(&mut self) -> anyhow::Result<()>871     fn wake(&mut self) -> anyhow::Result<()> {
872         (**self).wake()
873     }
874 }
875 
876 impl<T: 'static + PciDevice> BusDeviceObj for T {
as_pci_device(&self) -> Option<&dyn PciDevice>877     fn as_pci_device(&self) -> Option<&dyn PciDevice> {
878         Some(self)
879     }
as_pci_device_mut(&mut self) -> Option<&mut dyn PciDevice>880     fn as_pci_device_mut(&mut self) -> Option<&mut dyn PciDevice> {
881         Some(self)
882     }
into_pci_device(self: Box<Self>) -> Option<Box<dyn PciDevice>>883     fn into_pci_device(self: Box<Self>) -> Option<Box<dyn PciDevice>> {
884         Some(self)
885     }
886 }
887 
888 #[cfg(test)]
889 mod tests {
890     use pci_configuration::PciBarPrefetchable;
891     use pci_configuration::PciBarRegionType;
892     use pci_configuration::PciClassCode;
893     use pci_configuration::PciConfiguration;
894     use pci_configuration::PciHeaderType;
895     use pci_configuration::PciMultimediaSubclass;
896 
897     use super::*;
898     use crate::pci::pci_configuration::BAR0_REG;
899 
900     const BAR0_SIZE: u64 = 0x1000;
901     const BAR2_SIZE: u64 = 0x20;
902     const BAR0_ADDR: u64 = 0xc0000000;
903     const BAR2_ADDR: u64 = 0x800;
904 
905     struct TestDev {
906         pub config_regs: PciConfiguration,
907     }
908 
909     impl PciDevice for TestDev {
debug_label(&self) -> String910         fn debug_label(&self) -> String {
911             "test".to_owned()
912         }
913 
keep_rds(&self) -> Vec<RawDescriptor>914         fn keep_rds(&self) -> Vec<RawDescriptor> {
915             Vec::new()
916         }
917 
read_config_register(&self, reg_idx: usize) -> u32918         fn read_config_register(&self, reg_idx: usize) -> u32 {
919             self.config_regs.read_reg(reg_idx)
920         }
921 
write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])922         fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
923             self.config_regs.write_reg(reg_idx, offset, data);
924         }
925 
read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8])926         fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {}
927 
write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8])928         fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {}
929 
allocate_address(&mut self, _resources: &mut SystemAllocator) -> Result<PciAddress>930         fn allocate_address(&mut self, _resources: &mut SystemAllocator) -> Result<PciAddress> {
931             Err(Error::PciAllocationFailed)
932         }
933 
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>934         fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
935             self.config_regs.get_bar_configuration(bar_num)
936         }
937     }
938 
939     impl Suspendable for TestDev {}
940 
941     #[test]
config_write_result()942     fn config_write_result() {
943         let mut test_dev = TestDev {
944             config_regs: PciConfiguration::new(
945                 0x1234,
946                 0xABCD,
947                 PciClassCode::MultimediaController,
948                 &PciMultimediaSubclass::AudioDevice,
949                 None,
950                 PciHeaderType::Device,
951                 0x5678,
952                 0xEF01,
953                 0,
954             ),
955         };
956 
957         let _ = test_dev.config_regs.add_pci_bar(
958             PciBarConfiguration::new(
959                 0,
960                 BAR0_SIZE,
961                 PciBarRegionType::Memory64BitRegion,
962                 PciBarPrefetchable::Prefetchable,
963             )
964             .set_address(BAR0_ADDR),
965         );
966         let _ = test_dev.config_regs.add_pci_bar(
967             PciBarConfiguration::new(
968                 2,
969                 BAR2_SIZE,
970                 PciBarRegionType::IoRegion,
971                 PciBarPrefetchable::NotPrefetchable,
972             )
973             .set_address(BAR2_ADDR),
974         );
975         let bar0_range = BusRange {
976             base: BAR0_ADDR,
977             len: BAR0_SIZE,
978         };
979         let bar2_range = BusRange {
980             base: BAR2_ADDR,
981             len: BAR2_SIZE,
982         };
983 
984         // Initialize command register to an all-zeroes value.
985         test_dev.config_register_write(COMMAND_REG, 0, &0u32.to_le_bytes());
986 
987         // Enable IO space access (bit 0 of command register).
988         assert_eq!(
989             test_dev.config_register_write(COMMAND_REG, 0, &1u32.to_le_bytes()),
990             ConfigWriteResult {
991                 mmio_remove: Vec::new(),
992                 mmio_add: Vec::new(),
993                 io_remove: Vec::new(),
994                 io_add: vec![bar2_range],
995                 removed_pci_devices: Vec::new(),
996             }
997         );
998 
999         // Enable memory space access (bit 1 of command register).
1000         assert_eq!(
1001             test_dev.config_register_write(COMMAND_REG, 0, &3u32.to_le_bytes()),
1002             ConfigWriteResult {
1003                 mmio_remove: Vec::new(),
1004                 mmio_add: vec![bar0_range],
1005                 io_remove: Vec::new(),
1006                 io_add: Vec::new(),
1007                 removed_pci_devices: Vec::new(),
1008             }
1009         );
1010 
1011         // Rewrite the same IO + mem value again (result should be no change).
1012         assert_eq!(
1013             test_dev.config_register_write(COMMAND_REG, 0, &3u32.to_le_bytes()),
1014             ConfigWriteResult {
1015                 mmio_remove: Vec::new(),
1016                 mmio_add: Vec::new(),
1017                 io_remove: Vec::new(),
1018                 io_add: Vec::new(),
1019                 removed_pci_devices: Vec::new(),
1020             }
1021         );
1022 
1023         // Disable IO space access, leaving mem enabled.
1024         assert_eq!(
1025             test_dev.config_register_write(COMMAND_REG, 0, &2u32.to_le_bytes()),
1026             ConfigWriteResult {
1027                 mmio_remove: Vec::new(),
1028                 mmio_add: Vec::new(),
1029                 io_remove: vec![bar2_range],
1030                 io_add: Vec::new(),
1031                 removed_pci_devices: Vec::new(),
1032             }
1033         );
1034 
1035         // Disable mem space access.
1036         assert_eq!(
1037             test_dev.config_register_write(COMMAND_REG, 0, &0u32.to_le_bytes()),
1038             ConfigWriteResult {
1039                 mmio_remove: vec![bar0_range],
1040                 mmio_add: Vec::new(),
1041                 io_remove: Vec::new(),
1042                 io_add: Vec::new(),
1043                 removed_pci_devices: Vec::new(),
1044             }
1045         );
1046 
1047         assert_eq!(test_dev.get_ranges(), Vec::new());
1048 
1049         // Re-enable mem and IO space.
1050         assert_eq!(
1051             test_dev.config_register_write(COMMAND_REG, 0, &3u32.to_le_bytes()),
1052             ConfigWriteResult {
1053                 mmio_remove: Vec::new(),
1054                 mmio_add: vec![bar0_range],
1055                 io_remove: Vec::new(),
1056                 io_add: vec![bar2_range],
1057                 removed_pci_devices: Vec::new(),
1058             }
1059         );
1060 
1061         // Change Bar0's address
1062         assert_eq!(
1063             test_dev.config_register_write(BAR0_REG, 0, &0xD0000000u32.to_le_bytes()),
1064             ConfigWriteResult {
1065                 mmio_remove: vec!(bar0_range),
1066                 mmio_add: vec![BusRange {
1067                     base: 0xD0000000,
1068                     len: BAR0_SIZE
1069                 }],
1070                 io_remove: Vec::new(),
1071                 io_add: Vec::new(),
1072                 removed_pci_devices: Vec::new(),
1073             }
1074         );
1075     }
1076 
1077     #[test]
find_bar()1078     fn find_bar() {
1079         let mut dev = TestDev {
1080             config_regs: PciConfiguration::new(
1081                 0x1234,
1082                 0xABCD,
1083                 PciClassCode::MultimediaController,
1084                 &PciMultimediaSubclass::AudioDevice,
1085                 None,
1086                 PciHeaderType::Device,
1087                 0x5678,
1088                 0xEF01,
1089                 0,
1090             ),
1091         };
1092 
1093         let _ = dev.config_regs.add_pci_bar(
1094             PciBarConfiguration::new(
1095                 0,
1096                 BAR0_SIZE,
1097                 PciBarRegionType::Memory64BitRegion,
1098                 PciBarPrefetchable::Prefetchable,
1099             )
1100             .set_address(BAR0_ADDR),
1101         );
1102         let _ = dev.config_regs.add_pci_bar(
1103             PciBarConfiguration::new(
1104                 2,
1105                 BAR2_SIZE,
1106                 PciBarRegionType::IoRegion,
1107                 PciBarPrefetchable::NotPrefetchable,
1108             )
1109             .set_address(BAR2_ADDR),
1110         );
1111 
1112         // No matching BAR
1113         assert_eq!(find_bar_and_offset(&dev, 0, 4), None);
1114         assert_eq!(find_bar_and_offset(&dev, 0xbfffffff, 4), None);
1115         assert_eq!(find_bar_and_offset(&dev, 0xc0000000, 0), None);
1116         assert_eq!(find_bar_and_offset(&dev, 0xc0000000, 0x1001), None);
1117         assert_eq!(find_bar_and_offset(&dev, 0xffff_ffff_ffff_ffff, 1), None);
1118         assert_eq!(find_bar_and_offset(&dev, 0xffff_ffff_ffff_ffff, 4), None);
1119 
1120         // BAR0 (64-bit memory BAR at 0xc0000000, size 0x1000)
1121         assert_eq!(find_bar_and_offset(&dev, 0xc0000000, 4), Some((0, 0)));
1122         assert_eq!(find_bar_and_offset(&dev, 0xc0000001, 4), Some((0, 1)));
1123         assert_eq!(find_bar_and_offset(&dev, 0xc0000ffc, 4), Some((0, 0xffc)));
1124         assert_eq!(find_bar_and_offset(&dev, 0xc0000ffd, 4), None);
1125         assert_eq!(find_bar_and_offset(&dev, 0xc0000ffe, 4), None);
1126         assert_eq!(find_bar_and_offset(&dev, 0xc0000fff, 4), None);
1127         assert_eq!(find_bar_and_offset(&dev, 0xc0000fff, 1), Some((0, 0xfff)));
1128         assert_eq!(find_bar_and_offset(&dev, 0xc0001000, 1), None);
1129         assert_eq!(find_bar_and_offset(&dev, 0xc0000000, 0xfff), Some((0, 0)));
1130         assert_eq!(find_bar_and_offset(&dev, 0xc0000000, 0x1000), Some((0, 0)));
1131 
1132         // BAR2 (I/O BAR)
1133         assert_eq!(find_bar_and_offset(&dev, 0x800, 1), None);
1134     }
1135 }
1136