Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/pci/pci_root.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::btree_map::Entry as BTreeMapEntry;
6
use std::collections::BTreeMap;
7
use std::convert::TryInto;
8
use std::ops::Bound::Included;
9
use std::ops::DerefMut;
10
use std::sync::Arc;
11
use std::sync::Weak;
12
13
use anyhow::Context;
14
use base::error;
15
use base::MemoryMapping;
16
use base::MemoryMappingBuilder;
17
use base::Protection;
18
use base::RawDescriptor;
19
use base::SendTube;
20
use base::SharedMemory;
21
use base::VmEventType;
22
use hypervisor::MemCacheType;
23
use hypervisor::Vm;
24
use resources::SystemAllocator;
25
use serde::Deserialize;
26
use serde::Serialize;
27
use snapshot::AnySnapshot;
28
use sync::Mutex;
29
use vm_control::DeviceId;
30
use vm_control::PciId;
31
use vm_memory::GuestAddress;
32
33
use crate::pci::pci_configuration::PciBarConfiguration;
34
use crate::pci::pci_configuration::PciBridgeSubclass;
35
use crate::pci::pci_configuration::PciClassCode;
36
use crate::pci::pci_configuration::PciConfiguration;
37
use crate::pci::pci_configuration::PciHeaderType;
38
use crate::pci::pci_configuration::HEADER_TYPE_MULTIFUNCTION_MASK;
39
use crate::pci::pci_configuration::HEADER_TYPE_REG;
40
use crate::pci::pci_configuration::HEADER_TYPE_REG_OFFSET;
41
use crate::pci::pci_device::Error;
42
use crate::pci::pci_device::PciBus;
43
use crate::pci::pci_device::PciDevice;
44
use crate::pci::PciAddress;
45
use crate::pci::PciBarIndex;
46
use crate::pci::PCI_VENDOR_ID_INTEL;
47
use crate::Bus;
48
use crate::BusAccessInfo;
49
use crate::BusDevice;
50
use crate::BusType;
51
use crate::Suspendable;
52
53
// A PciDevice that holds the root hub's configuration.
54
struct PciRootConfiguration {
55
config: PciConfiguration,
56
}
57
58
impl PciDevice for PciRootConfiguration {
59
fn debug_label(&self) -> String {
60
"pci root device".to_owned()
61
}
62
fn allocate_address(&mut self, _resources: &mut SystemAllocator) -> Result<PciAddress, Error> {
63
// PCI root fixed address.
64
Ok(PciAddress {
65
bus: 0,
66
dev: 0,
67
func: 0,
68
})
69
}
70
fn keep_rds(&self) -> Vec<RawDescriptor> {
71
Vec::new()
72
}
73
fn read_config_register(&self, reg_idx: usize) -> u32 {
74
self.config.read_reg(reg_idx)
75
}
76
77
fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
78
self.config.write_reg(reg_idx, offset, data);
79
}
80
81
fn setup_pci_config_mapping(
82
&mut self,
83
shmem: &SharedMemory,
84
base: usize,
85
len: usize,
86
) -> Result<bool, Error> {
87
self.config
88
.setup_mapping(shmem, base, len)
89
.map(|_| true)
90
.map_err(Error::MmioSetup)
91
}
92
93
fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {}
94
95
fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {}
96
97
fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
98
self.config.get_bar_configuration(bar_num)
99
}
100
}
101
102
impl Suspendable for PciRootConfiguration {
103
// no thread to sleep, no change required.
104
fn sleep(&mut self) -> anyhow::Result<()> {
105
Ok(())
106
}
107
108
fn wake(&mut self) -> anyhow::Result<()> {
109
Ok(())
110
}
111
112
fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
113
self.config
114
.snapshot()
115
.with_context(|| format!("failed to serialize {}", PciDevice::debug_label(self)))
116
}
117
118
fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
119
self.config
120
.restore(data)
121
.context("failed to deserialize PciRootConfiguration")
122
}
123
}
124
125
// Command send to pci root worker thread to add/remove device from pci root
126
pub enum PciRootCommand {
127
Add(PciAddress, Arc<Mutex<dyn BusDevice>>),
128
AddBridge(Arc<Mutex<PciBus>>),
129
Remove(PciAddress),
130
Kill,
131
}
132
133
#[derive(Serialize)]
134
struct PciRootMmioState {
135
/// Contains pages mapped read-only into the guest's MMIO space corresponding to
136
/// the PCI configuration space. Keys are the offset in number of pages from the
137
/// start of MMIO space. If a particular value is None, then at least one
138
/// attached device on that page does not support read-only mapped MMIO.
139
#[serde(skip_serializing)]
140
mappings: BTreeMap<u32, Option<(SharedMemory, MemoryMapping)>>,
141
/// Base address of the PCI configuration space's MMIO region.
142
base: GuestAddress,
143
/// Number of bits in the address space of a particular function's MMIO space.
144
register_bit_num: usize,
145
}
146
147
/// Emulates the PCI Root bridge.
148
#[allow(dead_code)] // TODO(b/174705596): remove once mmio_bus and io_bus are used
149
pub struct PciRoot {
150
/// Memory (MMIO) bus.
151
mmio_bus: Weak<Bus>,
152
/// IO bus (x86 only - for non-x86 platforms, this is just an empty Bus).
153
io_bus: Weak<Bus>,
154
/// Root pci bus (bus 0)
155
root_bus: Arc<Mutex<PciBus>>,
156
/// Bus configuration for the root device.
157
root_configuration: PciRootConfiguration,
158
/// Devices attached to this bridge.
159
devices: BTreeMap<PciAddress, Arc<Mutex<dyn BusDevice>>>,
160
/// pcie enhanced configuration access mmio base
161
pcie_cfg_mmio: Option<u64>,
162
pci_mmio_state: PciRootMmioState,
163
}
164
165
const PCI_DEVICE_ID_INTEL_82441: u16 = 0x1237;
166
const PCIE_XBAR_BASE_ADDR: usize = 24;
167
168
/// Used to serialize relevant information to PciRoot
169
#[derive(Serialize, Deserialize)]
170
struct PciRootSerializable {
171
root_configuration: AnySnapshot,
172
pcie_cfg_mmio: Option<u64>,
173
}
174
175
impl PciRoot {
176
/// Create an empty PCI root bus.
177
pub fn new(
178
vm: &mut impl Vm,
179
mmio_bus: Weak<Bus>,
180
mmio_base: GuestAddress,
181
mmio_register_bit_num: usize,
182
io_bus: Weak<Bus>,
183
root_bus: Arc<Mutex<PciBus>>,
184
) -> anyhow::Result<Self> {
185
// mmio_mappings's implementation assumes each device's mmio registers
186
// can fit on a single page. Always true given existing specs.
187
assert!(base::pagesize() >= (1 << mmio_register_bit_num));
188
let mut root =
189
Self::create_for_test(mmio_bus, mmio_base, mmio_register_bit_num, io_bus, root_bus);
190
root.pci_mmio_state
191
.setup_mapping(
192
&PciAddress::new(0, 0, 0, 0).unwrap(),
193
&mut root.root_configuration,
194
vm,
195
)
196
.context("failed to set up root configuration mapping")?;
197
Ok(root)
198
}
199
200
fn create_for_test(
201
mmio_bus: Weak<Bus>,
202
mmio_base: GuestAddress,
203
mmio_register_bit_num: usize,
204
io_bus: Weak<Bus>,
205
root_bus: Arc<Mutex<PciBus>>,
206
) -> Self {
207
PciRoot {
208
mmio_bus,
209
io_bus,
210
root_bus,
211
root_configuration: PciRootConfiguration {
212
config: PciConfiguration::new(
213
PCI_VENDOR_ID_INTEL,
214
PCI_DEVICE_ID_INTEL_82441,
215
PciClassCode::BridgeDevice,
216
&PciBridgeSubclass::HostBridge,
217
None,
218
PciHeaderType::Device,
219
0,
220
0,
221
0,
222
),
223
},
224
devices: BTreeMap::new(),
225
pcie_cfg_mmio: None,
226
pci_mmio_state: PciRootMmioState {
227
mappings: BTreeMap::new(),
228
base: mmio_base,
229
register_bit_num: mmio_register_bit_num,
230
},
231
}
232
}
233
234
/// Get the root pci bus
235
pub fn get_root_bus(&self) -> Arc<Mutex<PciBus>> {
236
self.root_bus.clone()
237
}
238
239
/// Get the ACPI path to a PCI device
240
pub fn acpi_path(&self, address: &PciAddress) -> Option<String> {
241
if let Some(device) = self.devices.get(address) {
242
let path = self.root_bus.lock().path_to(address.bus);
243
if path.is_empty() {
244
None
245
} else {
246
Some(format!(
247
"_SB_.{}.{}",
248
path.iter()
249
.map(|x| format!("PC{x:02X}"))
250
.collect::<Vec<String>>()
251
.join("."),
252
match device.lock().is_bridge() {
253
Some(bus_no) => format!("PC{bus_no:02X}"),
254
None => format!("PE{:02X}", address.devfn()),
255
}
256
))
257
}
258
} else {
259
None
260
}
261
}
262
263
/// enable pcie enhanced configuration access and set base mmio
264
pub fn enable_pcie_cfg_mmio(&mut self, pcie_cfg_mmio: u64) {
265
self.pcie_cfg_mmio = Some(pcie_cfg_mmio);
266
// Update the config space registers that depend on pcie_cfg_mmio.
267
self.root_configuration.config.set_reg(
268
PCIE_XBAR_BASE_ADDR,
269
self.pcie_cfg_mmio.unwrap() as u32 | 0x1,
270
0xffff_ffff,
271
);
272
self.root_configuration.config.set_reg(
273
PCIE_XBAR_BASE_ADDR + 1,
274
(self.pcie_cfg_mmio.unwrap() >> 32) as u32,
275
0xffff_ffff,
276
);
277
}
278
279
/// Add a `device` to this root PCI bus.
280
pub fn add_device<T>(
281
&mut self,
282
address: PciAddress,
283
device: Arc<Mutex<dyn BusDevice>>,
284
mapper: &mut T,
285
) -> Result<(), Error>
286
where
287
T: PciMmioMapper,
288
{
289
// Ignore attempt to replace PCI Root host bridge.
290
if !address.is_root() {
291
self.pci_mmio_state
292
.setup_mapping(&address, device.lock().deref_mut(), mapper)
293
.map_err(Error::MmioSetup)?;
294
self.devices.insert(address, device);
295
self.sync_multifunction_bit_to_mmio_mappings(&address, true);
296
}
297
298
self.root_bus.lock().add_child_device(address)
299
}
300
301
fn sync_multifunction_bit_to_mmio_mappings(&mut self, address: &PciAddress, on_add: bool) {
302
let num_mfd = self.num_multifunction_device(address);
303
let target_range = if (num_mfd == 1 && on_add) || (num_mfd == 0 && !on_add) {
304
// If we added the first mfd or removed the last mfd, update all functions' bits
305
0..8
306
} else if on_add && num_mfd > 0 {
307
// If we added a new function, set its bit if necessary
308
address.func..(address.func + 1)
309
} else {
310
return;
311
};
312
for i in target_range {
313
self.pci_mmio_state.set_mfd_bit(
314
&PciAddress {
315
func: i,
316
..*address
317
},
318
num_mfd > 0,
319
);
320
}
321
}
322
323
pub fn add_bridge(&mut self, bridge_bus: Arc<Mutex<PciBus>>) -> Result<(), Error> {
324
self.root_bus.lock().add_child_bus(bridge_bus)
325
}
326
327
pub fn remove_device(&mut self, address: PciAddress) {
328
if let Some(d) = self.devices.remove(&address) {
329
for (range, bus_type) in d.lock().get_ranges() {
330
let bus_ptr = if bus_type == BusType::Mmio {
331
match self.mmio_bus.upgrade() {
332
Some(m) => m,
333
None => continue,
334
}
335
} else {
336
match self.io_bus.upgrade() {
337
Some(i) => i,
338
None => continue,
339
}
340
};
341
let _ = bus_ptr.remove(range.base, range.len);
342
}
343
// Remove the pci bus if this device is a pci bridge.
344
if let Some(bus_no) = d.lock().is_bridge() {
345
let _ = self.root_bus.lock().remove_child_bus(bus_no);
346
}
347
d.lock().destroy_device();
348
let _ = self.root_bus.lock().remove_child_device(address);
349
}
350
self.sync_multifunction_bit_to_mmio_mappings(&address, false);
351
}
352
353
pub fn config_space_read(&self, address: PciAddress, register: usize) -> u32 {
354
if address.is_root() {
355
if register == PCIE_XBAR_BASE_ADDR && self.pcie_cfg_mmio.is_some() {
356
let pcie_mmio = self.pcie_cfg_mmio.unwrap() as u32;
357
pcie_mmio | 0x1
358
} else if register == (PCIE_XBAR_BASE_ADDR + 1) && self.pcie_cfg_mmio.is_some() {
359
(self.pcie_cfg_mmio.unwrap() >> 32) as u32
360
} else {
361
self.root_configuration.config_register_read(register)
362
}
363
} else {
364
let mut data = self
365
.devices
366
.get(&address)
367
.map_or(0xffff_ffff, |d| d.lock().config_register_read(register));
368
369
if register == HEADER_TYPE_REG {
370
// Set multifunction bit in header type if there are devices at non-zero functions
371
// in this slot.
372
if self.num_multifunction_device(&address) != 0 {
373
data |= (HEADER_TYPE_MULTIFUNCTION_MASK as u32) << (HEADER_TYPE_REG_OFFSET * 8);
374
}
375
}
376
377
data
378
}
379
}
380
381
pub fn config_space_write(
382
&mut self,
383
address: PciAddress,
384
register: usize,
385
offset: u64,
386
data: &[u8],
387
) {
388
if offset as usize + data.len() > 4 {
389
return;
390
}
391
if address.is_root() {
392
self.root_configuration
393
.config_register_write(register, offset, data);
394
} else if let Some(d) = self.devices.get(&address) {
395
let res = d.lock().config_register_write(register, offset, data);
396
397
if !res.mmio_add.is_empty() || !res.mmio_remove.is_empty() {
398
let mmio_bus = match self.mmio_bus.upgrade() {
399
Some(m) => m,
400
None => return,
401
};
402
for range in &res.mmio_remove {
403
let _ = mmio_bus.remove(range.base, range.len);
404
}
405
for range in &res.mmio_add {
406
let _ = mmio_bus.insert(d.clone(), range.base, range.len);
407
}
408
}
409
410
if !res.io_add.is_empty() || !res.io_remove.is_empty() {
411
let io_bus = match self.io_bus.upgrade() {
412
Some(i) => i,
413
None => return,
414
};
415
for range in &res.io_remove {
416
let _ = io_bus.remove(range.base, range.len);
417
}
418
for range in &res.io_add {
419
let _ = io_bus.insert(d.clone(), range.base, range.len);
420
}
421
}
422
423
for remove_pci_device in res.removed_pci_devices.iter() {
424
self.remove_device(*remove_pci_device);
425
}
426
}
427
}
428
429
pub fn virtual_config_space_read(&self, address: PciAddress, register: usize) -> u32 {
430
if address.is_root() {
431
0u32
432
} else {
433
self.devices
434
.get(&address)
435
.map_or(0u32, |d| d.lock().virtual_config_register_read(register))
436
}
437
}
438
439
pub fn virtual_config_space_write(&mut self, address: PciAddress, register: usize, value: u32) {
440
if !address.is_root() {
441
if let Some(d) = self.devices.get(&address) {
442
d.lock().virtual_config_register_write(register, value);
443
}
444
}
445
}
446
447
pub fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
448
AnySnapshot::to_any(PciRootSerializable {
449
root_configuration: self
450
.root_configuration
451
.snapshot()
452
.context("failed to serialize PciRoot.root_configuration")?,
453
pcie_cfg_mmio: self.pcie_cfg_mmio,
454
})
455
.context("failed to serialize PciRoot")
456
}
457
458
pub fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
459
let deser: PciRootSerializable =
460
AnySnapshot::from_any(data).context("failed to deserialize PciRoot")?;
461
self.root_configuration.restore(deser.root_configuration)?;
462
self.pcie_cfg_mmio = deser.pcie_cfg_mmio;
463
Ok(())
464
}
465
466
fn num_multifunction_device(&self, address: &PciAddress) -> usize {
467
self.devices
468
.range((
469
Included(&PciAddress {
470
func: 1,
471
..*address
472
}),
473
Included(&PciAddress {
474
func: 7,
475
..*address
476
}),
477
))
478
.count()
479
}
480
}
481
482
impl PciRootMmioState {
483
fn setup_mapping<T>(
484
&mut self,
485
address: &PciAddress,
486
device: &mut dyn BusDevice,
487
mapper: &mut T,
488
) -> anyhow::Result<()>
489
where
490
T: PciMmioMapper,
491
{
492
// The PCI spec requires that config writes are non-posted. This requires uncached mappings
493
// in the guest. The cache maintenance story for riscv is unclear, so that is not
494
// implemented.
495
if cfg!(not(any(target_arch = "x86_64", target_arch = "aarch64"))) {
496
return Ok(());
497
}
498
499
// The optional optimizations below require the hypervisor to support read-only memory
500
// regions.
501
if !mapper.supports_readonly_mapping() {
502
return Ok(());
503
}
504
505
let pagesize = base::pagesize();
506
let offset = address.to_config_address(0, self.register_bit_num);
507
let mmio_mapping_num = offset / pagesize as u32;
508
let (shmem, new_entry) = match self.mappings.entry(mmio_mapping_num) {
509
BTreeMapEntry::Vacant(e) => {
510
let shmem = SharedMemory::new(
511
format!("{mmio_mapping_num:04x}_pci_cfg_mapping"),
512
pagesize as u64,
513
)
514
.context("failed to create shmem")?;
515
let mapping = MemoryMappingBuilder::new(pagesize)
516
.from_shared_memory(&shmem)
517
.protection(Protection::read_write())
518
.build()
519
.context("failed to map shmem")?;
520
let (shmem, _) = e.insert(Some((shmem, mapping))).as_ref().unwrap();
521
(shmem, true)
522
}
523
BTreeMapEntry::Occupied(e) => {
524
let Some((shmem, _)) = e.into_mut() else {
525
// Another device sharing the page didn't support mapped mmio. Oh
526
// well, we'll just have to fall back to vm-exit handling.
527
return Ok(());
528
};
529
(&*shmem, false)
530
}
531
};
532
533
if device.init_pci_config_mapping(
534
shmem,
535
offset as usize % pagesize,
536
1 << self.register_bit_num,
537
) {
538
if new_entry {
539
let mmio_address = self
540
.base
541
.unchecked_add(mmio_mapping_num as u64 * pagesize as u64);
542
match mapper.add_mapping(mmio_address, shmem) {
543
// We never unmap the mapping, so we don't need the id
544
Ok(_) => (),
545
// If this fails, mmio handling via vm-exit will work fine. Devices
546
// will be doing some pointless work keeping the unused mapping up
547
// to date, but addressing that isn't worth the implementation cost.
548
Err(e) => error!("Failed to map mmio page; {:?}", e),
549
}
550
}
551
} else {
552
self.mappings.insert(mmio_mapping_num, None);
553
}
554
Ok(())
555
}
556
557
fn set_mfd_bit(&mut self, address: &PciAddress, is_mfd: bool) {
558
let pagesize = base::pagesize();
559
let offset = address.to_config_address(0, self.register_bit_num);
560
let mapping_num = offset / pagesize as u32;
561
if let Some(Some((_, mapping))) = self.mappings.get_mut(&mapping_num) {
562
let mapping_base = offset as usize % pagesize;
563
let reg_offset = mapping_base + (HEADER_TYPE_REG * 4) + HEADER_TYPE_REG_OFFSET;
564
565
let mut val = mapping.read_obj::<u8>(reg_offset).expect("memcpy failed");
566
val = if is_mfd {
567
val | HEADER_TYPE_MULTIFUNCTION_MASK
568
} else {
569
val & !HEADER_TYPE_MULTIFUNCTION_MASK
570
};
571
mapping
572
.write_obj_volatile(val, reg_offset)
573
.expect("memcpy failed");
574
if let Err(err) = mapping.flush_region(reg_offset, 4) {
575
error!("failed to flush write to mfd bit: {}", err);
576
}
577
}
578
}
579
}
580
581
pub trait PciMmioMapper {
582
fn supports_readonly_mapping(&self) -> bool;
583
fn add_mapping(&mut self, addr: GuestAddress, shmem: &SharedMemory) -> anyhow::Result<u32>;
584
}
585
586
impl<T: Vm> PciMmioMapper for T {
587
fn supports_readonly_mapping(&self) -> bool {
588
self.check_capability(hypervisor::VmCap::ReadOnlyMemoryRegion)
589
}
590
591
fn add_mapping(&mut self, addr: GuestAddress, shmem: &SharedMemory) -> anyhow::Result<u32> {
592
let mapping = MemoryMappingBuilder::new(base::pagesize())
593
.from_shared_memory(shmem)
594
.protection(Protection::read())
595
.build()
596
.context("failed to map shmem")?;
597
self.add_memory_region(
598
addr,
599
Box::new(mapping),
600
true,
601
false,
602
MemCacheType::CacheCoherent,
603
)
604
.context("failed to create vm mapping")
605
}
606
}
607
608
/// Emulates PCI configuration access mechanism #1 (I/O ports 0xcf8 and 0xcfc).
609
pub struct PciConfigIo {
610
/// PCI root bridge.
611
pci_root: Arc<Mutex<PciRoot>>,
612
/// Current address to read/write from (0xcf8 register, litte endian).
613
config_address: u32,
614
/// Whether or not to actually function.
615
break_linux_pci_config_io: bool,
616
/// Tube to signal that the guest requested reset via writing to 0xcf9 register.
617
reset_evt_wrtube: SendTube,
618
}
619
620
#[derive(Serialize, Deserialize)]
621
struct PciConfigIoSerializable {
622
pci_root: AnySnapshot,
623
config_address: u32,
624
}
625
626
impl PciConfigIo {
627
const REGISTER_BITS_NUM: usize = 8;
628
629
pub fn new(
630
pci_root: Arc<Mutex<PciRoot>>,
631
break_linux_pci_config_io: bool,
632
reset_evt_wrtube: SendTube,
633
) -> Self {
634
PciConfigIo {
635
pci_root,
636
config_address: 0,
637
break_linux_pci_config_io,
638
reset_evt_wrtube,
639
}
640
}
641
642
fn config_space_read(&self) -> u32 {
643
let enabled = (self.config_address & 0x8000_0000) != 0;
644
if !enabled {
645
return 0xffff_ffff;
646
}
647
648
let (address, register) =
649
PciAddress::from_config_address(self.config_address, Self::REGISTER_BITS_NUM);
650
self.pci_root.lock().config_space_read(address, register)
651
}
652
653
fn config_space_write(&mut self, offset: u64, data: &[u8]) {
654
let enabled = (self.config_address & 0x8000_0000) != 0;
655
if !enabled {
656
return;
657
}
658
659
let (address, register) =
660
PciAddress::from_config_address(self.config_address, Self::REGISTER_BITS_NUM);
661
self.pci_root
662
.lock()
663
.config_space_write(address, register, offset, data)
664
}
665
666
fn set_config_address(&mut self, offset: u64, data: &[u8]) {
667
if offset as usize + data.len() > 4 {
668
return;
669
}
670
let (mask, value): (u32, u32) = match data.len() {
671
1 => (
672
0x0000_00ff << (offset * 8),
673
(data[0] as u32) << (offset * 8),
674
),
675
2 => (
676
0x0000_ffff << (offset * 8),
677
u32::from(u16::from_le_bytes(data.try_into().unwrap())) << (offset * 8),
678
),
679
4 => (0xffff_ffff, u32::from_le_bytes(data.try_into().unwrap())),
680
_ => return,
681
};
682
self.config_address = (self.config_address & !mask) | value;
683
}
684
}
685
686
const PCI_RESET_CPU_BIT: u8 = 1 << 2;
687
688
impl BusDevice for PciConfigIo {
689
fn debug_label(&self) -> String {
690
"pci config io-port".to_string()
691
}
692
693
fn device_id(&self) -> DeviceId {
694
PciId::new(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441).into()
695
}
696
697
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
698
if self.break_linux_pci_config_io {
699
for d in data {
700
*d = 0xff;
701
}
702
return;
703
}
704
// `offset` is relative to 0xcf8
705
let value = match info.offset {
706
0..=3 => self.config_address,
707
4..=7 => self.config_space_read(),
708
_ => 0xffff_ffff,
709
};
710
711
// Only allow reads to the register boundary.
712
let start = info.offset as usize % 4;
713
let end = start + data.len();
714
if end <= 4 {
715
for i in start..end {
716
data[i - start] = (value >> (i * 8)) as u8;
717
}
718
} else {
719
for d in data {
720
*d = 0xff;
721
}
722
}
723
}
724
725
fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
726
// `offset` is relative to 0xcf8
727
match info.offset {
728
_o @ 1 if data.len() == 1 && data[0] & PCI_RESET_CPU_BIT != 0 => {
729
if let Err(e) = self
730
.reset_evt_wrtube
731
.send::<VmEventType>(&VmEventType::Reset)
732
{
733
error!("failed to trigger PCI 0xcf9 reset event: {}", e);
734
}
735
}
736
o @ 0..=3 => self.set_config_address(o, data),
737
o @ 4..=7 => self.config_space_write(o - 4, data),
738
_ => (),
739
};
740
}
741
}
742
743
impl Suspendable for PciConfigIo {
744
// no thread to sleep, no change required.
745
fn sleep(&mut self) -> anyhow::Result<()> {
746
Ok(())
747
}
748
749
fn wake(&mut self) -> anyhow::Result<()> {
750
Ok(())
751
}
752
753
fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
754
AnySnapshot::to_any(PciConfigIoSerializable {
755
pci_root: self
756
.pci_root
757
.lock()
758
.snapshot()
759
.context("failed to snapshot root")?,
760
config_address: self.config_address,
761
})
762
.with_context(|| format!("failed to serialize {}", self.debug_label()))
763
}
764
765
fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
766
let mut root = self.pci_root.lock();
767
let deser: PciConfigIoSerializable = AnySnapshot::from_any(data)
768
.with_context(|| format!("failed to deserialize {}", self.debug_label()))?;
769
root.restore(deser.pci_root)?;
770
self.config_address = deser.config_address;
771
Ok(())
772
}
773
}
774
775
/// Emulates PCI memory-mapped configuration access mechanism.
776
pub struct PciConfigMmio {
777
/// PCI root bridge.
778
pci_root: Arc<Mutex<PciRoot>>,
779
/// Register bit number in config address.
780
register_bit_num: usize,
781
}
782
783
#[derive(Serialize, Deserialize)]
784
struct PciConfigMmioSerializable {
785
pci_root: AnySnapshot,
786
register_bit_num: usize,
787
}
788
789
impl PciConfigMmio {
790
pub fn new(pci_root: Arc<Mutex<PciRoot>>, register_bit_num: usize) -> Self {
791
PciConfigMmio {
792
pci_root,
793
register_bit_num,
794
}
795
}
796
797
fn config_space_read(&self, config_address: u32) -> u32 {
798
let (address, register) =
799
PciAddress::from_config_address(config_address, self.register_bit_num);
800
self.pci_root.lock().config_space_read(address, register)
801
}
802
803
fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
804
let (address, register) =
805
PciAddress::from_config_address(config_address, self.register_bit_num);
806
self.pci_root
807
.lock()
808
.config_space_write(address, register, offset, data)
809
}
810
}
811
812
impl BusDevice for PciConfigMmio {
813
fn debug_label(&self) -> String {
814
"pci config mmio".to_owned()
815
}
816
817
fn device_id(&self) -> DeviceId {
818
PciId::new(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441).into()
819
}
820
821
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
822
// Only allow reads to the register boundary.
823
let start = info.offset as usize % 4;
824
let end = start + data.len();
825
if end > 4 || info.offset > u32::MAX as u64 {
826
for d in data {
827
*d = 0xff;
828
}
829
return;
830
}
831
832
let value = self.config_space_read(info.offset as u32);
833
for i in start..end {
834
data[i - start] = (value >> (i * 8)) as u8;
835
}
836
}
837
838
fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
839
if info.offset > u32::MAX as u64 {
840
return;
841
}
842
self.config_space_write(info.offset as u32, info.offset % 4, data)
843
}
844
}
845
846
impl Suspendable for PciConfigMmio {
847
// no thread to sleep, no change required.
848
fn sleep(&mut self) -> anyhow::Result<()> {
849
Ok(())
850
}
851
852
fn wake(&mut self) -> anyhow::Result<()> {
853
Ok(())
854
}
855
856
fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
857
AnySnapshot::to_any(PciConfigMmioSerializable {
858
pci_root: self
859
.pci_root
860
.lock()
861
.snapshot()
862
.context("failed to snapshot root")?,
863
register_bit_num: self.register_bit_num,
864
})
865
.with_context(|| format!("failed to serialize {}", self.debug_label()))
866
}
867
868
fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
869
let mut root = self.pci_root.lock();
870
let deser: PciConfigMmioSerializable = AnySnapshot::from_any(data)
871
.with_context(|| format!("failed to deserialize {}", self.debug_label()))?;
872
root.restore(deser.pci_root)?;
873
self.register_bit_num = deser.register_bit_num;
874
Ok(())
875
}
876
}
877
878
/// Inspired by PCI configuration space, CrosVM provides 2048 dword virtual registers (8KiB in
879
/// total) for each PCI device. The guest can use these registers to exchange device-specific
880
/// information with crosvm. The first 4kB is trapped by crosvm and crosvm supplies these
881
/// register's emulation. The second 4KB is mapped into guest directly as shared memory, so
882
/// when guest access this 4KB, vm exit doesn't happen.
883
/// All these virtual registers from all PCI devices locate in a contiguous memory region.
884
/// The base address of this memory region is provided by an IntObj named VCFG in the ACPI DSDT.
885
/// Bit 12 is used to select the first trapped page or the second directly mapped page
886
/// The offset of each register is calculated in the same way as PCIe ECAM;
887
/// i.e. offset = (bus << 21) | (device << 16) | (function << 13) | (page_select << 12) |
888
/// (register_index << 2)
889
pub struct PciVirtualConfigMmio {
890
/// PCI root bridge.
891
pci_root: Arc<Mutex<PciRoot>>,
892
/// Register bit number in config address.
893
register_bit_num: usize,
894
}
895
896
#[derive(Serialize, Deserialize)]
897
struct PciVirtualConfigMmioSerializable {
898
pci_root: AnySnapshot,
899
register_bit_num: usize,
900
}
901
902
impl PciVirtualConfigMmio {
903
pub fn new(pci_root: Arc<Mutex<PciRoot>>, register_bit_num: usize) -> Self {
904
PciVirtualConfigMmio {
905
pci_root,
906
register_bit_num,
907
}
908
}
909
}
910
911
impl BusDevice for PciVirtualConfigMmio {
912
fn debug_label(&self) -> String {
913
"pci virtual config mmio".to_owned()
914
}
915
916
fn device_id(&self) -> DeviceId {
917
PciId::new(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441).into()
918
}
919
920
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
921
let value = if info.offset % 4 != 0 || data.len() != 4 {
922
error!(
923
"{} unexpected read at offset = {}, len = {}",
924
self.debug_label(),
925
info.offset,
926
data.len()
927
);
928
0u32
929
} else {
930
let (address, register) =
931
PciAddress::from_config_address(info.offset as u32, self.register_bit_num);
932
self.pci_root
933
.lock()
934
.virtual_config_space_read(address, register)
935
};
936
data[0..4].copy_from_slice(&value.to_le_bytes()[..]);
937
}
938
939
fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
940
if info.offset % 4 != 0 || data.len() != 4 {
941
error!(
942
"{} unexpected write at offset = {}, len = {}",
943
self.debug_label(),
944
info.offset,
945
data.len()
946
);
947
return;
948
}
949
// Unwrap is safe as we verified length above
950
let value = u32::from_le_bytes(data.try_into().unwrap());
951
let (address, register) =
952
PciAddress::from_config_address(info.offset as u32, self.register_bit_num);
953
self.pci_root
954
.lock()
955
.virtual_config_space_write(address, register, value)
956
}
957
}
958
959
impl Suspendable for PciVirtualConfigMmio {
960
// no thread to sleep, no change required.
961
fn sleep(&mut self) -> anyhow::Result<()> {
962
Ok(())
963
}
964
965
fn wake(&mut self) -> anyhow::Result<()> {
966
Ok(())
967
}
968
969
fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
970
AnySnapshot::to_any(PciVirtualConfigMmioSerializable {
971
pci_root: self
972
.pci_root
973
.lock()
974
.snapshot()
975
.context("failed to snapshot root")?,
976
register_bit_num: self.register_bit_num,
977
})
978
.with_context(|| format!("failed to serialize {}", self.debug_label()))
979
}
980
981
fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
982
let mut root = self.pci_root.lock();
983
let deser: PciVirtualConfigMmioSerializable = AnySnapshot::from_any(data)
984
.with_context(|| format!("failed to deserialize {}", self.debug_label()))?;
985
root.restore(deser.pci_root)?;
986
self.register_bit_num = deser.register_bit_num;
987
988
Ok(())
989
}
990
}
991
992
#[cfg(test)]
993
mod tests {
994
use base::Tube;
995
996
use super::*;
997
use crate::suspendable_tests;
998
999
fn create_pci_root() -> Arc<Mutex<PciRoot>> {
1000
let io_bus = Arc::new(Bus::new(BusType::Io));
1001
let mmio_bus = Arc::new(Bus::new(BusType::Mmio));
1002
let root_bus = Arc::new(Mutex::new(PciBus::new(0, 0, false)));
1003
1004
Arc::new(Mutex::new(PciRoot::create_for_test(
1005
Arc::downgrade(&mmio_bus),
1006
GuestAddress(0),
1007
0,
1008
Arc::downgrade(&io_bus),
1009
root_bus,
1010
)))
1011
}
1012
1013
fn create_pci_io_config(pci_root: Arc<Mutex<PciRoot>>) -> PciConfigIo {
1014
let (reset_evt_wrtube, _) = Tube::directional_pair().unwrap();
1015
PciConfigIo::new(pci_root, false, reset_evt_wrtube)
1016
}
1017
1018
fn modify_pci_io_config(pci_config: &mut PciConfigIo) {
1019
pci_config.config_address += 1;
1020
}
1021
fn create_pci_mmio_config(pci_root: Arc<Mutex<PciRoot>>) -> PciConfigMmio {
1022
PciConfigMmio::new(pci_root, 0)
1023
}
1024
1025
fn modify_pci_mmio_config(pci_config: &mut PciConfigMmio) {
1026
pci_config.register_bit_num += 1;
1027
}
1028
1029
fn create_pci_virtual_config_mmio(pci_root: Arc<Mutex<PciRoot>>) -> PciVirtualConfigMmio {
1030
PciVirtualConfigMmio::new(pci_root, 0)
1031
}
1032
1033
fn modify_pci_virtual_config_mmio(pci_config: &mut PciVirtualConfigMmio) {
1034
pci_config.register_bit_num += 1;
1035
}
1036
1037
suspendable_tests!(
1038
pci_io_config,
1039
create_pci_io_config(create_pci_root()),
1040
modify_pci_io_config
1041
);
1042
suspendable_tests!(
1043
pcie_mmio_config,
1044
create_pci_mmio_config(create_pci_root()),
1045
modify_pci_mmio_config
1046
);
1047
suspendable_tests!(
1048
pci_virtual_config_mmio,
1049
create_pci_virtual_config_mmio(create_pci_root()),
1050
modify_pci_virtual_config_mmio
1051
);
1052
1053
#[test]
1054
fn pci_set_config_address_word() {
1055
let mut pci_io_config = create_pci_io_config(create_pci_root());
1056
1057
// Set the full 32-bit config_address to a known value (0x11223344).
1058
pci_io_config.write(
1059
BusAccessInfo {
1060
offset: 0,
1061
address: 0xCF8,
1062
id: 0,
1063
},
1064
&[0x44, 0x33, 0x22, 0x11],
1065
);
1066
1067
// Overwrite the high 16 bits of config_address with 0x55AA (test for b/274366589).
1068
pci_io_config.write(
1069
BusAccessInfo {
1070
offset: 2,
1071
address: 0xCFA,
1072
id: 0,
1073
},
1074
&[0xAA, 0x55],
1075
);
1076
1077
// Verify config_address has the expected value (0x55AA3344).
1078
let mut config_address = [0u8; 4];
1079
pci_io_config.read(
1080
BusAccessInfo {
1081
offset: 0,
1082
address: 0xCF8,
1083
id: 0,
1084
},
1085
&mut config_address,
1086
);
1087
assert_eq!(config_address, [0x44, 0x33, 0xAA, 0x55]);
1088
}
1089
}
1090
1091