1use std::collections::BTreeMap;
6use std::convert::TryFrom;
7use std::convert::TryInto;
8use std::sync::Arc;
9
10use anyhow::bail;
11use anyhow::Context;
12use base::custom_serde::deserialize_seq_to_arr;
13use base::custom_serde::serialize_arr;
14use base::error;
15use base::warn;
16use base::MemoryMapping;
17use base::MemoryMappingBuilder;
18use base::SharedMemory;
19use downcast_rs::impl_downcast;
20use downcast_rs::Downcast;
21use remain::sorted;
22use serde::Deserialize;
23use serde::Serialize;
24use snapshot::AnySnapshot;
25use sync::Mutex;
26use thiserror::Error;
27
28use crate::pci::PciInterruptPin;
29
30const NUM_CONFIGURATION_REGISTERS: usize = 64;
32
33pub const PCI_ID_REG: usize = 0;
34pub const COMMAND_REG: usize = 1;
35pub const COMMAND_REG_IO_SPACE_MASK: u32 = 0x0000_0001;
36pub const COMMAND_REG_MEMORY_SPACE_MASK: u32 = 0x0000_0002;
37const STATUS_REG: usize = 1;
38pub const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
39#[allow(dead_code)]
40#[cfg(any(target_os = "android", target_os = "linux"))]
41pub const CLASS_REG: usize = 2;
42pub const HEADER_TYPE_REG: usize = 3;
43pub const HEADER_TYPE_REG_OFFSET: usize = 2;
44pub const HEADER_TYPE_MULTIFUNCTION_MASK: u8 = 0x80;
45pub const BAR0_REG: usize = 4;
46const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
47const BAR_IO_MIN_SIZE: u64 = 4;
48const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
49const BAR_MEM_MIN_SIZE: u64 = 16;
50const BAR_ROM_MIN_SIZE: u64 = 2048;
51pub const NUM_BAR_REGS: usize = 7; pub const ROM_BAR_IDX: PciBarIndex = 6;
53pub const ROM_BAR_REG: usize = 12;
54pub const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
55#[cfg(any(target_os = "android", target_os = "linux"))]
56pub const PCI_CAP_NEXT_POINTER: usize = 0x1;
57const FIRST_CAPABILITY_OFFSET: usize = 0x40;
58pub const CAPABILITY_MAX_OFFSET: usize = 255;
59
60const INTERRUPT_LINE_PIN_REG: usize = 15;
61
62#[allow(dead_code)]
64#[derive(Copy, Clone)]
65pub enum PciHeaderType {
66 Device,
67 Bridge,
68}
69
70#[allow(dead_code)]
72#[derive(Copy, Clone, Debug, enumn::N, Serialize, Deserialize, PartialEq, Eq)]
73pub enum PciClassCode {
74 TooOld,
75 MassStorage,
76 NetworkController,
77 DisplayController,
78 MultimediaController,
79 MemoryController,
80 BridgeDevice,
81 SimpleCommunicationController,
82 BaseSystemPeripheral,
83 InputDevice,
84 DockingStation,
85 Processor,
86 SerialBusController,
87 WirelessController,
88 IntelligentIoController,
89 SatelliteCommunicationController,
90 EncryptionController,
91 DataAcquisitionSignalProcessing,
92 ProcessingAccelerator,
93 NonEssentialInstrumentation,
94 Other = 0xff,
95}
96
97impl PciClassCode {
98 pub fn get_register_value(&self) -> u8 {
99 *self as u8
100 }
101}
102
103#[sorted]
104#[derive(Error, Debug)]
105pub enum PciClassCodeParseError {
106 #[error("Unknown class code")]
107 Unknown,
108}
109
110impl TryFrom<u8> for PciClassCode {
111 type Error = PciClassCodeParseError;
112 fn try_from(v: u8) -> std::result::Result<PciClassCode, PciClassCodeParseError> {
113 match PciClassCode::n(v) {
114 Some(class) => Ok(class),
115 None => Err(PciClassCodeParseError::Unknown),
116 }
117 }
118}
119
120pub trait PciSubclass {
123 fn get_register_value(&self) -> u8;
125}
126
127#[allow(dead_code)]
129#[derive(Copy, Clone)]
130pub enum PciMassStorageSubclass {
131 Scsi = 0x00,
132 NonVolatileMemory = 0x08,
133 Other = 0x80,
134}
135
136impl PciSubclass for PciMassStorageSubclass {
137 fn get_register_value(&self) -> u8 {
138 *self as u8
139 }
140}
141
142#[allow(dead_code)]
144#[derive(Copy, Clone)]
145pub enum PciNetworkControllerSubclass {
146 Other = 0x80,
147}
148
149impl PciSubclass for PciNetworkControllerSubclass {
150 fn get_register_value(&self) -> u8 {
151 *self as u8
152 }
153}
154
155#[allow(dead_code)]
157#[derive(Copy, Clone)]
158pub enum PciDisplaySubclass {
159 VgaCompatibleController = 0x00,
160 XgaCompatibleController = 0x01,
161 ThreeDController = 0x02,
162 Other = 0x80,
163}
164
165impl PciSubclass for PciDisplaySubclass {
166 fn get_register_value(&self) -> u8 {
167 *self as u8
168 }
169}
170
171#[allow(dead_code)]
173#[derive(Copy, Clone)]
174pub enum PciMultimediaSubclass {
175 VideoController = 0x00,
176 AudioController = 0x01,
177 TelephonyDevice = 0x02,
178 AudioDevice = 0x03,
179 Other = 0x80,
180}
181
182impl PciSubclass for PciMultimediaSubclass {
183 fn get_register_value(&self) -> u8 {
184 *self as u8
185 }
186}
187
188#[allow(dead_code)]
190#[derive(Copy, Clone)]
191pub enum PciBridgeSubclass {
192 HostBridge = 0x00,
193 IsaBridge = 0x01,
194 EisaBridge = 0x02,
195 McaBridge = 0x03,
196 PciToPciBridge = 0x04,
197 PcmciaBridge = 0x05,
198 NuBusBridge = 0x06,
199 CardBusBridge = 0x07,
200 RaceWayBridge = 0x08,
201 PciToPciSemiTransparentBridge = 0x09,
202 InfiniBrandToPciHostBridge = 0x0a,
203 OtherBridgeDevice = 0x80,
204}
205
206impl PciSubclass for PciBridgeSubclass {
207 fn get_register_value(&self) -> u8 {
208 *self as u8
209 }
210}
211
212#[allow(dead_code)]
214#[derive(Copy, Clone)]
215pub enum PciSimpleCommunicationControllerSubclass {
216 Other = 0x80,
217}
218
219impl PciSubclass for PciSimpleCommunicationControllerSubclass {
220 fn get_register_value(&self) -> u8 {
221 *self as u8
222 }
223}
224
225#[allow(dead_code)]
227#[derive(Copy, Clone)]
228pub enum PciBaseSystemPeripheralSubclass {
229 Iommu = 0x06,
230 Other = 0x80,
231}
232
233impl PciSubclass for PciBaseSystemPeripheralSubclass {
234 fn get_register_value(&self) -> u8 {
235 *self as u8
236 }
237}
238
239#[allow(dead_code)]
241#[derive(Copy, Clone)]
242pub enum PciInputDeviceSubclass {
243 Other = 0x80,
244}
245
246impl PciSubclass for PciInputDeviceSubclass {
247 fn get_register_value(&self) -> u8 {
248 *self as u8
249 }
250}
251
252#[allow(dead_code)]
254#[derive(Copy, Clone)]
255pub enum PciSerialBusSubClass {
256 Firewire = 0x00,
257 AccessBus = 0x01,
258 Ssa = 0x02,
259 Usb = 0x03,
260}
261
262impl PciSubclass for PciSerialBusSubClass {
263 fn get_register_value(&self) -> u8 {
264 *self as u8
265 }
266}
267
268#[allow(dead_code)]
270#[derive(Copy, Clone)]
271pub enum PciWirelessControllerSubclass {
272 Other = 0x80,
273}
274
275impl PciSubclass for PciWirelessControllerSubclass {
276 fn get_register_value(&self) -> u8 {
277 *self as u8
278 }
279}
280
281#[allow(dead_code)]
283#[derive(Copy, Clone)]
284#[repr(u8)]
285pub enum PciOtherSubclass {
286 Other = 0xff,
287}
288
289impl PciSubclass for PciOtherSubclass {
290 fn get_register_value(&self) -> u8 {
291 *self as u8
292 }
293}
294
295pub trait PciProgrammingInterface {
300 fn get_register_value(&self) -> u8;
302}
303
304pub enum PciCapabilityID {
306 ListID = 0,
307 PowerManagement = 0x01,
308 AcceleratedGraphicsPort = 0x02,
309 VitalProductData = 0x03,
310 SlotIdentification = 0x04,
311 MessageSignalledInterrupts = 0x05,
312 CompactPciHotSwap = 0x06,
313 Pcix = 0x07,
314 HyperTransport = 0x08,
315 VendorSpecific = 0x09,
316 Debugport = 0x0A,
317 CompactPciCentralResourceControl = 0x0B,
318 PciStandardHotPlugController = 0x0C,
319 BridgeSubsystemVendorDeviceID = 0x0D,
320 AgpTargetPciPciBridge = 0x0E,
321 SecureDevice = 0x0F,
322 PciExpress = 0x10,
323 Msix = 0x11,
324 SataDataIndexConf = 0x12,
325 PciAdvancedFeatures = 0x13,
326 PciEnhancedAllocation = 0x14,
327}
328
329pub trait PciCapability {
331 fn bytes(&self) -> &[u8];
332 fn id(&self) -> PciCapabilityID;
333 fn writable_bits(&self) -> Vec<u32>;
334}
335
336pub trait PciCapConfigWriteResult: Downcast {}
337impl_downcast!(PciCapConfigWriteResult);
338
339pub trait PciCapConfig: Send {
341 fn read_reg(&self, reg_idx: usize) -> u32;
346
347 fn read_mask(&self) -> &'static [u32];
349
350 fn write_reg(
356 &mut self,
357 reg_idx: usize,
358 offset: u64,
359 data: &[u8],
360 ) -> Option<Box<dyn PciCapConfigWriteResult>>;
361
362 fn set_cap_mapping(&mut self, _mapping: PciCapMapping) {}
367
368 fn num_regs(&self) -> usize {
369 self.read_mask().len()
370 }
371}
372
373pub struct PciConfiguration {
377 registers: [u32; NUM_CONFIGURATION_REGISTERS],
378 writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], bar_used: [bool; NUM_BAR_REGS],
380 bar_configs: [Option<PciBarConfiguration>; NUM_BAR_REGS],
381 last_capability: Option<(usize, usize)>,
383 capability_configs: BTreeMap<usize, Box<dyn PciCapConfig>>,
384 mmio_mapping: Option<(Arc<Mutex<MemoryMapping>>, usize)>,
385}
386
387#[derive(Serialize, Deserialize)]
388pub struct PciConfigurationSerialized {
389 #[serde(
390 serialize_with = "serialize_arr",
391 deserialize_with = "deserialize_seq_to_arr"
392 )]
393 registers: [u32; NUM_CONFIGURATION_REGISTERS],
394 #[serde(
395 serialize_with = "serialize_arr",
396 deserialize_with = "deserialize_seq_to_arr"
397 )]
398 writable_bits: [u32; NUM_CONFIGURATION_REGISTERS],
399 bar_used: [bool; NUM_BAR_REGS],
400 bar_configs: [Option<PciBarConfiguration>; NUM_BAR_REGS],
401 last_capability: Option<(usize, usize)>,
402}
403
404#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
406pub enum PciBarRegionType {
407 Memory32BitRegion = 0,
408 IoRegion = 0x01,
409 Memory64BitRegion = 0x04,
410}
411
412#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
413pub enum PciBarPrefetchable {
414 NotPrefetchable = 0,
415 Prefetchable = 0x08,
416}
417
418pub type PciBarIndex = usize;
419
420#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
421pub struct PciBarConfiguration {
422 addr: u64,
423 size: u64,
424 bar_idx: PciBarIndex,
425 region_type: PciBarRegionType,
426 prefetchable: PciBarPrefetchable,
427}
428
429pub struct PciBarIter<'a> {
430 config: &'a PciConfiguration,
431 bar_num: PciBarIndex,
432}
433
434impl Iterator for PciBarIter<'_> {
435 type Item = PciBarConfiguration;
436
437 fn next(&mut self) -> Option<Self::Item> {
438 while self.bar_num < NUM_BAR_REGS {
439 let bar_config = self.config.get_bar_configuration(self.bar_num);
440 self.bar_num += 1;
441 if let Some(bar_config) = bar_config {
442 return Some(bar_config);
443 }
444 }
445
446 None
447 }
448}
449
450#[sorted]
451#[derive(Error, Debug, PartialEq, Eq)]
452pub enum Error {
453 #[error("address {0} size {1} too big")]
454 BarAddressInvalid(u64, u64),
455 #[error("address {0} is not aligned to size {1}")]
456 BarAlignmentInvalid(u64, u64),
457 #[error("bar {0} already used")]
458 BarInUse(PciBarIndex),
459 #[error("64bit bar {0} already used (requires two regs)")]
460 BarInUse64(PciBarIndex),
461 #[error("bar {0} invalid, max {max}", max = NUM_BAR_REGS - 1)]
462 BarInvalid(PciBarIndex),
463 #[error("64bitbar {0} invalid, requires two regs, max {max}", max = ROM_BAR_IDX - 1)]
464 BarInvalid64(PciBarIndex),
465 #[error("expansion rom bar must be a memory region")]
466 BarInvalidRomType,
467 #[error("bar address {0} not a power of two")]
468 BarSizeInvalid(u64),
469 #[error("empty capabilities are invalid")]
470 CapabilityEmpty,
471 #[error("Invalid capability length {0}")]
472 CapabilityLengthInvalid(usize),
473 #[error("capability of size {0} doesn't fit")]
474 CapabilitySpaceFull(usize),
475}
476
477pub type Result<T> = std::result::Result<T, Error>;
478
479impl PciConfiguration {
480 pub fn new(
481 vendor_id: u16,
482 device_id: u16,
483 class_code: PciClassCode,
484 subclass: &dyn PciSubclass,
485 programming_interface: Option<&dyn PciProgrammingInterface>,
486 header_type: PciHeaderType,
487 subsystem_vendor_id: u16,
488 subsystem_id: u16,
489 revision_id: u8,
490 ) -> Self {
491 let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
492 let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
493 registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
494 writable_bits[1] = 0x0000_ffff; let pi = if let Some(pi) = programming_interface {
497 pi.get_register_value()
498 } else {
499 0
500 };
501 registers[2] = u32::from(class_code.get_register_value()) << 24
502 | u32::from(subclass.get_register_value()) << 16
503 | u32::from(pi) << 8
504 | u32::from(revision_id);
505 writable_bits[3] = 0x0000_00ff; match header_type {
507 PciHeaderType::Device => {
508 registers[3] = 0x0000_0000; writable_bits[15] = 0x0000_00ff; registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
511 }
512 PciHeaderType::Bridge => {
513 registers[3] = 0x0001_0000; writable_bits[6] = 0x00ff_ffff; registers[7] = 0x0000_00f0; writable_bits[7] = 0xf900_0000; registers[8] = 0x0000_fff0; writable_bits[8] = 0xfff0_fff0; registers[9] = 0x0001_fff1; writable_bits[9] = 0xfff0_fff0; writable_bits[10] = 0xffff_ffff; writable_bits[11] = 0xffff_ffff; writable_bits[15] = 0xffff_00ff; }
526 };
527
528 PciConfiguration {
529 registers,
530 writable_bits,
531 bar_used: [false; NUM_BAR_REGS],
532 bar_configs: [None; NUM_BAR_REGS],
533 last_capability: None,
534 capability_configs: BTreeMap::new(),
535 mmio_mapping: None,
536 }
537 }
538
539 pub fn read_reg(&self, reg_idx: usize) -> u32 {
541 let mut data = *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff));
542 if let Some((idx, cfg)) = self.capability_configs.range(..=reg_idx).last() {
543 if reg_idx < idx + cfg.num_regs() {
544 let cap_idx = reg_idx - idx;
545 let mask = cfg.read_mask()[cap_idx];
546 data = (data & !mask) | (cfg.read_reg(cap_idx) & mask);
547 }
548 }
549 data
550 }
551
552 pub fn write_reg(
558 &mut self,
559 reg_idx: usize,
560 offset: u64,
561 data: &[u8],
562 ) -> Option<Box<dyn PciCapConfigWriteResult>> {
563 let reg_offset = reg_idx * 4 + offset as usize;
564 match data.len() {
565 1 => self.write_byte(reg_offset, data[0]),
566 2 => self.write_word(reg_offset, u16::from_le_bytes(data.try_into().unwrap())),
567 4 => self.write_dword(reg_offset, u32::from_le_bytes(data.try_into().unwrap())),
568 _ => (),
569 }
570 if let Some((idx, cfg)) = self.capability_configs.range_mut(..=reg_idx).last() {
571 if reg_idx < idx + cfg.num_regs() {
572 let cap_idx = reg_idx - idx;
573 let ret = cfg.write_reg(cap_idx, offset, data);
574 let new_val = cfg.read_reg(cap_idx);
575 let mask = cfg.read_mask()[cap_idx];
576 self.set_reg(reg_idx, new_val, mask);
577 return ret;
578 }
579 }
580 None
581 }
582
583 fn write_dword(&mut self, offset: usize, value: u32) {
585 if offset % 4 != 0 {
586 warn!("bad PCI config dword write offset {}", offset);
587 return;
588 }
589 let reg_idx = offset / 4;
590 if reg_idx < NUM_CONFIGURATION_REGISTERS {
591 let old_value = self.registers[reg_idx];
592 let new_value =
593 (old_value & !self.writable_bits[reg_idx]) | (value & self.writable_bits[reg_idx]);
594 self.do_write(reg_idx, new_value)
595 } else {
596 warn!("bad PCI dword write {}", offset);
597 }
598 }
599
600 fn write_word(&mut self, offset: usize, value: u16) {
602 let shift = match offset % 4 {
603 0 => 0,
604 2 => 16,
605 _ => {
606 warn!("bad PCI config word write offset {}", offset);
607 return;
608 }
609 };
610 let reg_idx = offset / 4;
611
612 if reg_idx < NUM_CONFIGURATION_REGISTERS {
613 let old_value = self.registers[reg_idx];
614 let writable_mask = self.writable_bits[reg_idx];
615 let mask = (0xffffu32 << shift) & writable_mask;
616 let shifted_value = (u32::from(value) << shift) & writable_mask;
617 let new_value = old_value & !mask | shifted_value;
618 self.do_write(reg_idx, new_value)
619 } else {
620 warn!("bad PCI config word write offset {}", offset);
621 }
622 }
623
624 fn write_byte(&mut self, offset: usize, value: u8) {
626 self.write_byte_internal(offset, value, true);
627 }
628
629 fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
631 let shift = (offset % 4) * 8;
632 let reg_idx = offset / 4;
633
634 if reg_idx < NUM_CONFIGURATION_REGISTERS {
635 let writable_mask = if apply_writable_mask {
636 self.writable_bits[reg_idx]
637 } else {
638 0xffff_ffff
639 };
640 let old_value = self.registers[reg_idx];
641 let mask = (0xffu32 << shift) & writable_mask;
642 let shifted_value = (u32::from(value) << shift) & writable_mask;
643 let new_value = old_value & !mask | shifted_value;
644 self.do_write(reg_idx, new_value)
645 } else {
646 warn!("bad PCI config byte write offset {}", offset);
647 }
648 }
649
650 pub fn set_reg(&mut self, reg_idx: usize, data: u32, mask: u32) {
657 if reg_idx >= NUM_CONFIGURATION_REGISTERS {
658 return;
659 }
660 let new_val = (self.registers[reg_idx] & !mask) | (data & mask);
661 self.do_write(reg_idx, new_val);
662 }
663
664 pub fn add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex> {
669 if config.bar_idx >= NUM_BAR_REGS {
670 return Err(Error::BarInvalid(config.bar_idx));
671 }
672
673 if self.bar_used[config.bar_idx] {
674 return Err(Error::BarInUse(config.bar_idx));
675 }
676
677 if config.size.count_ones() != 1 {
678 return Err(Error::BarSizeInvalid(config.size));
679 }
680
681 if config.is_expansion_rom() && config.region_type != PciBarRegionType::Memory32BitRegion {
682 return Err(Error::BarInvalidRomType);
683 }
684
685 let min_size = if config.is_expansion_rom() {
686 BAR_ROM_MIN_SIZE
687 } else if config.region_type == PciBarRegionType::IoRegion {
688 BAR_IO_MIN_SIZE
689 } else {
690 BAR_MEM_MIN_SIZE
691 };
692
693 if config.size < min_size {
694 return Err(Error::BarSizeInvalid(config.size));
695 }
696
697 if config.addr % config.size != 0 {
698 return Err(Error::BarAlignmentInvalid(config.addr, config.size));
699 }
700
701 let reg_idx = config.reg_index();
702 let end_addr = config
703 .addr
704 .checked_add(config.size)
705 .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
706 match config.region_type {
707 PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => {
708 if end_addr > u64::from(u32::MAX) {
709 return Err(Error::BarAddressInvalid(config.addr, config.size));
710 }
711 }
712 PciBarRegionType::Memory64BitRegion => {
713 if config.bar_idx + 1 >= ROM_BAR_IDX {
715 return Err(Error::BarInvalid64(config.bar_idx));
716 }
717
718 if self.bar_used[config.bar_idx + 1] {
719 return Err(Error::BarInUse64(config.bar_idx));
720 }
721
722 self.do_write(reg_idx + 1, (config.addr >> 32) as u32);
723 self.writable_bits[reg_idx + 1] = !((config.size - 1) >> 32) as u32;
724 self.bar_used[config.bar_idx + 1] = true;
725 }
726 }
727
728 let (mask, lower_bits) = match config.region_type {
729 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
730 self.registers[COMMAND_REG] |= COMMAND_REG_MEMORY_SPACE_MASK;
731 (
732 BAR_MEM_ADDR_MASK,
733 config.prefetchable as u32 | config.region_type as u32,
734 )
735 }
736 PciBarRegionType::IoRegion => {
737 self.registers[COMMAND_REG] |= COMMAND_REG_IO_SPACE_MASK;
738 (BAR_IO_ADDR_MASK, config.region_type as u32)
739 }
740 };
741
742 self.do_write(reg_idx, ((config.addr as u32) & mask) | lower_bits);
743 self.writable_bits[reg_idx] = !(config.size - 1) as u32;
744 if config.is_expansion_rom() {
745 self.writable_bits[reg_idx] |= 1; }
747 self.bar_used[config.bar_idx] = true;
748 self.bar_configs[config.bar_idx] = Some(config);
749 Ok(config.bar_idx)
750 }
751
752 #[allow(dead_code)] pub fn get_bars(&self) -> PciBarIter {
755 PciBarIter {
756 config: self,
757 bar_num: 0,
758 }
759 }
760
761 pub fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
763 let config = self.bar_configs.get(bar_num)?;
764
765 if let Some(mut config) = config {
766 let command = self.read_reg(COMMAND_REG);
767 if (config.is_memory() && (command & COMMAND_REG_MEMORY_SPACE_MASK == 0))
768 || (config.is_io() && (command & COMMAND_REG_IO_SPACE_MASK == 0))
769 {
770 return None;
771 }
772
773 config.addr = self.get_bar_addr(bar_num);
776 Some(config)
777 } else {
778 None
779 }
780 }
781
782 pub fn get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType> {
784 self.bar_configs.get(bar_num)?.map(|c| c.region_type)
785 }
786
787 pub fn get_bar_addr(&self, bar_num: PciBarIndex) -> u64 {
789 let bar_idx = if bar_num == ROM_BAR_IDX {
790 ROM_BAR_REG
791 } else {
792 BAR0_REG + bar_num
793 };
794
795 let bar_type = match self.get_bar_type(bar_num) {
796 Some(t) => t,
797 None => return 0,
798 };
799
800 match bar_type {
801 PciBarRegionType::IoRegion => u64::from(self.registers[bar_idx] & BAR_IO_ADDR_MASK),
802 PciBarRegionType::Memory32BitRegion => {
803 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
804 }
805 PciBarRegionType::Memory64BitRegion => {
806 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
807 | u64::from(self.registers[bar_idx + 1]) << 32
808 }
809 }
810 }
811
812 pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
814 let pin_idx = (pin as u32) + 1;
816 let new_val = (self.registers[INTERRUPT_LINE_PIN_REG] & 0xffff_0000)
817 | (pin_idx << 8)
818 | u32::from(line);
819 self.do_write(INTERRUPT_LINE_PIN_REG, new_val)
820 }
821
822 pub fn add_capability(
827 &mut self,
828 cap_data: &dyn PciCapability,
829 cap_config: Option<Box<dyn PciCapConfig>>,
830 ) -> Result<()> {
831 let total_len = cap_data.bytes().len();
832 if cap_data.bytes().is_empty() {
834 return Err(Error::CapabilityEmpty);
835 }
836 let (cap_offset, tail_offset) = match self.last_capability {
837 Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
838 None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
839 };
840 let end_offset = cap_offset
841 .checked_add(total_len)
842 .ok_or(Error::CapabilitySpaceFull(total_len))?;
843 if end_offset > CAPABILITY_MAX_OFFSET {
844 return Err(Error::CapabilitySpaceFull(total_len));
845 }
846 self.do_write(
847 STATUS_REG,
848 self.registers[STATUS_REG] | STATUS_REG_CAPABILITIES_USED_MASK,
849 );
850 self.write_byte_internal(tail_offset, cap_offset as u8, false);
851 self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
852 self.write_byte_internal(cap_offset + 1, 0, false); for (i, byte) in cap_data.bytes().iter().enumerate().skip(2) {
854 self.write_byte_internal(cap_offset + i, *byte, false);
855 }
856 let reg_idx = cap_offset / 4;
857 for (i, dword) in cap_data.writable_bits().iter().enumerate() {
858 self.writable_bits[reg_idx + i] = *dword;
859 }
860 self.last_capability = Some((cap_offset, total_len));
861 if let Some(mut cap_config) = cap_config {
862 if let Some((mapping, offset)) = &self.mmio_mapping {
863 cap_config.set_cap_mapping(PciCapMapping {
864 mapping: mapping.clone(),
865 offset: reg_idx * 4 + offset,
866 num_regs: total_len / 4,
867 });
868 }
869 self.capability_configs.insert(cap_offset / 4, cap_config);
870 }
871 Ok(())
872 }
873
874 fn next_dword(offset: usize, len: usize) -> usize {
876 let next = offset + len;
877 (next + 3) & !3
878 }
879
880 fn do_write(&mut self, reg_idx: usize, value: u32) {
881 self.registers[reg_idx] = value;
882 if let Some((mmio_mapping, offset)) = self.mmio_mapping.as_ref() {
883 let mmio_mapping = mmio_mapping.lock();
884 let reg_offset = offset + reg_idx * 4;
885 if reg_idx == HEADER_TYPE_REG {
886 mmio_mapping
889 .write_obj_volatile((value & 0xffff) as u16, reg_offset)
890 .expect("bad register offset");
891 mmio_mapping
893 .write_obj_volatile(((value >> 24) & 0xff) as u8, reg_offset + 3)
894 .expect("bad register offset");
895 } else {
896 mmio_mapping
897 .write_obj_volatile(value, reg_offset)
898 .expect("bad register offset");
899 }
900 if let Err(err) = mmio_mapping.flush_region(reg_offset, 4) {
901 error!(
902 "failed to flush write to pci mmio register ({}): {}",
903 reg_idx, err
904 );
905 }
906 }
907 }
908
909 pub fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
910 AnySnapshot::to_any(PciConfigurationSerialized {
911 registers: self.registers,
912 writable_bits: self.writable_bits,
913 bar_used: self.bar_used,
914 bar_configs: self.bar_configs,
915 last_capability: self.last_capability,
916 })
917 .context("failed to serialize PciConfiguration")
918 }
919
920 pub fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
921 let deser: PciConfigurationSerialized =
922 AnySnapshot::from_any(data).context("failed to deserialize PciConfiguration")?;
923 self.registers = deser.registers;
924 self.writable_bits = deser.writable_bits;
925 self.bar_used = deser.bar_used;
926 self.bar_configs = deser.bar_configs;
927 self.last_capability = deser.last_capability;
928 for i in 0..NUM_CONFIGURATION_REGISTERS {
933 self.do_write(i, self.registers[i]);
934 }
935 Ok(())
936 }
937
938 pub fn setup_mapping(
939 &mut self,
940 shmem: &SharedMemory,
941 base: usize,
942 len: usize,
943 ) -> anyhow::Result<()> {
944 if self.mmio_mapping.is_some() {
945 bail!("PCIe config mmio mapping already initialized");
946 }
947 let mapping = MemoryMappingBuilder::new(base::pagesize())
948 .from_shared_memory(shmem)
949 .build()
950 .context("Failed to create mapping")?;
951 for i in 0..(len / 4) {
952 let val = self.registers.get(i).unwrap_or(&0xffff_ffff);
953 mapping
954 .write_obj_volatile(*val, base + i * 4)
955 .expect("memcpy failed");
956 }
957 let mapping = Arc::new(Mutex::new(mapping));
958 for (idx, cap) in self.capability_configs.iter_mut() {
959 let mut cap_mapping = PciCapMapping {
960 mapping: mapping.clone(),
961 offset: idx * 4 + base,
962 num_regs: cap.num_regs(),
963 };
964 for i in 0..cap.num_regs() {
965 let val = cap.read_reg(i);
966 let mask = cap.read_mask()[i];
967 cap_mapping.set_reg(i, val, mask);
968 }
969 cap.set_cap_mapping(cap_mapping);
970 }
971 self.mmio_mapping = Some((mapping, base));
972 Ok(())
973 }
974}
975
976impl PciBarConfiguration {
977 pub fn new(
978 bar_idx: PciBarIndex,
979 size: u64,
980 region_type: PciBarRegionType,
981 prefetchable: PciBarPrefetchable,
982 ) -> Self {
983 PciBarConfiguration {
984 bar_idx,
985 addr: 0,
986 size,
987 region_type,
988 prefetchable,
989 }
990 }
991
992 pub fn bar_index(&self) -> PciBarIndex {
993 self.bar_idx
994 }
995
996 pub fn reg_index(&self) -> usize {
997 if self.bar_idx == ROM_BAR_IDX {
998 ROM_BAR_REG
999 } else {
1000 BAR0_REG + self.bar_idx
1001 }
1002 }
1003
1004 pub fn address(&self) -> u64 {
1005 self.addr
1006 }
1007
1008 pub fn address_range(&self) -> std::ops::Range<u64> {
1009 self.addr..self.addr + self.size
1010 }
1011
1012 pub fn set_address(mut self, addr: u64) -> Self {
1013 self.addr = addr;
1014 self
1015 }
1016
1017 pub fn size(&self) -> u64 {
1018 self.size
1019 }
1020
1021 pub fn is_expansion_rom(&self) -> bool {
1022 self.bar_idx == ROM_BAR_IDX
1023 }
1024
1025 pub fn is_memory(&self) -> bool {
1026 matches!(
1027 self.region_type,
1028 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion
1029 )
1030 }
1031
1032 pub fn is_64bit_memory(&self) -> bool {
1033 self.region_type == PciBarRegionType::Memory64BitRegion
1034 }
1035
1036 pub fn is_io(&self) -> bool {
1037 self.region_type == PciBarRegionType::IoRegion
1038 }
1039
1040 pub fn is_prefetchable(&self) -> bool {
1041 self.is_memory() && self.prefetchable == PciBarPrefetchable::Prefetchable
1042 }
1043}
1044
1045impl<T: PciCapConfig + ?Sized> PciCapConfig for Arc<Mutex<T>> {
1046 fn read_mask(&self) -> &'static [u32] {
1047 self.lock().read_mask()
1048 }
1049 fn read_reg(&self, reg_idx: usize) -> u32 {
1050 self.lock().read_reg(reg_idx)
1051 }
1052 fn write_reg(
1053 &mut self,
1054 reg_idx: usize,
1055 offset: u64,
1056 data: &[u8],
1057 ) -> Option<Box<dyn PciCapConfigWriteResult>> {
1058 self.lock().write_reg(reg_idx, offset, data)
1059 }
1060 fn set_cap_mapping(&mut self, mapping: PciCapMapping) {
1061 self.lock().set_cap_mapping(mapping)
1062 }
1063}
1064
1065pub struct PciCapMapping {
1067 mapping: Arc<Mutex<MemoryMapping>>,
1068 offset: usize,
1069 num_regs: usize,
1070}
1071
1072impl PciCapMapping {
1073 pub fn set_reg(&mut self, reg_idx: usize, data: u32, mask: u32) {
1075 if reg_idx >= self.num_regs {
1076 error!(
1077 "out of bounds register write {} vs {}",
1078 self.num_regs, reg_idx
1079 );
1080 return;
1081 }
1082 let mapping = self.mapping.lock();
1083 let offset = self.offset + reg_idx * 4;
1084 let cur_value = mapping.read_obj::<u32>(offset).expect("memcpy failed");
1085 let new_val = (cur_value & !mask) | (data & mask);
1086 mapping
1087 .write_obj_volatile(new_val, offset)
1088 .expect("memcpy failed");
1089 if let Err(err) = mapping.flush_region(offset, 4) {
1090 error!(
1091 "failed to flush write to pci cap in mmio register ({}): {}",
1092 reg_idx, err
1093 );
1094 }
1095 }
1096}
1097
1098#[cfg(test)]
1099mod tests {
1100 use zerocopy::FromBytes;
1101 use zerocopy::Immutable;
1102 use zerocopy::IntoBytes;
1103 use zerocopy::KnownLayout;
1104
1105 use super::*;
1106
1107 #[repr(C, packed)]
1108 #[derive(Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
1109 #[allow(dead_code)]
1110 struct TestCap {
1111 _vndr: u8,
1112 _next: u8,
1113 len: u8,
1114 foo: u8,
1115 }
1116
1117 impl PciCapability for TestCap {
1118 fn bytes(&self) -> &[u8] {
1119 self.as_bytes()
1120 }
1121
1122 fn id(&self) -> PciCapabilityID {
1123 PciCapabilityID::VendorSpecific
1124 }
1125
1126 fn writable_bits(&self) -> Vec<u32> {
1127 vec![0u32; 1]
1128 }
1129 }
1130
1131 #[test]
1132 fn add_capability() {
1133 let mut cfg = PciConfiguration::new(
1134 0x1234,
1135 0x5678,
1136 PciClassCode::MultimediaController,
1137 &PciMultimediaSubclass::AudioController,
1138 None,
1139 PciHeaderType::Device,
1140 0xABCD,
1141 0x2468,
1142 0,
1143 );
1144
1145 let cap1 = TestCap {
1147 _vndr: 0,
1148 _next: 0,
1149 len: 4,
1150 foo: 0xAA,
1151 };
1152 let cap1_offset = 64;
1153 cfg.add_capability(&cap1, None).unwrap();
1154
1155 let cap2 = TestCap {
1156 _vndr: 0,
1157 _next: 0,
1158 len: 0x04,
1159 foo: 0x55,
1160 };
1161 let cap2_offset = 68;
1162 cfg.add_capability(&cap2, None).unwrap();
1163
1164 let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
1166 assert_eq!(cap1_offset, cap_ptr as usize);
1167
1168 let cap1_data = cfg.read_reg(cap1_offset / 4);
1170 assert_eq!(cap1_data & 0xFF, 0x09); assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); assert_eq!((cap1_data >> 16) & 0xFF, 0x04); assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); let cap2_data = cfg.read_reg(cap2_offset / 4);
1176 assert_eq!(cap2_data & 0xFF, 0x09); assert_eq!((cap2_data >> 8) & 0xFF, 0x00); assert_eq!((cap2_data >> 16) & 0xFF, 0x04); assert_eq!((cap2_data >> 24) & 0xFF, 0x55); }
1181
1182 #[derive(Copy, Clone)]
1183 enum TestPI {
1184 Test = 0x5a,
1185 }
1186
1187 impl PciProgrammingInterface for TestPI {
1188 fn get_register_value(&self) -> u8 {
1189 *self as u8
1190 }
1191 }
1192
1193 #[test]
1194 fn class_code() {
1195 let cfg = PciConfiguration::new(
1196 0x1234,
1197 0x5678,
1198 PciClassCode::MultimediaController,
1199 &PciMultimediaSubclass::AudioController,
1200 Some(&TestPI::Test),
1201 PciHeaderType::Device,
1202 0xABCD,
1203 0x2468,
1204 0,
1205 );
1206
1207 let class_reg = cfg.read_reg(2);
1208 let class_code = (class_reg >> 24) & 0xFF;
1209 let subclass = (class_reg >> 16) & 0xFF;
1210 let prog_if = (class_reg >> 8) & 0xFF;
1211 assert_eq!(class_code, 0x04);
1212 assert_eq!(subclass, 0x01);
1213 assert_eq!(prog_if, 0x5a);
1214 }
1215
1216 #[test]
1217 fn read_only_bits() {
1218 let mut cfg = PciConfiguration::new(
1219 0x1234,
1220 0x5678,
1221 PciClassCode::MultimediaController,
1222 &PciMultimediaSubclass::AudioController,
1223 Some(&TestPI::Test),
1224 PciHeaderType::Device,
1225 0xABCD,
1226 0x2468,
1227 0,
1228 );
1229
1230 cfg.write_reg(0, 0, &[0xBA, 0xAD, 0xF0, 0x0D]);
1232 assert_eq!(cfg.read_reg(0), 0x56781234);
1234 }
1235
1236 #[test]
1237 fn query_unused_bar() {
1238 let cfg = PciConfiguration::new(
1239 0x1234,
1240 0x5678,
1241 PciClassCode::MultimediaController,
1242 &PciMultimediaSubclass::AudioController,
1243 Some(&TestPI::Test),
1244 PciHeaderType::Device,
1245 0xABCD,
1246 0x2468,
1247 0,
1248 );
1249
1250 assert_eq!(cfg.get_bar_type(0), None);
1252 assert_eq!(cfg.get_bar_addr(0), 0);
1253
1254 let mut bar_iter = cfg.get_bars();
1255 assert_eq!(bar_iter.next(), None);
1256 }
1257
1258 #[test]
1259 fn add_pci_bar_mem_64bit() {
1260 let mut cfg = PciConfiguration::new(
1261 0x1234,
1262 0x5678,
1263 PciClassCode::MultimediaController,
1264 &PciMultimediaSubclass::AudioController,
1265 Some(&TestPI::Test),
1266 PciHeaderType::Device,
1267 0xABCD,
1268 0x2468,
1269 0,
1270 );
1271
1272 cfg.add_pci_bar(
1273 PciBarConfiguration::new(
1274 0,
1275 0x10,
1276 PciBarRegionType::Memory64BitRegion,
1277 PciBarPrefetchable::NotPrefetchable,
1278 )
1279 .set_address(0x0123_4567_89AB_CDE0),
1280 )
1281 .expect("add_pci_bar failed");
1282
1283 assert_eq!(
1284 cfg.get_bar_type(0),
1285 Some(PciBarRegionType::Memory64BitRegion)
1286 );
1287 assert_eq!(cfg.get_bar_addr(0), 0x0123_4567_89AB_CDE0);
1288 assert_eq!(cfg.writable_bits[BAR0_REG + 1], 0xFFFFFFFF);
1289 assert_eq!(cfg.writable_bits[BAR0_REG + 0], 0xFFFFFFF0);
1290
1291 let mut bar_iter = cfg.get_bars();
1292 assert_eq!(
1293 bar_iter.next(),
1294 Some(PciBarConfiguration {
1295 addr: 0x0123_4567_89AB_CDE0,
1296 size: 0x10,
1297 bar_idx: 0,
1298 region_type: PciBarRegionType::Memory64BitRegion,
1299 prefetchable: PciBarPrefetchable::NotPrefetchable
1300 })
1301 );
1302 assert_eq!(bar_iter.next(), None);
1303 }
1304
1305 #[test]
1306 fn add_pci_bar_mem_32bit() {
1307 let mut cfg = PciConfiguration::new(
1308 0x1234,
1309 0x5678,
1310 PciClassCode::MultimediaController,
1311 &PciMultimediaSubclass::AudioController,
1312 Some(&TestPI::Test),
1313 PciHeaderType::Device,
1314 0xABCD,
1315 0x2468,
1316 0,
1317 );
1318
1319 cfg.add_pci_bar(
1320 PciBarConfiguration::new(
1321 0,
1322 0x10,
1323 PciBarRegionType::Memory32BitRegion,
1324 PciBarPrefetchable::NotPrefetchable,
1325 )
1326 .set_address(0x12345670),
1327 )
1328 .expect("add_pci_bar failed");
1329
1330 assert_eq!(
1331 cfg.get_bar_type(0),
1332 Some(PciBarRegionType::Memory32BitRegion)
1333 );
1334 assert_eq!(cfg.get_bar_addr(0), 0x12345670);
1335 assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFF0);
1336
1337 let mut bar_iter = cfg.get_bars();
1338 assert_eq!(
1339 bar_iter.next(),
1340 Some(PciBarConfiguration {
1341 addr: 0x12345670,
1342 size: 0x10,
1343 bar_idx: 0,
1344 region_type: PciBarRegionType::Memory32BitRegion,
1345 prefetchable: PciBarPrefetchable::NotPrefetchable
1346 })
1347 );
1348 assert_eq!(bar_iter.next(), None);
1349 }
1350
1351 #[test]
1352 fn add_pci_bar_io() {
1353 let mut cfg = PciConfiguration::new(
1354 0x1234,
1355 0x5678,
1356 PciClassCode::MultimediaController,
1357 &PciMultimediaSubclass::AudioController,
1358 Some(&TestPI::Test),
1359 PciHeaderType::Device,
1360 0xABCD,
1361 0x2468,
1362 0,
1363 );
1364
1365 cfg.add_pci_bar(
1366 PciBarConfiguration::new(
1367 0,
1368 0x4,
1369 PciBarRegionType::IoRegion,
1370 PciBarPrefetchable::NotPrefetchable,
1371 )
1372 .set_address(0x1230),
1373 )
1374 .expect("add_pci_bar failed");
1375
1376 assert_eq!(cfg.get_bar_type(0), Some(PciBarRegionType::IoRegion));
1377 assert_eq!(cfg.get_bar_addr(0), 0x1230);
1378 assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFFC);
1379
1380 let mut bar_iter = cfg.get_bars();
1381 assert_eq!(
1382 bar_iter.next(),
1383 Some(PciBarConfiguration {
1384 addr: 0x1230,
1385 size: 0x4,
1386 bar_idx: 0,
1387 region_type: PciBarRegionType::IoRegion,
1388 prefetchable: PciBarPrefetchable::NotPrefetchable
1389 })
1390 );
1391 assert_eq!(bar_iter.next(), None);
1392 }
1393
1394 #[test]
1395 fn add_pci_bar_multiple() {
1396 let mut cfg = PciConfiguration::new(
1397 0x1234,
1398 0x5678,
1399 PciClassCode::MultimediaController,
1400 &PciMultimediaSubclass::AudioController,
1401 Some(&TestPI::Test),
1402 PciHeaderType::Device,
1403 0xABCD,
1404 0x2468,
1405 0,
1406 );
1407
1408 cfg.add_pci_bar(
1410 PciBarConfiguration::new(
1411 0,
1412 0x10,
1413 PciBarRegionType::Memory64BitRegion,
1414 PciBarPrefetchable::NotPrefetchable,
1415 )
1416 .set_address(0x0123_4567_89AB_CDE0),
1417 )
1418 .expect("add_pci_bar failed");
1419
1420 cfg.add_pci_bar(
1422 PciBarConfiguration::new(
1423 2,
1424 0x10,
1425 PciBarRegionType::Memory32BitRegion,
1426 PciBarPrefetchable::NotPrefetchable,
1427 )
1428 .set_address(0x12345670),
1429 )
1430 .expect("add_pci_bar failed");
1431
1432 cfg.add_pci_bar(
1434 PciBarConfiguration::new(
1435 3,
1436 0x4,
1437 PciBarRegionType::IoRegion,
1438 PciBarPrefetchable::NotPrefetchable,
1439 )
1440 .set_address(0x1230),
1441 )
1442 .expect("add_pci_bar failed");
1443
1444 let mut bar_iter = cfg.get_bars();
1446 assert_eq!(
1447 bar_iter.next(),
1448 Some(PciBarConfiguration {
1449 addr: 0x0123_4567_89AB_CDE0,
1450 size: 0x10,
1451 bar_idx: 0,
1452 region_type: PciBarRegionType::Memory64BitRegion,
1453 prefetchable: PciBarPrefetchable::NotPrefetchable
1454 })
1455 );
1456 assert_eq!(
1457 bar_iter.next(),
1458 Some(PciBarConfiguration {
1459 addr: 0x12345670,
1460 size: 0x10,
1461 bar_idx: 2,
1462 region_type: PciBarRegionType::Memory32BitRegion,
1463 prefetchable: PciBarPrefetchable::NotPrefetchable
1464 })
1465 );
1466 assert_eq!(
1467 bar_iter.next(),
1468 Some(PciBarConfiguration {
1469 addr: 0x1230,
1470 size: 0x4,
1471 bar_idx: 3,
1472 region_type: PciBarRegionType::IoRegion,
1473 prefetchable: PciBarPrefetchable::NotPrefetchable
1474 })
1475 );
1476 assert_eq!(bar_iter.next(), None);
1477
1478 cfg.write_reg(4 + 0, 0, &0xBBAA9980u32.to_le_bytes());
1480 cfg.write_reg(4 + 1, 0, &0xFFEEDDCCu32.to_le_bytes());
1481
1482 let mut bar_iter = cfg.get_bars();
1483 assert_eq!(
1484 bar_iter.next(),
1485 Some(PciBarConfiguration {
1486 addr: 0xFFEE_DDCC_BBAA_9980,
1487 size: 0x10,
1488 bar_idx: 0,
1489 region_type: PciBarRegionType::Memory64BitRegion,
1490 prefetchable: PciBarPrefetchable::NotPrefetchable
1491 })
1492 );
1493 assert_eq!(
1494 bar_iter.next(),
1495 Some(PciBarConfiguration {
1496 addr: 0x12345670,
1497 size: 0x10,
1498 bar_idx: 2,
1499 region_type: PciBarRegionType::Memory32BitRegion,
1500 prefetchable: PciBarPrefetchable::NotPrefetchable
1501 })
1502 );
1503 assert_eq!(
1504 bar_iter.next(),
1505 Some(PciBarConfiguration {
1506 addr: 0x1230,
1507 size: 0x4,
1508 bar_idx: 3,
1509 region_type: PciBarRegionType::IoRegion,
1510 prefetchable: PciBarPrefetchable::NotPrefetchable
1511 })
1512 );
1513 assert_eq!(bar_iter.next(), None);
1514 }
1515
1516 #[test]
1517 fn add_pci_bar_invalid_size() {
1518 let mut cfg = PciConfiguration::new(
1519 0x1234,
1520 0x5678,
1521 PciClassCode::MultimediaController,
1522 &PciMultimediaSubclass::AudioController,
1523 Some(&TestPI::Test),
1524 PciHeaderType::Device,
1525 0xABCD,
1526 0x2468,
1527 0,
1528 );
1529
1530 assert_eq!(
1532 cfg.add_pci_bar(
1533 PciBarConfiguration::new(
1534 0,
1535 0x2,
1536 PciBarRegionType::IoRegion,
1537 PciBarPrefetchable::NotPrefetchable,
1538 )
1539 .set_address(0x1230),
1540 ),
1541 Err(Error::BarSizeInvalid(0x2))
1542 );
1543
1544 assert_eq!(
1546 cfg.add_pci_bar(
1547 PciBarConfiguration::new(
1548 0,
1549 0x3,
1550 PciBarRegionType::IoRegion,
1551 PciBarPrefetchable::NotPrefetchable,
1552 )
1553 .set_address(0x1230),
1554 ),
1555 Err(Error::BarSizeInvalid(0x3))
1556 );
1557
1558 assert_eq!(
1560 cfg.add_pci_bar(
1561 PciBarConfiguration::new(
1562 0,
1563 0x8,
1564 PciBarRegionType::Memory32BitRegion,
1565 PciBarPrefetchable::NotPrefetchable,
1566 )
1567 .set_address(0x12345670),
1568 ),
1569 Err(Error::BarSizeInvalid(0x8))
1570 );
1571 }
1572
1573 #[test]
1574 fn add_rom_bar() {
1575 let mut cfg = PciConfiguration::new(
1576 0x1234,
1577 0x5678,
1578 PciClassCode::MultimediaController,
1579 &PciMultimediaSubclass::AudioController,
1580 Some(&TestPI::Test),
1581 PciHeaderType::Device,
1582 0xABCD,
1583 0x2468,
1584 0,
1585 );
1586
1587 assert_eq!(
1589 cfg.add_pci_bar(PciBarConfiguration::new(
1590 ROM_BAR_IDX,
1591 0x1000,
1592 PciBarRegionType::Memory64BitRegion,
1593 PciBarPrefetchable::NotPrefetchable,
1594 ),),
1595 Err(Error::BarInvalidRomType)
1596 );
1597
1598 assert_eq!(
1600 cfg.add_pci_bar(PciBarConfiguration::new(
1601 ROM_BAR_IDX,
1602 0x1000,
1603 PciBarRegionType::IoRegion,
1604 PciBarPrefetchable::NotPrefetchable,
1605 ),),
1606 Err(Error::BarInvalidRomType)
1607 );
1608
1609 assert_eq!(
1611 cfg.add_pci_bar(PciBarConfiguration::new(
1612 ROM_BAR_IDX,
1613 1024,
1614 PciBarRegionType::Memory32BitRegion,
1615 PciBarPrefetchable::NotPrefetchable,
1616 ),),
1617 Err(Error::BarSizeInvalid(1024))
1618 );
1619
1620 cfg.add_pci_bar(
1622 PciBarConfiguration::new(
1623 ROM_BAR_IDX,
1624 0x800,
1625 PciBarRegionType::Memory32BitRegion,
1626 PciBarPrefetchable::NotPrefetchable,
1627 )
1628 .set_address(0x12345000),
1629 )
1630 .expect("add_pci_bar failed");
1631
1632 assert_eq!(
1633 cfg.get_bar_type(ROM_BAR_IDX),
1634 Some(PciBarRegionType::Memory32BitRegion)
1635 );
1636 assert_eq!(cfg.get_bar_addr(ROM_BAR_IDX), 0x12345000);
1637 assert_eq!(cfg.read_reg(ROM_BAR_REG), 0x12345000);
1638 assert_eq!(cfg.writable_bits[ROM_BAR_REG], 0xFFFFF801);
1639 }
1640
1641 #[test]
1642 fn pci_configuration_capability_snapshot_restore() -> anyhow::Result<()> {
1643 let mut cfg = PciConfiguration::new(
1644 0x1234,
1645 0x5678,
1646 PciClassCode::MultimediaController,
1647 &PciMultimediaSubclass::AudioController,
1648 Some(&TestPI::Test),
1649 PciHeaderType::Device,
1650 0xABCD,
1651 0x2468,
1652 0,
1653 );
1654
1655 let snap_init = cfg.snapshot().context("failed to snapshot")?;
1656
1657 let cap1 = TestCap {
1659 _vndr: 0,
1660 _next: 0,
1661 len: 4,
1662 foo: 0xAA,
1663 };
1664 cfg.add_capability(&cap1, None).unwrap();
1665
1666 let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1667 cfg.restore(snap_init.clone())
1668 .context("failed to restore snap_init")?;
1669 let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1670 assert_eq!(snap_init, snap_restore_init);
1671 assert_ne!(snap_init, snap_mod);
1672 cfg.restore(snap_mod.clone())
1673 .context("failed to restore snap_init")?;
1674 let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1675 assert_eq!(snap_mod, snap_restore_mod);
1676 Ok(())
1677 }
1678
1679 #[test]
1680 fn pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()> {
1681 let mut cfg = PciConfiguration::new(
1682 0x1234,
1683 0x5678,
1684 PciClassCode::MultimediaController,
1685 &PciMultimediaSubclass::AudioController,
1686 Some(&TestPI::Test),
1687 PciHeaderType::Device,
1688 0xABCD,
1689 0x2468,
1690 0,
1691 );
1692
1693 let snap_init = cfg.snapshot().context("failed to snapshot")?;
1694
1695 cfg.add_pci_bar(
1697 PciBarConfiguration::new(
1698 0,
1699 0x10,
1700 PciBarRegionType::Memory64BitRegion,
1701 PciBarPrefetchable::NotPrefetchable,
1702 )
1703 .set_address(0x0123_4567_89AB_CDE0),
1704 )
1705 .expect("add_pci_bar failed");
1706
1707 let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1708 cfg.restore(snap_init.clone())
1709 .context("failed to restore snap_init")?;
1710 let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1711 assert_eq!(snap_init, snap_restore_init);
1712 assert_ne!(snap_init, snap_mod);
1713 cfg.restore(snap_mod.clone())
1714 .context("failed to restore snap_init")?;
1715 let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1716 assert_eq!(snap_mod, snap_restore_mod);
1717 Ok(())
1718 }
1719
1720 #[test]
1721 fn pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()> {
1722 let mut cfg = PciConfiguration::new(
1723 0x1234,
1724 0x5678,
1725 PciClassCode::MultimediaController,
1726 &PciMultimediaSubclass::AudioController,
1727 Some(&TestPI::Test),
1728 PciHeaderType::Device,
1729 0xABCD,
1730 0x2468,
1731 0,
1732 );
1733
1734 let snap_init = cfg.snapshot().context("failed to snapshot")?;
1735
1736 let cap1 = TestCap {
1738 _vndr: 0,
1739 _next: 0,
1740 len: 4,
1741 foo: 0xAA,
1742 };
1743 cfg.add_capability(&cap1, None).unwrap();
1744
1745 cfg.add_pci_bar(
1747 PciBarConfiguration::new(
1748 0,
1749 0x10,
1750 PciBarRegionType::Memory64BitRegion,
1751 PciBarPrefetchable::NotPrefetchable,
1752 )
1753 .set_address(0x0123_4567_89AB_CDE0),
1754 )
1755 .expect("add_pci_bar failed");
1756
1757 let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1758 cfg.restore(snap_init.clone())
1759 .context("failed to restore snap_init")?;
1760 let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1761 assert_eq!(snap_init, snap_restore_init);
1762 assert_ne!(snap_init, snap_mod);
1763 cfg.restore(snap_mod.clone())
1764 .context("failed to restore snap_init")?;
1765 let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1766 assert_eq!(snap_mod, snap_restore_mod);
1767 Ok(())
1768 }
1769}