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; }
527 };
528
529 PciConfiguration {
530 registers,
531 writable_bits,
532 bar_used: [false; NUM_BAR_REGS],
533 bar_configs: [None; NUM_BAR_REGS],
534 last_capability: None,
535 capability_configs: BTreeMap::new(),
536 mmio_mapping: None,
537 }
538 }
539
540 pub fn read_reg(&self, reg_idx: usize) -> u32 {
542 let mut data = *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff));
543 if let Some((idx, cfg)) = self.capability_configs.range(..=reg_idx).last() {
544 if reg_idx < idx + cfg.num_regs() {
545 let cap_idx = reg_idx - idx;
546 let mask = cfg.read_mask()[cap_idx];
547 data = (data & !mask) | (cfg.read_reg(cap_idx) & mask);
548 }
549 }
550 data
551 }
552
553 pub fn write_reg(
559 &mut self,
560 reg_idx: usize,
561 offset: u64,
562 data: &[u8],
563 ) -> Option<Box<dyn PciCapConfigWriteResult>> {
564 let reg_offset = reg_idx * 4 + offset as usize;
565 match data.len() {
566 1 => self.write_byte(reg_offset, data[0]),
567 2 => self.write_word(reg_offset, u16::from_le_bytes(data.try_into().unwrap())),
568 4 => self.write_dword(reg_offset, u32::from_le_bytes(data.try_into().unwrap())),
569 _ => (),
570 }
571 if let Some((idx, cfg)) = self.capability_configs.range_mut(..=reg_idx).last() {
572 if reg_idx < idx + cfg.num_regs() {
573 let cap_idx = reg_idx - idx;
574 let ret = cfg.write_reg(cap_idx, offset, data);
575 let new_val = cfg.read_reg(cap_idx);
576 let mask = cfg.read_mask()[cap_idx];
577 self.set_reg(reg_idx, new_val, mask);
578 return ret;
579 }
580 }
581 None
582 }
583
584 fn write_dword(&mut self, offset: usize, value: u32) {
586 if offset % 4 != 0 {
587 warn!("bad PCI config dword write offset {}", offset);
588 return;
589 }
590 let reg_idx = offset / 4;
591 if reg_idx < NUM_CONFIGURATION_REGISTERS {
592 let old_value = self.registers[reg_idx];
593 let new_value =
594 (old_value & !self.writable_bits[reg_idx]) | (value & self.writable_bits[reg_idx]);
595 self.do_write(reg_idx, new_value)
596 } else {
597 warn!("bad PCI dword write {}", offset);
598 }
599 }
600
601 fn write_word(&mut self, offset: usize, value: u16) {
603 let shift = match offset % 4 {
604 0 => 0,
605 2 => 16,
606 _ => {
607 warn!("bad PCI config word write offset {}", offset);
608 return;
609 }
610 };
611 let reg_idx = offset / 4;
612
613 if reg_idx < NUM_CONFIGURATION_REGISTERS {
614 let old_value = self.registers[reg_idx];
615 let writable_mask = self.writable_bits[reg_idx];
616 let mask = (0xffffu32 << shift) & writable_mask;
617 let shifted_value = (u32::from(value) << shift) & writable_mask;
618 let new_value = old_value & !mask | shifted_value;
619 self.do_write(reg_idx, new_value)
620 } else {
621 warn!("bad PCI config word write offset {}", offset);
622 }
623 }
624
625 fn write_byte(&mut self, offset: usize, value: u8) {
627 self.write_byte_internal(offset, value, true);
628 }
629
630 fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
632 let shift = (offset % 4) * 8;
633 let reg_idx = offset / 4;
634
635 if reg_idx < NUM_CONFIGURATION_REGISTERS {
636 let writable_mask = if apply_writable_mask {
637 self.writable_bits[reg_idx]
638 } else {
639 0xffff_ffff
640 };
641 let old_value = self.registers[reg_idx];
642 let mask = (0xffu32 << shift) & writable_mask;
643 let shifted_value = (u32::from(value) << shift) & writable_mask;
644 let new_value = old_value & !mask | shifted_value;
645 self.do_write(reg_idx, new_value)
646 } else {
647 warn!("bad PCI config byte write offset {}", offset);
648 }
649 }
650
651 pub fn set_reg(&mut self, reg_idx: usize, data: u32, mask: u32) {
658 if reg_idx >= NUM_CONFIGURATION_REGISTERS {
659 return;
660 }
661 let new_val = (self.registers[reg_idx] & !mask) | (data & mask);
662 self.do_write(reg_idx, new_val);
663 }
664
665 pub fn add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex> {
670 if config.bar_idx >= NUM_BAR_REGS {
671 return Err(Error::BarInvalid(config.bar_idx));
672 }
673
674 if self.bar_used[config.bar_idx] {
675 return Err(Error::BarInUse(config.bar_idx));
676 }
677
678 if config.size.count_ones() != 1 {
679 return Err(Error::BarSizeInvalid(config.size));
680 }
681
682 if config.is_expansion_rom() && config.region_type != PciBarRegionType::Memory32BitRegion {
683 return Err(Error::BarInvalidRomType);
684 }
685
686 let min_size = if config.is_expansion_rom() {
687 BAR_ROM_MIN_SIZE
688 } else if config.region_type == PciBarRegionType::IoRegion {
689 BAR_IO_MIN_SIZE
690 } else {
691 BAR_MEM_MIN_SIZE
692 };
693
694 if config.size < min_size {
695 return Err(Error::BarSizeInvalid(config.size));
696 }
697
698 if config.addr % config.size != 0 {
699 return Err(Error::BarAlignmentInvalid(config.addr, config.size));
700 }
701
702 let reg_idx = config.reg_index();
703 let end_addr = config
704 .addr
705 .checked_add(config.size)
706 .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
707 match config.region_type {
708 PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => {
709 if end_addr > u64::from(u32::MAX) {
710 return Err(Error::BarAddressInvalid(config.addr, config.size));
711 }
712 }
713 PciBarRegionType::Memory64BitRegion => {
714 if config.bar_idx + 1 >= ROM_BAR_IDX {
716 return Err(Error::BarInvalid64(config.bar_idx));
717 }
718
719 if self.bar_used[config.bar_idx + 1] {
720 return Err(Error::BarInUse64(config.bar_idx));
721 }
722
723 self.do_write(reg_idx + 1, (config.addr >> 32) as u32);
724 self.writable_bits[reg_idx + 1] = !((config.size - 1) >> 32) as u32;
725 self.bar_used[config.bar_idx + 1] = true;
726 }
727 }
728
729 let (mask, lower_bits) = match config.region_type {
730 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
731 self.registers[COMMAND_REG] |= COMMAND_REG_MEMORY_SPACE_MASK;
732 (
733 BAR_MEM_ADDR_MASK,
734 config.prefetchable as u32 | config.region_type as u32,
735 )
736 }
737 PciBarRegionType::IoRegion => {
738 self.registers[COMMAND_REG] |= COMMAND_REG_IO_SPACE_MASK;
739 (BAR_IO_ADDR_MASK, config.region_type as u32)
740 }
741 };
742
743 self.do_write(reg_idx, ((config.addr as u32) & mask) | lower_bits);
744 self.writable_bits[reg_idx] = !(config.size - 1) as u32;
745 if config.is_expansion_rom() {
746 self.writable_bits[reg_idx] |= 1; }
748 self.bar_used[config.bar_idx] = true;
749 self.bar_configs[config.bar_idx] = Some(config);
750 Ok(config.bar_idx)
751 }
752
753 #[allow(dead_code)] pub fn get_bars(&self) -> PciBarIter {
756 PciBarIter {
757 config: self,
758 bar_num: 0,
759 }
760 }
761
762 pub fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
764 let config = self.bar_configs.get(bar_num)?;
765
766 if let Some(mut config) = config {
767 let command = self.read_reg(COMMAND_REG);
768 if (config.is_memory() && (command & COMMAND_REG_MEMORY_SPACE_MASK == 0))
769 || (config.is_io() && (command & COMMAND_REG_IO_SPACE_MASK == 0))
770 {
771 return None;
772 }
773
774 config.addr = self.get_bar_addr(bar_num);
777 Some(config)
778 } else {
779 None
780 }
781 }
782
783 pub fn get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType> {
785 self.bar_configs.get(bar_num)?.map(|c| c.region_type)
786 }
787
788 pub fn get_bar_addr(&self, bar_num: PciBarIndex) -> u64 {
790 let bar_idx = if bar_num == ROM_BAR_IDX {
791 ROM_BAR_REG
792 } else {
793 BAR0_REG + bar_num
794 };
795
796 let bar_type = match self.get_bar_type(bar_num) {
797 Some(t) => t,
798 None => return 0,
799 };
800
801 match bar_type {
802 PciBarRegionType::IoRegion => u64::from(self.registers[bar_idx] & BAR_IO_ADDR_MASK),
803 PciBarRegionType::Memory32BitRegion => {
804 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
805 }
806 PciBarRegionType::Memory64BitRegion => {
807 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
808 | u64::from(self.registers[bar_idx + 1]) << 32
809 }
810 }
811 }
812
813 pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
815 let pin_idx = (pin as u32) + 1;
817 let new_val = (self.registers[INTERRUPT_LINE_PIN_REG] & 0xffff_0000)
818 | (pin_idx << 8)
819 | u32::from(line);
820 self.do_write(INTERRUPT_LINE_PIN_REG, new_val)
821 }
822
823 pub fn add_capability(
828 &mut self,
829 cap_data: &dyn PciCapability,
830 cap_config: Option<Box<dyn PciCapConfig>>,
831 ) -> Result<()> {
832 let total_len = cap_data.bytes().len();
833 if cap_data.bytes().is_empty() {
835 return Err(Error::CapabilityEmpty);
836 }
837 let (cap_offset, tail_offset) = match self.last_capability {
838 Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
839 None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
840 };
841 let end_offset = cap_offset
842 .checked_add(total_len)
843 .ok_or(Error::CapabilitySpaceFull(total_len))?;
844 if end_offset > CAPABILITY_MAX_OFFSET {
845 return Err(Error::CapabilitySpaceFull(total_len));
846 }
847 self.do_write(
848 STATUS_REG,
849 self.registers[STATUS_REG] | STATUS_REG_CAPABILITIES_USED_MASK,
850 );
851 self.write_byte_internal(tail_offset, cap_offset as u8, false);
852 self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
853 self.write_byte_internal(cap_offset + 1, 0, false); for (i, byte) in cap_data.bytes().iter().enumerate().skip(2) {
855 self.write_byte_internal(cap_offset + i, *byte, false);
856 }
857 let reg_idx = cap_offset / 4;
858 for (i, dword) in cap_data.writable_bits().iter().enumerate() {
859 self.writable_bits[reg_idx + i] = *dword;
860 }
861 self.last_capability = Some((cap_offset, total_len));
862 if let Some(mut cap_config) = cap_config {
863 if let Some((mapping, offset)) = &self.mmio_mapping {
864 cap_config.set_cap_mapping(PciCapMapping {
865 mapping: mapping.clone(),
866 offset: reg_idx * 4 + offset,
867 num_regs: total_len / 4,
868 });
869 }
870 self.capability_configs.insert(cap_offset / 4, cap_config);
871 }
872 Ok(())
873 }
874
875 fn next_dword(offset: usize, len: usize) -> usize {
877 let next = offset + len;
878 (next + 3) & !3
879 }
880
881 fn do_write(&mut self, reg_idx: usize, value: u32) {
882 self.registers[reg_idx] = value;
883 if let Some((mmio_mapping, offset)) = self.mmio_mapping.as_ref() {
884 let mmio_mapping = mmio_mapping.lock();
885 let reg_offset = offset + reg_idx * 4;
886 if reg_idx == HEADER_TYPE_REG {
887 mmio_mapping
890 .write_obj_volatile((value & 0xffff) as u16, reg_offset)
891 .expect("bad register offset");
892 mmio_mapping
894 .write_obj_volatile(((value >> 24) & 0xff) as u8, reg_offset + 3)
895 .expect("bad register offset");
896 } else {
897 mmio_mapping
898 .write_obj_volatile(value, reg_offset)
899 .expect("bad register offset");
900 }
901 if let Err(err) = mmio_mapping.flush_region(reg_offset, 4) {
902 error!(
903 "failed to flush write to pci mmio register ({}): {}",
904 reg_idx, err
905 );
906 }
907 }
908 }
909
910 pub fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
911 AnySnapshot::to_any(PciConfigurationSerialized {
912 registers: self.registers,
913 writable_bits: self.writable_bits,
914 bar_used: self.bar_used,
915 bar_configs: self.bar_configs,
916 last_capability: self.last_capability,
917 })
918 .context("failed to serialize PciConfiguration")
919 }
920
921 pub fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
922 let deser: PciConfigurationSerialized =
923 AnySnapshot::from_any(data).context("failed to deserialize PciConfiguration")?;
924 self.registers = deser.registers;
925 self.writable_bits = deser.writable_bits;
926 self.bar_used = deser.bar_used;
927 self.bar_configs = deser.bar_configs;
928 self.last_capability = deser.last_capability;
929 for i in 0..NUM_CONFIGURATION_REGISTERS {
934 self.do_write(i, self.registers[i]);
935 }
936 Ok(())
937 }
938
939 pub fn setup_mapping(
940 &mut self,
941 shmem: &SharedMemory,
942 base: usize,
943 len: usize,
944 ) -> anyhow::Result<()> {
945 if self.mmio_mapping.is_some() {
946 bail!("PCIe config mmio mapping already initialized");
947 }
948 let mapping = MemoryMappingBuilder::new(base::pagesize())
949 .from_shared_memory(shmem)
950 .build()
951 .context("Failed to create mapping")?;
952 for i in 0..(len / 4) {
953 let val = self.registers.get(i).unwrap_or(&0xffff_ffff);
954 mapping
955 .write_obj_volatile(*val, base + i * 4)
956 .expect("memcpy failed");
957 }
958 let mapping = Arc::new(Mutex::new(mapping));
959 for (idx, cap) in self.capability_configs.iter_mut() {
960 let mut cap_mapping = PciCapMapping {
961 mapping: mapping.clone(),
962 offset: idx * 4 + base,
963 num_regs: cap.num_regs(),
964 };
965 for i in 0..cap.num_regs() {
966 let val = cap.read_reg(i);
967 let mask = cap.read_mask()[i];
968 cap_mapping.set_reg(i, val, mask);
969 }
970 cap.set_cap_mapping(cap_mapping);
971 }
972 self.mmio_mapping = Some((mapping, base));
973 Ok(())
974 }
975}
976
977impl PciBarConfiguration {
978 pub fn new(
979 bar_idx: PciBarIndex,
980 size: u64,
981 region_type: PciBarRegionType,
982 prefetchable: PciBarPrefetchable,
983 ) -> Self {
984 PciBarConfiguration {
985 bar_idx,
986 addr: 0,
987 size,
988 region_type,
989 prefetchable,
990 }
991 }
992
993 pub fn bar_index(&self) -> PciBarIndex {
994 self.bar_idx
995 }
996
997 pub fn reg_index(&self) -> usize {
998 if self.bar_idx == ROM_BAR_IDX {
999 ROM_BAR_REG
1000 } else {
1001 BAR0_REG + self.bar_idx
1002 }
1003 }
1004
1005 pub fn address(&self) -> u64 {
1006 self.addr
1007 }
1008
1009 pub fn address_range(&self) -> std::ops::Range<u64> {
1010 self.addr..self.addr + self.size
1011 }
1012
1013 pub fn set_address(mut self, addr: u64) -> Self {
1014 self.addr = addr;
1015 self
1016 }
1017
1018 pub fn size(&self) -> u64 {
1019 self.size
1020 }
1021
1022 pub fn is_expansion_rom(&self) -> bool {
1023 self.bar_idx == ROM_BAR_IDX
1024 }
1025
1026 pub fn is_memory(&self) -> bool {
1027 matches!(
1028 self.region_type,
1029 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion
1030 )
1031 }
1032
1033 pub fn is_64bit_memory(&self) -> bool {
1034 self.region_type == PciBarRegionType::Memory64BitRegion
1035 }
1036
1037 pub fn is_io(&self) -> bool {
1038 self.region_type == PciBarRegionType::IoRegion
1039 }
1040
1041 pub fn is_prefetchable(&self) -> bool {
1042 self.is_memory() && self.prefetchable == PciBarPrefetchable::Prefetchable
1043 }
1044}
1045
1046impl<T: PciCapConfig + ?Sized> PciCapConfig for Arc<Mutex<T>> {
1047 fn read_mask(&self) -> &'static [u32] {
1048 self.lock().read_mask()
1049 }
1050 fn read_reg(&self, reg_idx: usize) -> u32 {
1051 self.lock().read_reg(reg_idx)
1052 }
1053 fn write_reg(
1054 &mut self,
1055 reg_idx: usize,
1056 offset: u64,
1057 data: &[u8],
1058 ) -> Option<Box<dyn PciCapConfigWriteResult>> {
1059 self.lock().write_reg(reg_idx, offset, data)
1060 }
1061 fn set_cap_mapping(&mut self, mapping: PciCapMapping) {
1062 self.lock().set_cap_mapping(mapping)
1063 }
1064}
1065
1066pub struct PciCapMapping {
1068 mapping: Arc<Mutex<MemoryMapping>>,
1069 offset: usize,
1070 num_regs: usize,
1071}
1072
1073impl PciCapMapping {
1074 pub fn set_reg(&mut self, reg_idx: usize, data: u32, mask: u32) {
1076 if reg_idx >= self.num_regs {
1077 error!(
1078 "out of bounds register write {} vs {}",
1079 self.num_regs, reg_idx
1080 );
1081 return;
1082 }
1083 let mapping = self.mapping.lock();
1084 let offset = self.offset + reg_idx * 4;
1085 let cur_value = mapping.read_obj::<u32>(offset).expect("memcpy failed");
1086 let new_val = (cur_value & !mask) | (data & mask);
1087 mapping
1088 .write_obj_volatile(new_val, offset)
1089 .expect("memcpy failed");
1090 if let Err(err) = mapping.flush_region(offset, 4) {
1091 error!(
1092 "failed to flush write to pci cap in mmio register ({}): {}",
1093 reg_idx, err
1094 );
1095 }
1096 }
1097}
1098
1099#[cfg(test)]
1100mod tests {
1101 use zerocopy::FromBytes;
1102 use zerocopy::Immutable;
1103 use zerocopy::IntoBytes;
1104 use zerocopy::KnownLayout;
1105
1106 use super::*;
1107
1108 #[repr(C, packed)]
1109 #[derive(Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
1110 #[allow(dead_code)]
1111 struct TestCap {
1112 _vndr: u8,
1113 _next: u8,
1114 len: u8,
1115 foo: u8,
1116 }
1117
1118 impl PciCapability for TestCap {
1119 fn bytes(&self) -> &[u8] {
1120 self.as_bytes()
1121 }
1122
1123 fn id(&self) -> PciCapabilityID {
1124 PciCapabilityID::VendorSpecific
1125 }
1126
1127 fn writable_bits(&self) -> Vec<u32> {
1128 vec![0u32; 1]
1129 }
1130 }
1131
1132 #[test]
1133 fn add_capability() {
1134 let mut cfg = PciConfiguration::new(
1135 0x1234,
1136 0x5678,
1137 PciClassCode::MultimediaController,
1138 &PciMultimediaSubclass::AudioController,
1139 None,
1140 PciHeaderType::Device,
1141 0xABCD,
1142 0x2468,
1143 0,
1144 );
1145
1146 let cap1 = TestCap {
1148 _vndr: 0,
1149 _next: 0,
1150 len: 4,
1151 foo: 0xAA,
1152 };
1153 let cap1_offset = 64;
1154 cfg.add_capability(&cap1, None).unwrap();
1155
1156 let cap2 = TestCap {
1157 _vndr: 0,
1158 _next: 0,
1159 len: 0x04,
1160 foo: 0x55,
1161 };
1162 let cap2_offset = 68;
1163 cfg.add_capability(&cap2, None).unwrap();
1164
1165 let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
1167 assert_eq!(cap1_offset, cap_ptr as usize);
1168
1169 let cap1_data = cfg.read_reg(cap1_offset / 4);
1171 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);
1177 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); }
1182
1183 #[derive(Copy, Clone)]
1184 enum TestPI {
1185 Test = 0x5a,
1186 }
1187
1188 impl PciProgrammingInterface for TestPI {
1189 fn get_register_value(&self) -> u8 {
1190 *self as u8
1191 }
1192 }
1193
1194 #[test]
1195 fn class_code() {
1196 let cfg = PciConfiguration::new(
1197 0x1234,
1198 0x5678,
1199 PciClassCode::MultimediaController,
1200 &PciMultimediaSubclass::AudioController,
1201 Some(&TestPI::Test),
1202 PciHeaderType::Device,
1203 0xABCD,
1204 0x2468,
1205 0,
1206 );
1207
1208 let class_reg = cfg.read_reg(2);
1209 let class_code = (class_reg >> 24) & 0xFF;
1210 let subclass = (class_reg >> 16) & 0xFF;
1211 let prog_if = (class_reg >> 8) & 0xFF;
1212 assert_eq!(class_code, 0x04);
1213 assert_eq!(subclass, 0x01);
1214 assert_eq!(prog_if, 0x5a);
1215 }
1216
1217 #[test]
1218 fn read_only_bits() {
1219 let mut cfg = PciConfiguration::new(
1220 0x1234,
1221 0x5678,
1222 PciClassCode::MultimediaController,
1223 &PciMultimediaSubclass::AudioController,
1224 Some(&TestPI::Test),
1225 PciHeaderType::Device,
1226 0xABCD,
1227 0x2468,
1228 0,
1229 );
1230
1231 cfg.write_reg(0, 0, &[0xBA, 0xAD, 0xF0, 0x0D]);
1233 assert_eq!(cfg.read_reg(0), 0x56781234);
1235 }
1236
1237 #[test]
1238 fn query_unused_bar() {
1239 let cfg = PciConfiguration::new(
1240 0x1234,
1241 0x5678,
1242 PciClassCode::MultimediaController,
1243 &PciMultimediaSubclass::AudioController,
1244 Some(&TestPI::Test),
1245 PciHeaderType::Device,
1246 0xABCD,
1247 0x2468,
1248 0,
1249 );
1250
1251 assert_eq!(cfg.get_bar_type(0), None);
1253 assert_eq!(cfg.get_bar_addr(0), 0);
1254
1255 let mut bar_iter = cfg.get_bars();
1256 assert_eq!(bar_iter.next(), None);
1257 }
1258
1259 #[test]
1260 fn add_pci_bar_mem_64bit() {
1261 let mut cfg = PciConfiguration::new(
1262 0x1234,
1263 0x5678,
1264 PciClassCode::MultimediaController,
1265 &PciMultimediaSubclass::AudioController,
1266 Some(&TestPI::Test),
1267 PciHeaderType::Device,
1268 0xABCD,
1269 0x2468,
1270 0,
1271 );
1272
1273 cfg.add_pci_bar(
1274 PciBarConfiguration::new(
1275 0,
1276 0x10,
1277 PciBarRegionType::Memory64BitRegion,
1278 PciBarPrefetchable::NotPrefetchable,
1279 )
1280 .set_address(0x0123_4567_89AB_CDE0),
1281 )
1282 .expect("add_pci_bar failed");
1283
1284 assert_eq!(
1285 cfg.get_bar_type(0),
1286 Some(PciBarRegionType::Memory64BitRegion)
1287 );
1288 assert_eq!(cfg.get_bar_addr(0), 0x0123_4567_89AB_CDE0);
1289 assert_eq!(cfg.writable_bits[BAR0_REG + 1], 0xFFFFFFFF);
1290 assert_eq!(cfg.writable_bits[BAR0_REG + 0], 0xFFFFFFF0);
1291
1292 let mut bar_iter = cfg.get_bars();
1293 assert_eq!(
1294 bar_iter.next(),
1295 Some(PciBarConfiguration {
1296 addr: 0x0123_4567_89AB_CDE0,
1297 size: 0x10,
1298 bar_idx: 0,
1299 region_type: PciBarRegionType::Memory64BitRegion,
1300 prefetchable: PciBarPrefetchable::NotPrefetchable
1301 })
1302 );
1303 assert_eq!(bar_iter.next(), None);
1304 }
1305
1306 #[test]
1307 fn add_pci_bar_mem_32bit() {
1308 let mut cfg = PciConfiguration::new(
1309 0x1234,
1310 0x5678,
1311 PciClassCode::MultimediaController,
1312 &PciMultimediaSubclass::AudioController,
1313 Some(&TestPI::Test),
1314 PciHeaderType::Device,
1315 0xABCD,
1316 0x2468,
1317 0,
1318 );
1319
1320 cfg.add_pci_bar(
1321 PciBarConfiguration::new(
1322 0,
1323 0x10,
1324 PciBarRegionType::Memory32BitRegion,
1325 PciBarPrefetchable::NotPrefetchable,
1326 )
1327 .set_address(0x12345670),
1328 )
1329 .expect("add_pci_bar failed");
1330
1331 assert_eq!(
1332 cfg.get_bar_type(0),
1333 Some(PciBarRegionType::Memory32BitRegion)
1334 );
1335 assert_eq!(cfg.get_bar_addr(0), 0x12345670);
1336 assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFF0);
1337
1338 let mut bar_iter = cfg.get_bars();
1339 assert_eq!(
1340 bar_iter.next(),
1341 Some(PciBarConfiguration {
1342 addr: 0x12345670,
1343 size: 0x10,
1344 bar_idx: 0,
1345 region_type: PciBarRegionType::Memory32BitRegion,
1346 prefetchable: PciBarPrefetchable::NotPrefetchable
1347 })
1348 );
1349 assert_eq!(bar_iter.next(), None);
1350 }
1351
1352 #[test]
1353 fn add_pci_bar_io() {
1354 let mut cfg = PciConfiguration::new(
1355 0x1234,
1356 0x5678,
1357 PciClassCode::MultimediaController,
1358 &PciMultimediaSubclass::AudioController,
1359 Some(&TestPI::Test),
1360 PciHeaderType::Device,
1361 0xABCD,
1362 0x2468,
1363 0,
1364 );
1365
1366 cfg.add_pci_bar(
1367 PciBarConfiguration::new(
1368 0,
1369 0x4,
1370 PciBarRegionType::IoRegion,
1371 PciBarPrefetchable::NotPrefetchable,
1372 )
1373 .set_address(0x1230),
1374 )
1375 .expect("add_pci_bar failed");
1376
1377 assert_eq!(cfg.get_bar_type(0), Some(PciBarRegionType::IoRegion));
1378 assert_eq!(cfg.get_bar_addr(0), 0x1230);
1379 assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFFC);
1380
1381 let mut bar_iter = cfg.get_bars();
1382 assert_eq!(
1383 bar_iter.next(),
1384 Some(PciBarConfiguration {
1385 addr: 0x1230,
1386 size: 0x4,
1387 bar_idx: 0,
1388 region_type: PciBarRegionType::IoRegion,
1389 prefetchable: PciBarPrefetchable::NotPrefetchable
1390 })
1391 );
1392 assert_eq!(bar_iter.next(), None);
1393 }
1394
1395 #[test]
1396 fn add_pci_bar_multiple() {
1397 let mut cfg = PciConfiguration::new(
1398 0x1234,
1399 0x5678,
1400 PciClassCode::MultimediaController,
1401 &PciMultimediaSubclass::AudioController,
1402 Some(&TestPI::Test),
1403 PciHeaderType::Device,
1404 0xABCD,
1405 0x2468,
1406 0,
1407 );
1408
1409 cfg.add_pci_bar(
1411 PciBarConfiguration::new(
1412 0,
1413 0x10,
1414 PciBarRegionType::Memory64BitRegion,
1415 PciBarPrefetchable::NotPrefetchable,
1416 )
1417 .set_address(0x0123_4567_89AB_CDE0),
1418 )
1419 .expect("add_pci_bar failed");
1420
1421 cfg.add_pci_bar(
1423 PciBarConfiguration::new(
1424 2,
1425 0x10,
1426 PciBarRegionType::Memory32BitRegion,
1427 PciBarPrefetchable::NotPrefetchable,
1428 )
1429 .set_address(0x12345670),
1430 )
1431 .expect("add_pci_bar failed");
1432
1433 cfg.add_pci_bar(
1435 PciBarConfiguration::new(
1436 3,
1437 0x4,
1438 PciBarRegionType::IoRegion,
1439 PciBarPrefetchable::NotPrefetchable,
1440 )
1441 .set_address(0x1230),
1442 )
1443 .expect("add_pci_bar failed");
1444
1445 let mut bar_iter = cfg.get_bars();
1447 assert_eq!(
1448 bar_iter.next(),
1449 Some(PciBarConfiguration {
1450 addr: 0x0123_4567_89AB_CDE0,
1451 size: 0x10,
1452 bar_idx: 0,
1453 region_type: PciBarRegionType::Memory64BitRegion,
1454 prefetchable: PciBarPrefetchable::NotPrefetchable
1455 })
1456 );
1457 assert_eq!(
1458 bar_iter.next(),
1459 Some(PciBarConfiguration {
1460 addr: 0x12345670,
1461 size: 0x10,
1462 bar_idx: 2,
1463 region_type: PciBarRegionType::Memory32BitRegion,
1464 prefetchable: PciBarPrefetchable::NotPrefetchable
1465 })
1466 );
1467 assert_eq!(
1468 bar_iter.next(),
1469 Some(PciBarConfiguration {
1470 addr: 0x1230,
1471 size: 0x4,
1472 bar_idx: 3,
1473 region_type: PciBarRegionType::IoRegion,
1474 prefetchable: PciBarPrefetchable::NotPrefetchable
1475 })
1476 );
1477 assert_eq!(bar_iter.next(), None);
1478
1479 cfg.write_reg(4 + 0, 0, &0xBBAA9980u32.to_le_bytes());
1481 cfg.write_reg(4 + 1, 0, &0xFFEEDDCCu32.to_le_bytes());
1482
1483 let mut bar_iter = cfg.get_bars();
1484 assert_eq!(
1485 bar_iter.next(),
1486 Some(PciBarConfiguration {
1487 addr: 0xFFEE_DDCC_BBAA_9980,
1488 size: 0x10,
1489 bar_idx: 0,
1490 region_type: PciBarRegionType::Memory64BitRegion,
1491 prefetchable: PciBarPrefetchable::NotPrefetchable
1492 })
1493 );
1494 assert_eq!(
1495 bar_iter.next(),
1496 Some(PciBarConfiguration {
1497 addr: 0x12345670,
1498 size: 0x10,
1499 bar_idx: 2,
1500 region_type: PciBarRegionType::Memory32BitRegion,
1501 prefetchable: PciBarPrefetchable::NotPrefetchable
1502 })
1503 );
1504 assert_eq!(
1505 bar_iter.next(),
1506 Some(PciBarConfiguration {
1507 addr: 0x1230,
1508 size: 0x4,
1509 bar_idx: 3,
1510 region_type: PciBarRegionType::IoRegion,
1511 prefetchable: PciBarPrefetchable::NotPrefetchable
1512 })
1513 );
1514 assert_eq!(bar_iter.next(), None);
1515 }
1516
1517 #[test]
1518 fn add_pci_bar_invalid_size() {
1519 let mut cfg = PciConfiguration::new(
1520 0x1234,
1521 0x5678,
1522 PciClassCode::MultimediaController,
1523 &PciMultimediaSubclass::AudioController,
1524 Some(&TestPI::Test),
1525 PciHeaderType::Device,
1526 0xABCD,
1527 0x2468,
1528 0,
1529 );
1530
1531 assert_eq!(
1533 cfg.add_pci_bar(
1534 PciBarConfiguration::new(
1535 0,
1536 0x2,
1537 PciBarRegionType::IoRegion,
1538 PciBarPrefetchable::NotPrefetchable,
1539 )
1540 .set_address(0x1230),
1541 ),
1542 Err(Error::BarSizeInvalid(0x2))
1543 );
1544
1545 assert_eq!(
1547 cfg.add_pci_bar(
1548 PciBarConfiguration::new(
1549 0,
1550 0x3,
1551 PciBarRegionType::IoRegion,
1552 PciBarPrefetchable::NotPrefetchable,
1553 )
1554 .set_address(0x1230),
1555 ),
1556 Err(Error::BarSizeInvalid(0x3))
1557 );
1558
1559 assert_eq!(
1561 cfg.add_pci_bar(
1562 PciBarConfiguration::new(
1563 0,
1564 0x8,
1565 PciBarRegionType::Memory32BitRegion,
1566 PciBarPrefetchable::NotPrefetchable,
1567 )
1568 .set_address(0x12345670),
1569 ),
1570 Err(Error::BarSizeInvalid(0x8))
1571 );
1572 }
1573
1574 #[test]
1575 fn add_rom_bar() {
1576 let mut cfg = PciConfiguration::new(
1577 0x1234,
1578 0x5678,
1579 PciClassCode::MultimediaController,
1580 &PciMultimediaSubclass::AudioController,
1581 Some(&TestPI::Test),
1582 PciHeaderType::Device,
1583 0xABCD,
1584 0x2468,
1585 0,
1586 );
1587
1588 assert_eq!(
1590 cfg.add_pci_bar(PciBarConfiguration::new(
1591 ROM_BAR_IDX,
1592 0x1000,
1593 PciBarRegionType::Memory64BitRegion,
1594 PciBarPrefetchable::NotPrefetchable,
1595 ),),
1596 Err(Error::BarInvalidRomType)
1597 );
1598
1599 assert_eq!(
1601 cfg.add_pci_bar(PciBarConfiguration::new(
1602 ROM_BAR_IDX,
1603 0x1000,
1604 PciBarRegionType::IoRegion,
1605 PciBarPrefetchable::NotPrefetchable,
1606 ),),
1607 Err(Error::BarInvalidRomType)
1608 );
1609
1610 assert_eq!(
1612 cfg.add_pci_bar(PciBarConfiguration::new(
1613 ROM_BAR_IDX,
1614 1024,
1615 PciBarRegionType::Memory32BitRegion,
1616 PciBarPrefetchable::NotPrefetchable,
1617 ),),
1618 Err(Error::BarSizeInvalid(1024))
1619 );
1620
1621 cfg.add_pci_bar(
1623 PciBarConfiguration::new(
1624 ROM_BAR_IDX,
1625 0x800,
1626 PciBarRegionType::Memory32BitRegion,
1627 PciBarPrefetchable::NotPrefetchable,
1628 )
1629 .set_address(0x12345000),
1630 )
1631 .expect("add_pci_bar failed");
1632
1633 assert_eq!(
1634 cfg.get_bar_type(ROM_BAR_IDX),
1635 Some(PciBarRegionType::Memory32BitRegion)
1636 );
1637 assert_eq!(cfg.get_bar_addr(ROM_BAR_IDX), 0x12345000);
1638 assert_eq!(cfg.read_reg(ROM_BAR_REG), 0x12345000);
1639 assert_eq!(cfg.writable_bits[ROM_BAR_REG], 0xFFFFF801);
1640 }
1641
1642 #[test]
1643 fn pci_configuration_capability_snapshot_restore() -> anyhow::Result<()> {
1644 let mut cfg = PciConfiguration::new(
1645 0x1234,
1646 0x5678,
1647 PciClassCode::MultimediaController,
1648 &PciMultimediaSubclass::AudioController,
1649 Some(&TestPI::Test),
1650 PciHeaderType::Device,
1651 0xABCD,
1652 0x2468,
1653 0,
1654 );
1655
1656 let snap_init = cfg.snapshot().context("failed to snapshot")?;
1657
1658 let cap1 = TestCap {
1660 _vndr: 0,
1661 _next: 0,
1662 len: 4,
1663 foo: 0xAA,
1664 };
1665 cfg.add_capability(&cap1, None).unwrap();
1666
1667 let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1668 cfg.restore(snap_init.clone())
1669 .context("failed to restore snap_init")?;
1670 let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1671 assert_eq!(snap_init, snap_restore_init);
1672 assert_ne!(snap_init, snap_mod);
1673 cfg.restore(snap_mod.clone())
1674 .context("failed to restore snap_init")?;
1675 let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1676 assert_eq!(snap_mod, snap_restore_mod);
1677 Ok(())
1678 }
1679
1680 #[test]
1681 fn pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()> {
1682 let mut cfg = PciConfiguration::new(
1683 0x1234,
1684 0x5678,
1685 PciClassCode::MultimediaController,
1686 &PciMultimediaSubclass::AudioController,
1687 Some(&TestPI::Test),
1688 PciHeaderType::Device,
1689 0xABCD,
1690 0x2468,
1691 0,
1692 );
1693
1694 let snap_init = cfg.snapshot().context("failed to snapshot")?;
1695
1696 cfg.add_pci_bar(
1698 PciBarConfiguration::new(
1699 0,
1700 0x10,
1701 PciBarRegionType::Memory64BitRegion,
1702 PciBarPrefetchable::NotPrefetchable,
1703 )
1704 .set_address(0x0123_4567_89AB_CDE0),
1705 )
1706 .expect("add_pci_bar failed");
1707
1708 let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1709 cfg.restore(snap_init.clone())
1710 .context("failed to restore snap_init")?;
1711 let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1712 assert_eq!(snap_init, snap_restore_init);
1713 assert_ne!(snap_init, snap_mod);
1714 cfg.restore(snap_mod.clone())
1715 .context("failed to restore snap_init")?;
1716 let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1717 assert_eq!(snap_mod, snap_restore_mod);
1718 Ok(())
1719 }
1720
1721 #[test]
1722 fn pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()> {
1723 let mut cfg = PciConfiguration::new(
1724 0x1234,
1725 0x5678,
1726 PciClassCode::MultimediaController,
1727 &PciMultimediaSubclass::AudioController,
1728 Some(&TestPI::Test),
1729 PciHeaderType::Device,
1730 0xABCD,
1731 0x2468,
1732 0,
1733 );
1734
1735 let snap_init = cfg.snapshot().context("failed to snapshot")?;
1736
1737 let cap1 = TestCap {
1739 _vndr: 0,
1740 _next: 0,
1741 len: 4,
1742 foo: 0xAA,
1743 };
1744 cfg.add_capability(&cap1, None).unwrap();
1745
1746 cfg.add_pci_bar(
1748 PciBarConfiguration::new(
1749 0,
1750 0x10,
1751 PciBarRegionType::Memory64BitRegion,
1752 PciBarPrefetchable::NotPrefetchable,
1753 )
1754 .set_address(0x0123_4567_89AB_CDE0),
1755 )
1756 .expect("add_pci_bar failed");
1757
1758 let snap_mod = cfg.snapshot().context("failed to snapshot mod")?;
1759 cfg.restore(snap_init.clone())
1760 .context("failed to restore snap_init")?;
1761 let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?;
1762 assert_eq!(snap_init, snap_restore_init);
1763 assert_ne!(snap_init, snap_mod);
1764 cfg.restore(snap_mod.clone())
1765 .context("failed to restore snap_init")?;
1766 let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?;
1767 assert_eq!(snap_mod, snap_restore_mod);
1768 Ok(())
1769 }
1770}