1use std::collections::HashMap;
9use std::fmt::Debug;
10use std::ops::DerefMut;
11use std::sync::{Arc, Barrier, Mutex};
12
13use byteorder::{ByteOrder, LittleEndian};
14use pci::{PciBridgeSubclass, PciClassCode};
15
16use crate::logger::error;
17use crate::pci::configuration::PciConfiguration;
18use crate::pci::{DeviceRelocation, PciDevice};
19use crate::utils::u64_to_usize;
20use crate::vstate::bus::BusDevice;
21
22#[derive(Debug, thiserror::Error, displaydoc::Display)]
24pub enum PciRootError {
25 NoPciDeviceSlotAvailable,
27}
28
29const VENDOR_ID_INTEL: u16 = 0x8086;
30const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
31const NUM_DEVICE_IDS: usize = 32;
32
33#[derive(Debug)]
34pub struct PciRoot {
36 config: PciConfiguration,
38}
39
40impl PciRoot {
41 pub fn new(config: Option<PciConfiguration>) -> Self {
43 if let Some(config) = config {
44 PciRoot { config }
45 } else {
46 PciRoot {
47 config: PciConfiguration::new_type0(
48 VENDOR_ID_INTEL,
49 DEVICE_ID_INTEL_VIRT_PCIE_HOST,
50 0,
51 PciClassCode::BridgeDevice,
52 &PciBridgeSubclass::HostBridge,
53 0,
54 0,
55 None,
56 ),
57 }
58 }
59 }
60}
61
62impl BusDevice for PciRoot {}
63
64impl PciDevice for PciRoot {
65 fn write_config_register(
66 &mut self,
67 reg_idx: usize,
68 offset: u64,
69 data: &[u8],
70 ) -> Option<Arc<Barrier>> {
71 self.config.write_config_register(reg_idx, offset, data);
72 None
73 }
74
75 fn read_config_register(&mut self, reg_idx: usize) -> u32 {
76 self.config.read_reg(reg_idx)
77 }
78}
79
80pub struct PciBus {
82 pub devices: HashMap<u32, Arc<Mutex<dyn PciDevice>>>,
85 vm: Arc<dyn DeviceRelocation>,
86 device_ids: Vec<bool>,
87}
88
89impl Debug for PciBus {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 f.debug_struct("Root Firecracker PCI Bus")
92 .field("device_ids", &self.device_ids)
93 .finish()
94 }
95}
96
97impl PciBus {
98 pub fn new(pci_root: PciRoot, vm: Arc<dyn DeviceRelocation>) -> Self {
100 let mut devices: HashMap<u32, Arc<Mutex<dyn PciDevice>>> = HashMap::new();
101 let mut device_ids: Vec<bool> = vec![false; NUM_DEVICE_IDS];
102
103 devices.insert(0, Arc::new(Mutex::new(pci_root)));
104 device_ids[0] = true;
105
106 PciBus {
107 devices,
108 vm,
109 device_ids,
110 }
111 }
112
113 pub fn add_device(&mut self, device_id: u32, device: Arc<Mutex<dyn PciDevice>>) {
115 self.devices.insert(device_id, device);
116 }
117
118 pub fn next_device_id(&mut self) -> Result<u32, PciRootError> {
120 for (idx, device_id) in self.device_ids.iter_mut().enumerate() {
121 if !(*device_id) {
122 *device_id = true;
123 return Ok(idx.try_into().unwrap());
124 }
125 }
126
127 Err(PciRootError::NoPciDeviceSlotAvailable)
128 }
129}
130
131#[cfg(target_arch = "x86_64")]
132pub const PCI_CONFIG_IO_PORT: u64 = 0xcf8;
134#[cfg(target_arch = "x86_64")]
135pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8;
138
139#[derive(Debug)]
141pub struct PciConfigIo {
142 config_address: u32,
144 pci_bus: Arc<Mutex<PciBus>>,
145}
146
147impl PciConfigIo {
148 pub fn new(pci_bus: Arc<Mutex<PciBus>>) -> Self {
150 PciConfigIo {
151 config_address: 0,
152 pci_bus,
153 }
154 }
155
156 pub fn config_space_read(&self) -> u32 {
158 let enabled = (self.config_address & 0x8000_0000) != 0;
159 if !enabled {
160 return 0xffff_ffff;
161 }
162
163 let (bus, device, function, register) =
164 parse_io_config_address(self.config_address & !0x8000_0000);
165
166 if bus != 0 {
168 return 0xffff_ffff;
169 }
170
171 if function > 0 {
173 return 0xffff_ffff;
174 }
175
176 self.pci_bus
180 .as_ref()
181 .lock()
182 .unwrap()
183 .devices
184 .get(&(device.try_into().unwrap()))
185 .map_or(0xffff_ffff, |d| {
186 d.lock().unwrap().read_config_register(register)
187 })
188 }
189
190 pub fn config_space_write(&mut self, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
192 if u64_to_usize(offset) + data.len() > 4 {
193 return None;
194 }
195
196 let enabled = (self.config_address & 0x8000_0000) != 0;
197 if !enabled {
198 return None;
199 }
200
201 let (bus, device, function, register) =
202 parse_io_config_address(self.config_address & !0x8000_0000);
203
204 if bus != 0 {
206 return None;
207 }
208
209 if function > 0 {
211 return None;
212 }
213
214 let pci_bus = self.pci_bus.as_ref().lock().unwrap();
218 if let Some(d) = pci_bus.devices.get(&(device.try_into().unwrap())) {
219 let mut device = d.lock().unwrap();
220
221 if let Some(params) = device.detect_bar_reprogramming(register, data)
224 && let Err(e) = pci_bus.vm.move_bar(
225 params.old_base,
226 params.new_base,
227 params.len,
228 device.deref_mut(),
229 )
230 {
231 error!(
232 "Failed moving device BAR: {}: 0x{:x}->0x{:x}(0x{:x})",
233 e, params.old_base, params.new_base, params.len
234 );
235 }
236
237 device.write_config_register(register, offset, data)
239 } else {
240 None
241 }
242 }
243
244 fn set_config_address(&mut self, offset: u64, data: &[u8]) {
245 if u64_to_usize(offset) + data.len() > 4 {
246 return;
247 }
248 let (mask, value): (u32, u32) = match data.len() {
249 1 => (
250 0x0000_00ff << (offset * 8),
251 u32::from(data[0]) << (offset * 8),
252 ),
253 2 => (
254 0x0000_ffff << (offset * 8),
255 ((u32::from(data[1]) << 8) | u32::from(data[0])) << (offset * 8),
256 ),
257 4 => (0xffff_ffff, LittleEndian::read_u32(data)),
258 _ => return,
259 };
260 self.config_address = (self.config_address & !mask) | value;
261 }
262}
263
264impl BusDevice for PciConfigIo {
265 fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
266 let start = u64_to_usize(offset) % 4;
268 let end = start + data.len();
269 if end > 4 {
270 for d in data.iter_mut() {
271 *d = 0xff;
272 }
273 return;
274 }
275
276 let value = match offset {
278 0..=3 => self.config_address,
279 4..=7 => self.config_space_read(),
280 _ => 0xffff_ffff,
281 };
282
283 for i in start..end {
284 data[i - start] = ((value >> (i * 8)) & 0xff) as u8;
285 }
286 }
287
288 fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
289 match offset {
291 o @ 0..=3 => {
292 self.set_config_address(o, data);
293 None
294 }
295 o @ 4..=7 => self.config_space_write(o - 4, data),
296 _ => None,
297 }
298 }
299}
300
301#[derive(Debug)]
302pub struct PciConfigMmio {
304 pci_bus: Arc<Mutex<PciBus>>,
305}
306
307impl PciConfigMmio {
308 pub fn new(pci_bus: Arc<Mutex<PciBus>>) -> Self {
310 PciConfigMmio { pci_bus }
311 }
312
313 fn config_space_read(&self, config_address: u32) -> u32 {
314 let (bus, device, function, register) = parse_mmio_config_address(config_address);
315
316 if bus != 0 {
318 return 0xffff_ffff;
319 }
320
321 if function > 0 {
323 return 0xffff_ffff;
324 }
325
326 self.pci_bus
327 .lock()
328 .unwrap()
329 .devices
330 .get(&(device.try_into().unwrap()))
331 .map_or(0xffff_ffff, |d| {
332 d.lock().unwrap().read_config_register(register)
333 })
334 }
335
336 fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
337 if u64_to_usize(offset) + data.len() > 4 {
338 return;
339 }
340
341 let (bus, device, function, register) = parse_mmio_config_address(config_address);
342
343 if bus != 0 {
345 return;
346 }
347
348 if function > 0 {
350 return;
351 }
352
353 let pci_bus = self.pci_bus.lock().unwrap();
354 if let Some(d) = pci_bus.devices.get(&(device.try_into().unwrap())) {
355 let mut device = d.lock().unwrap();
356
357 if let Some(params) = device.detect_bar_reprogramming(register, data)
360 && let Err(e) = pci_bus.vm.move_bar(
361 params.old_base,
362 params.new_base,
363 params.len,
364 device.deref_mut(),
365 )
366 {
367 error!(
368 "Failed moving device BAR: {}: 0x{:x}->0x{:x}(0x{:x})",
369 e, params.old_base, params.new_base, params.len
370 );
371 }
372
373 device.write_config_register(register, offset, data);
375 }
376 }
377}
378
379impl BusDevice for PciConfigMmio {
380 fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
381 let start = u64_to_usize(offset) % 4;
383 let end = start + data.len();
384 if end > 4 || offset > u64::from(u32::MAX) {
385 for d in data {
386 *d = 0xff;
387 }
388 return;
389 }
390
391 let value = self.config_space_read(offset.try_into().unwrap());
392 for i in start..end {
393 data[i - start] = ((value >> (i * 8)) & 0xff) as u8;
394 }
395 }
396
397 fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
398 if offset > u64::from(u32::MAX) {
399 return None;
400 }
401 self.config_space_write(offset.try_into().unwrap(), offset % 4, data);
402
403 None
404 }
405}
406
407fn shift_and_mask(value: u32, offset: usize, mask: u32) -> usize {
408 ((value >> offset) & mask) as usize
409}
410
411fn parse_mmio_config_address(config_address: u32) -> (usize, usize, usize, usize) {
415 const BUS_NUMBER_OFFSET: usize = 20;
416 const BUS_NUMBER_MASK: u32 = 0x00ff;
417 const DEVICE_NUMBER_OFFSET: usize = 15;
418 const DEVICE_NUMBER_MASK: u32 = 0x1f;
419 const FUNCTION_NUMBER_OFFSET: usize = 12;
420 const FUNCTION_NUMBER_MASK: u32 = 0x07;
421 const REGISTER_NUMBER_OFFSET: usize = 2;
422 const REGISTER_NUMBER_MASK: u32 = 0x3ff;
423
424 (
425 shift_and_mask(config_address, BUS_NUMBER_OFFSET, BUS_NUMBER_MASK),
426 shift_and_mask(config_address, DEVICE_NUMBER_OFFSET, DEVICE_NUMBER_MASK),
427 shift_and_mask(config_address, FUNCTION_NUMBER_OFFSET, FUNCTION_NUMBER_MASK),
428 shift_and_mask(config_address, REGISTER_NUMBER_OFFSET, REGISTER_NUMBER_MASK),
429 )
430}
431
432fn parse_io_config_address(config_address: u32) -> (usize, usize, usize, usize) {
434 const BUS_NUMBER_OFFSET: usize = 16;
435 const BUS_NUMBER_MASK: u32 = 0x00ff;
436 const DEVICE_NUMBER_OFFSET: usize = 11;
437 const DEVICE_NUMBER_MASK: u32 = 0x1f;
438 const FUNCTION_NUMBER_OFFSET: usize = 8;
439 const FUNCTION_NUMBER_MASK: u32 = 0x07;
440 const REGISTER_NUMBER_OFFSET: usize = 2;
441 const REGISTER_NUMBER_MASK: u32 = 0x3f;
442
443 (
444 shift_and_mask(config_address, BUS_NUMBER_OFFSET, BUS_NUMBER_MASK),
445 shift_and_mask(config_address, DEVICE_NUMBER_OFFSET, DEVICE_NUMBER_MASK),
446 shift_and_mask(config_address, FUNCTION_NUMBER_OFFSET, FUNCTION_NUMBER_MASK),
447 shift_and_mask(config_address, REGISTER_NUMBER_OFFSET, REGISTER_NUMBER_MASK),
448 )
449}
450
451#[cfg(test)]
452mod tests {
453 use std::sync::atomic::AtomicUsize;
454 use std::sync::{Arc, Mutex};
455
456 use pci::{PciClassCode, PciMassStorageSubclass};
457
458 use super::{PciBus, PciConfigIo, PciConfigMmio, PciRoot};
459 use crate::pci::bus::{DEVICE_ID_INTEL_VIRT_PCIE_HOST, VENDOR_ID_INTEL};
460 use crate::pci::configuration::PciConfiguration;
461 use crate::pci::{BarReprogrammingParams, DeviceRelocation, DeviceRelocationError, PciDevice};
462 use crate::vstate::bus::BusDevice;
463
464 #[derive(Debug, Default)]
465 struct RelocationMock {
466 reloc_cnt: AtomicUsize,
467 }
468
469 impl RelocationMock {
470 fn cnt(&self) -> usize {
471 self.reloc_cnt.load(std::sync::atomic::Ordering::SeqCst)
472 }
473 }
474
475 impl DeviceRelocation for RelocationMock {
476 fn move_bar(
477 &self,
478 _old_base: u64,
479 _new_base: u64,
480 _len: u64,
481 _pci_dev: &mut dyn PciDevice,
482 ) -> Result<(), DeviceRelocationError> {
483 self.reloc_cnt
484 .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
485 Ok(())
486 }
487 }
488
489 struct PciDevMock(PciConfiguration);
490
491 impl PciDevMock {
492 fn new() -> Self {
493 let mut config = PciConfiguration::new_type0(
494 0x42,
495 0x0,
496 0x0,
497 PciClassCode::MassStorage,
498 &PciMassStorageSubclass::SerialScsiController,
499 0x13,
500 0x12,
501 None,
502 );
503
504 config.add_pci_bar(0, 0x1000, 0x1000);
505
506 PciDevMock(config)
507 }
508 }
509
510 impl PciDevice for PciDevMock {
511 fn write_config_register(
512 &mut self,
513 reg_idx: usize,
514 offset: u64,
515 data: &[u8],
516 ) -> Option<Arc<std::sync::Barrier>> {
517 self.0.write_config_register(reg_idx, offset, data);
518 None
519 }
520
521 fn read_config_register(&mut self, reg_idx: usize) -> u32 {
522 self.0.read_reg(reg_idx)
523 }
524
525 fn detect_bar_reprogramming(
526 &mut self,
527 reg_idx: usize,
528 data: &[u8],
529 ) -> Option<BarReprogrammingParams> {
530 self.0.detect_bar_reprogramming(reg_idx, data)
531 }
532 }
533
534 #[test]
535 fn test_writing_io_config_address() {
536 let mock = Arc::new(RelocationMock::default());
537 let root = PciRoot::new(None);
538 let mut bus = PciConfigIo::new(Arc::new(Mutex::new(PciBus::new(root, mock))));
539
540 assert_eq!(bus.config_address, 0);
541 bus.write(0, 0, &[0x42; 8]);
543 assert_eq!(bus.config_address, 0);
544 bus.write(0, 0, &[0x13, 0x12, 0x11, 0x10]);
546 assert_eq!(bus.config_address, 0x10111213);
547 bus.write(0, 1, &[0x0; 4]);
549 assert_eq!(bus.config_address, 0x10111213);
550
551 bus.write(0, 0, &[0x42, 0x42]);
553 assert_eq!(bus.config_address, 0x10114242);
554 bus.write(0, 1, &[0x43, 0x43]);
555 assert_eq!(bus.config_address, 0x10434342);
556 bus.write(0, 2, &[0x44, 0x44]);
557 assert_eq!(bus.config_address, 0x44444342);
558 bus.write(0, 3, &[0x45, 0x45]);
560 assert_eq!(bus.config_address, 0x44444342);
561
562 bus.write(0, 0, &[0x0]);
564 assert_eq!(bus.config_address, 0x44444300);
565 bus.write(0, 1, &[0x0]);
566 assert_eq!(bus.config_address, 0x44440000);
567 bus.write(0, 2, &[0x0]);
568 assert_eq!(bus.config_address, 0x44000000);
569 bus.write(0, 3, &[0x0]);
570 assert_eq!(bus.config_address, 0x00000000);
571 bus.write(0, 4, &[0x13]);
573 assert_eq!(bus.config_address, 0x0);
574 }
575
576 #[test]
577 fn test_reading_io_config_address() {
578 let mock = Arc::new(RelocationMock::default());
579 let root = PciRoot::new(None);
580 let mut bus = PciConfigIo::new(Arc::new(Mutex::new(PciBus::new(root, mock))));
581
582 let mut buffer = [0u8; 4];
583
584 bus.config_address = 0x13121110;
585
586 bus.read(0, 8, &mut buffer);
591 assert_eq!(buffer, [0xff; 4]);
592
593 bus.read(0, 1, &mut buffer);
595 assert_eq!(buffer, [0xff; 4]);
596 bus.read(0, 2, &mut buffer[..3]);
597 assert_eq!(buffer, [0xff; 4]);
598 bus.read(0, 3, &mut buffer[..2]);
599 assert_eq!(buffer, [0xff; 4]);
600
601 bus.read(0, 0, &mut buffer[0..1]);
603 assert_eq!(buffer, [0x10, 0xff, 0xff, 0xff]);
604 bus.read(0, 1, &mut buffer[1..2]);
605 assert_eq!(buffer, [0x10, 0x11, 0xff, 0xff]);
606 bus.read(0, 2, &mut buffer[2..3]);
607 assert_eq!(buffer, [0x10, 0x11, 0x12, 0xff]);
608 bus.read(0, 3, &mut buffer[3..4]);
609 assert_eq!(buffer, [0x10, 0x11, 0x12, 0x13]);
610
611 bus.config_address = 0x42434445;
613 bus.read(0, 0, &mut buffer[..2]);
614 assert_eq!(buffer, [0x45, 0x44, 0x12, 0x13]);
615 bus.read(0, 1, &mut buffer[..2]);
616 assert_eq!(buffer, [0x44, 0x43, 0x12, 0x13]);
617 bus.read(0, 2, &mut buffer[..2]);
618 assert_eq!(buffer, [0x43, 0x42, 0x12, 0x13]);
619
620 bus.read(0, 0, &mut buffer);
622 assert_eq!(buffer, [0x45, 0x44, 0x43, 0x42]);
623 }
624
625 fn initialize_bus() -> (PciConfigMmio, PciConfigIo, Arc<RelocationMock>) {
626 let mock = Arc::new(RelocationMock::default());
627 let root = PciRoot::new(None);
628 let mut bus = PciBus::new(root, mock.clone());
629 bus.add_device(1, Arc::new(Mutex::new(PciDevMock::new())));
630
631 let bus = Arc::new(Mutex::new(bus));
632 (PciConfigMmio::new(bus.clone()), PciConfigIo::new(bus), mock)
633 }
634
635 #[test]
636 fn test_invalid_register_boundary_reads() {
637 let (mut mmio_config, mut io_config, _) = initialize_bus();
638
639 let mut buffer = [0u8; 4];
641 mmio_config.read(0, 1, &mut buffer);
642 assert_eq!(0xffff_ffff, u32::from_le_bytes(buffer));
643
644 let mut buffer = [0u8; 4];
645 io_config.read(0, 1, &mut buffer);
646 assert_eq!(0xffff_ffff, u32::from_le_bytes(buffer));
647
648 let mut buffer = [0u8; 4];
650 io_config.read(0, 5, &mut buffer);
651 assert_eq!(0xffff_ffff, u32::from_le_bytes(buffer));
652 }
653
654 fn mmio_offset(bus: u8, device: u8, function: u8, register: u16, byte: u8) -> u32 {
663 assert!(device < 32);
664 assert!(function < 8);
665 assert!(register < 1024);
666 assert!(byte < 4);
667
668 (bus as u32) << 20
669 | (device as u32) << 15
670 | (function as u32) << 12
671 | (register as u32) << 2
672 | (byte as u32)
673 }
674
675 fn read_mmio_config(
676 config: &mut PciConfigMmio,
677 bus: u8,
678 device: u8,
679 function: u8,
680 register: u16,
681 byte: u8,
682 data: &mut [u8],
683 ) {
684 config.read(
685 0,
686 mmio_offset(bus, device, function, register, byte) as u64,
687 data,
688 );
689 }
690
691 fn write_mmio_config(
692 config: &mut PciConfigMmio,
693 bus: u8,
694 device: u8,
695 function: u8,
696 register: u16,
697 byte: u8,
698 data: &[u8],
699 ) {
700 config.write(
701 0,
702 mmio_offset(bus, device, function, register, byte) as u64,
703 data,
704 );
705 }
706
707 fn pio_offset(enabled: bool, bus: u8, device: u8, function: u8, register: u8) -> u32 {
719 assert!(device < 32);
720 assert!(function < 8);
721 assert!(register < 64);
722
723 let offset = if enabled { 0x8000_0000 } else { 0u32 };
724
725 offset
726 | (bus as u32) << 16
727 | (device as u32) << 11
728 | (function as u32) << 8
729 | (register as u32) << 2
730 }
731
732 fn set_io_address(
733 config: &mut PciConfigIo,
734 enabled: bool,
735 bus: u8,
736 device: u8,
737 function: u8,
738 register: u8,
739 ) {
740 let address = u32::to_le_bytes(pio_offset(enabled, bus, device, function, register));
741 config.write(0, 0, &address);
742 }
743
744 fn read_io_config(
745 config: &mut PciConfigIo,
746 enabled: bool,
747 bus: u8,
748 device: u8,
749 function: u8,
750 register: u8,
751 data: &mut [u8],
752 ) {
753 set_io_address(config, enabled, bus, device, function, register);
754 config.read(0, 4, data);
755 }
756
757 fn write_io_config(
758 config: &mut PciConfigIo,
759 enabled: bool,
760 bus: u8,
761 device: u8,
762 function: u8,
763 register: u8,
764 data: &[u8],
765 ) {
766 set_io_address(config, enabled, bus, device, function, register);
767 config.write(0, 4, data);
768 }
769
770 #[test]
771 fn test_mmio_invalid_bus_number() {
772 let (mut mmio_config, _, _) = initialize_bus();
773 let mut buffer = [0u8; 4];
774
775 read_mmio_config(&mut mmio_config, 1, 0, 0, 0, 0, &mut buffer);
777 assert_eq!(buffer, u32::to_le_bytes(0xffff_ffff));
778 buffer[0] = 0x42;
780 write_mmio_config(&mut mmio_config, 1, 0, 0, 15, 0, &buffer);
781 read_mmio_config(&mut mmio_config, 1, 0, 0, 15, 0, &mut buffer);
782 assert_eq!(buffer, u32::to_le_bytes(0xffff_ffff));
783 read_mmio_config(&mut mmio_config, 0, 0, 0, 15, 0, &mut buffer);
784 assert_eq!(buffer, u32::to_le_bytes(0x0));
785
786 read_mmio_config(&mut mmio_config, 0, 0, 0, 0, 0, &mut buffer);
788 assert_eq!(&buffer[..2], &u16::to_le_bytes(VENDOR_ID_INTEL));
789 assert_eq!(
790 &buffer[2..],
791 &u16::to_le_bytes(DEVICE_ID_INTEL_VIRT_PCIE_HOST)
792 );
793 }
794
795 #[test]
796 fn test_io_invalid_bus_number() {
797 let (_, mut pio_config, _) = initialize_bus();
798 let mut buffer = [0u8; 4];
799
800 read_io_config(&mut pio_config, true, 1, 0, 0, 0, &mut buffer);
802 assert_eq!(buffer, u32::to_le_bytes(0xffff_ffff));
803
804 read_io_config(&mut pio_config, true, 0, 0, 0, 0, &mut buffer);
806 assert_eq!(&buffer[..2], &u16::to_le_bytes(VENDOR_ID_INTEL));
807 assert_eq!(
808 &buffer[2..],
809 &u16::to_le_bytes(DEVICE_ID_INTEL_VIRT_PCIE_HOST)
810 );
811 }
812
813 #[test]
814 fn test_mmio_invalid_function() {
815 let (mut mmio_config, _, _) = initialize_bus();
816 let mut buffer = [0u8; 4];
817
818 read_mmio_config(&mut mmio_config, 0, 0, 1, 0, 0, &mut buffer);
820 assert_eq!(buffer, u32::to_le_bytes(0xffff_ffff));
821 buffer[0] = 0x42;
823 write_mmio_config(&mut mmio_config, 0, 0, 1, 15, 0, &buffer);
824 read_mmio_config(&mut mmio_config, 0, 0, 1, 15, 0, &mut buffer);
825 assert_eq!(buffer, u32::to_le_bytes(0xffff_ffff));
826 read_mmio_config(&mut mmio_config, 0, 0, 0, 15, 0, &mut buffer);
827 assert_eq!(buffer, u32::to_le_bytes(0x0));
828
829 read_mmio_config(&mut mmio_config, 0, 0, 0, 0, 0, &mut buffer);
831 assert_eq!(&buffer[..2], &u16::to_le_bytes(VENDOR_ID_INTEL));
832 assert_eq!(
833 &buffer[2..],
834 &u16::to_le_bytes(DEVICE_ID_INTEL_VIRT_PCIE_HOST)
835 );
836 }
837
838 #[test]
839 fn test_io_invalid_function() {
840 let (_, mut pio_config, _) = initialize_bus();
841 let mut buffer = [0u8; 4];
842
843 read_io_config(&mut pio_config, true, 0, 0, 1, 0, &mut buffer);
845 assert_eq!(buffer, u32::to_le_bytes(0xffff_ffff));
846
847 read_io_config(&mut pio_config, true, 0, 0, 0, 0, &mut buffer);
849 assert_eq!(&buffer[..2], &u16::to_le_bytes(VENDOR_ID_INTEL));
850 assert_eq!(
851 &buffer[2..],
852 &u16::to_le_bytes(DEVICE_ID_INTEL_VIRT_PCIE_HOST)
853 );
854 }
855
856 #[test]
857 fn test_io_disabled_reads() {
858 let (_, mut pio_config, _) = initialize_bus();
859 let mut buffer = [0u8; 4];
860
861 read_io_config(&mut pio_config, false, 0, 0, 0, 0, &mut buffer);
863 assert_eq!(buffer, u32::to_le_bytes(0xffff_ffff));
864
865 read_io_config(&mut pio_config, true, 0, 0, 0, 0, &mut buffer);
867 assert_eq!(&buffer[..2], &u16::to_le_bytes(VENDOR_ID_INTEL));
868 assert_eq!(
869 &buffer[2..],
870 &u16::to_le_bytes(DEVICE_ID_INTEL_VIRT_PCIE_HOST)
871 );
872 }
873
874 #[test]
875 fn test_io_disabled_writes() {
876 let (_, mut pio_config, _) = initialize_bus();
877
878 let mut buffer = [0u8; 4];
880
881 read_io_config(&mut pio_config, true, 0, 0, 0, 15, &mut buffer);
883 let irq_line = buffer[0];
884
885 buffer[0] = 0x42;
887 write_io_config(&mut pio_config, false, 0, 0, 0, 15, &buffer);
888
889 read_io_config(&mut pio_config, true, 0, 0, 0, 15, &mut buffer);
891 assert_eq!(buffer[0], irq_line);
892
893 buffer[0] = 0x42;
895 write_io_config(&mut pio_config, true, 0, 0, 0, 15, &buffer);
896
897 read_io_config(&mut pio_config, true, 0, 0, 0, 15, &mut buffer);
899 assert_eq!(buffer[0], 0x42);
900 }
901
902 #[test]
903 fn test_mmio_writes() {
904 let (mut mmio_config, _, _) = initialize_bus();
905 let mut buffer = [0u8; 4];
906
907 read_mmio_config(&mut mmio_config, 0, 0, 0, 15, 0, &mut buffer);
908 assert_eq!(buffer[0], 0x0);
909 write_mmio_config(&mut mmio_config, 0, 0, 0, 15, 0, &[0x42]);
910 read_mmio_config(&mut mmio_config, 0, 0, 0, 15, 0, &mut buffer);
911 assert_eq!(buffer[0], 0x42);
912 }
913
914 #[test]
915 fn test_bar_reprogramming() {
916 let (mut mmio_config, _, mock) = initialize_bus();
917 let mut buffer = [0u8; 4];
918 assert_eq!(mock.cnt(), 0);
919
920 read_mmio_config(&mut mmio_config, 0, 1, 0, 0x4, 0, &mut buffer);
921 let old_addr = u32::from_le_bytes(buffer) & 0xffff_fff0;
922 assert_eq!(old_addr, 0x1000);
923
924 write_mmio_config(
926 &mut mmio_config,
927 0,
928 1,
929 0,
930 0x4,
931 0,
932 &u32::to_le_bytes(0x1312_0000),
933 );
934
935 read_mmio_config(&mut mmio_config, 0, 1, 0, 0x4, 0, &mut buffer);
936 let new_addr = u32::from_le_bytes(buffer) & 0xffff_fff0;
937 assert_eq!(new_addr, 0x1312_0000);
938 assert_eq!(mock.cnt(), 0);
939
940 write_mmio_config(&mut mmio_config, 0, 1, 0, 0x5, 0, &u32::to_le_bytes(0x1110));
942 read_mmio_config(&mut mmio_config, 0, 1, 0, 0x5, 0, &mut buffer);
943 let new_addr = u32::from_le_bytes(buffer);
944 assert_eq!(new_addr, 0x1110);
945 assert_eq!(mock.cnt(), 1);
946
947 read_mmio_config(&mut mmio_config, 0, 1, 0, 0x6, 0, &mut buffer);
949 assert_eq!(buffer, [0x0, 0x0, 0x0, 0x0]);
950
951 write_mmio_config(
953 &mut mmio_config,
954 0,
955 1,
956 0,
957 0x5,
958 0,
959 &u32::to_le_bytes(0x1312_1110),
960 );
961
962 read_mmio_config(&mut mmio_config, 0, 1, 0, 0x6, 0, &mut buffer);
963 assert_eq!(buffer, [0x0, 0x0, 0x0, 0x0]);
964 }
965}