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