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