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