1use crate::PciInterruptPin;
10use crate::bar_mapping::BarMappings;
11use crate::capabilities::PciCapability;
12use crate::spec::caps::CapabilityId;
13use crate::spec::cfg_space;
14use crate::spec::hwid::HardwareIds;
15use chipset_device::io::IoError;
16use chipset_device::io::IoResult;
17use chipset_device::mmio::ControlMmioIntercept;
18use guestmem::MappableGuestMemory;
19use inspect::Inspect;
20use std::ops::RangeInclusive;
21use std::sync::Arc;
22use std::sync::atomic::AtomicBool;
23use std::sync::atomic::Ordering;
24use vmcore::line_interrupt::LineInterrupt;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum HeaderType {
45 Type0,
47 Type1,
49}
50
51impl HeaderType {
52 pub const fn bar_count(self) -> usize {
54 match self {
55 HeaderType::Type0 => 6,
56 HeaderType::Type1 => 2,
57 }
58 }
59}
60
61impl From<HeaderType> for usize {
62 fn from(header_type: HeaderType) -> usize {
63 header_type.bar_count()
64 }
65}
66
67pub mod header_type_consts {
69 use super::HeaderType;
70
71 pub const TYPE0_BAR_COUNT: usize = HeaderType::Type0.bar_count();
73
74 pub const TYPE1_BAR_COUNT: usize = HeaderType::Type1.bar_count();
76}
77
78#[derive(Debug)]
80pub enum CommonHeaderResult {
81 Handled,
83 Unhandled,
85 Failed(IoError),
87}
88
89impl PartialEq for CommonHeaderResult {
90 fn eq(&self, other: &Self) -> bool {
91 match (self, other) {
92 (Self::Handled, Self::Handled) => true,
93 (Self::Unhandled, Self::Unhandled) => true,
94 (Self::Failed(_), Self::Failed(_)) => true, _ => false,
96 }
97 }
98}
99
100const SUPPORTED_COMMAND_BITS: u16 = cfg_space::Command::new()
101 .with_pio_enabled(true)
102 .with_mmio_enabled(true)
103 .with_bus_master(true)
104 .with_special_cycles(true)
105 .with_enable_memory_write_invalidate(true)
106 .with_vga_palette_snoop(true)
107 .with_parity_error_response(true)
108 .with_enable_serr(true)
109 .with_enable_fast_b2b(true)
110 .with_intx_disable(true)
111 .into_bits();
112
113#[derive(Debug, Inspect)]
116pub struct IntxInterrupt {
117 pin: PciInterruptPin,
118 line: LineInterrupt,
119 interrupt_disabled: AtomicBool,
120 interrupt_status: AtomicBool,
121}
122
123impl IntxInterrupt {
124 pub fn set_level(&self, high: bool) {
129 tracing::debug!(
130 disabled = ?self.interrupt_disabled,
131 status = ?self.interrupt_status,
132 ?high,
133 %self.line,
134 "set_level"
135 );
136
137 self.interrupt_status.store(high, Ordering::SeqCst);
139
140 if self.interrupt_disabled.load(Ordering::SeqCst) {
142 self.line.set_level(false);
143 } else {
144 self.line.set_level(high);
145 }
146 }
147
148 fn set_disabled(&self, disabled: bool) {
149 tracing::debug!(
150 disabled = ?self.interrupt_disabled,
151 status = ?self.interrupt_status,
152 ?disabled,
153 %self.line,
154 "set_disabled"
155 );
156
157 self.interrupt_disabled.store(disabled, Ordering::SeqCst);
158 if disabled {
159 self.line.set_level(false)
160 } else {
161 if self.interrupt_status.load(Ordering::SeqCst) {
162 self.line.set_level(true)
163 }
164 }
165 }
166}
167
168#[derive(Debug, Inspect)]
169struct ConfigSpaceCommonHeaderEmulatorState<const N: usize> {
170 command: cfg_space::Command,
172 #[inspect(with = "inspect_helpers::bars_generic")]
174 base_addresses: [u32; N],
175 interrupt_line: u8,
180}
181
182impl<const N: usize> ConfigSpaceCommonHeaderEmulatorState<N> {
183 fn new() -> Self {
184 Self {
185 command: cfg_space::Command::new(),
186 base_addresses: {
187 const ZERO: u32 = 0;
188 [ZERO; N]
189 },
190 interrupt_line: 0,
191 }
192 }
193}
194
195#[derive(Inspect)]
198pub struct ConfigSpaceCommonHeaderEmulator<const N: usize> {
199 #[inspect(with = "inspect_helpers::bars_generic")]
201 bar_masks: [u32; N],
202 hardware_ids: HardwareIds,
203 multi_function_bit: bool,
204
205 #[inspect(with = r#"|x| inspect::iter_by_index(x).prefix("bar")"#)]
207 mapped_memory: [Option<BarMemoryKind>; N],
208 #[inspect(with = "|x| inspect::iter_by_key(x.iter().map(|cap| (cap.label(), cap)))")]
209 capabilities: Vec<Box<dyn PciCapability>>,
210 intx_interrupt: Option<Arc<IntxInterrupt>>,
211
212 active_bars: BarMappings,
214
215 state: ConfigSpaceCommonHeaderEmulatorState<N>,
217}
218
219pub type ConfigSpaceCommonHeaderEmulatorType0 =
221 ConfigSpaceCommonHeaderEmulator<{ header_type_consts::TYPE0_BAR_COUNT }>;
222
223pub type ConfigSpaceCommonHeaderEmulatorType1 =
225 ConfigSpaceCommonHeaderEmulator<{ header_type_consts::TYPE1_BAR_COUNT }>;
226
227impl<const N: usize> ConfigSpaceCommonHeaderEmulator<N> {
228 pub fn new(
230 hardware_ids: HardwareIds,
231 capabilities: Vec<Box<dyn PciCapability>>,
232 bars: DeviceBars,
233 ) -> Self {
234 let mut bar_masks = {
235 const ZERO: u32 = 0;
236 [ZERO; N]
237 };
238 let mut mapped_memory = {
239 const NONE: Option<BarMemoryKind> = None;
240 [NONE; N]
241 };
242
243 for (bar_index, bar) in bars.bars.into_iter().enumerate().take(N) {
245 let (len, mapped) = match bar {
246 Some(bar) => bar,
247 None => continue,
248 };
249 assert!(bar_index < N.saturating_sub(1));
251 const MIN_BAR_SIZE: u64 = 4096;
255 let len = std::cmp::max(len.next_power_of_two(), MIN_BAR_SIZE);
256 let mask64 = !(len - 1);
257 bar_masks[bar_index] = cfg_space::BarEncodingBits::from_bits(mask64 as u32)
258 .with_type_64_bit(true)
259 .into_bits();
260 if bar_index + 1 < N {
261 bar_masks[bar_index + 1] = (mask64 >> 32) as u32;
262 }
263 mapped_memory[bar_index] = Some(mapped);
264 }
265
266 Self {
267 hardware_ids,
268 capabilities,
269 bar_masks,
270 mapped_memory,
271 multi_function_bit: false,
272 intx_interrupt: None,
273 active_bars: Default::default(),
274 state: ConfigSpaceCommonHeaderEmulatorState::new(),
275 }
276 }
277
278 pub const fn bar_count(&self) -> usize {
280 N
281 }
282
283 pub fn validate_header_type(&self, expected: HeaderType) -> bool {
285 N == expected.bar_count()
286 }
287
288 pub fn with_multi_function_bit(mut self, bit: bool) -> Self {
290 self.multi_function_bit = bit;
291 self
292 }
293
294 pub fn set_interrupt_pin(
298 &mut self,
299 pin: PciInterruptPin,
300 line: LineInterrupt,
301 ) -> Arc<IntxInterrupt> {
302 let intx_interrupt = Arc::new(IntxInterrupt {
303 pin,
304 line,
305 interrupt_disabled: AtomicBool::new(false),
306 interrupt_status: AtomicBool::new(false),
307 });
308 self.intx_interrupt = Some(intx_interrupt.clone());
309 intx_interrupt
310 }
311
312 pub fn reset(&mut self) {
314 tracing::info!("ConfigSpaceCommonHeaderEmulator: resetting state");
315 self.state = ConfigSpaceCommonHeaderEmulatorState::new();
316
317 tracing::info!("ConfigSpaceCommonHeaderEmulator: syncing command register after reset");
318 self.sync_command_register(self.state.command);
319
320 tracing::info!(
321 "ConfigSpaceCommonHeaderEmulator: resetting {} capabilities",
322 self.capabilities.len()
323 );
324 for cap in &mut self.capabilities {
325 cap.reset();
326 }
327
328 if let Some(intx) = &mut self.intx_interrupt {
329 tracing::info!("ConfigSpaceCommonHeaderEmulator: resetting interrupt level");
330 intx.set_level(false);
331 }
332 tracing::info!("ConfigSpaceCommonHeaderEmulator: reset completed");
333 }
334
335 pub fn hardware_ids(&self) -> &HardwareIds {
337 &self.hardware_ids
338 }
339
340 pub fn capabilities(&self) -> &[Box<dyn PciCapability>] {
342 &self.capabilities
343 }
344
345 pub fn capabilities_mut(&mut self) -> &mut [Box<dyn PciCapability>] {
347 &mut self.capabilities
348 }
349
350 pub fn multi_function_bit(&self) -> bool {
352 self.multi_function_bit
353 }
354
355 pub const fn header_type(&self) -> HeaderType {
357 match N {
358 header_type_consts::TYPE0_BAR_COUNT => HeaderType::Type0,
359 header_type_consts::TYPE1_BAR_COUNT => HeaderType::Type1,
360 _ => panic!("Unsupported BAR count - must be 6 (Type0) or 2 (Type1)"),
361 }
362 }
363
364 pub fn command(&self) -> cfg_space::Command {
366 self.state.command
367 }
368
369 pub fn base_addresses(&self) -> &[u32; N] {
371 &self.state.base_addresses
372 }
373
374 pub fn interrupt_line(&self) -> u8 {
376 self.state.interrupt_line
377 }
378
379 pub fn interrupt_pin(&self) -> u8 {
381 if let Some(intx) = &self.intx_interrupt {
382 (intx.pin as u8) + 1 } else {
384 0 }
386 }
387
388 pub fn set_interrupt_line(&mut self, interrupt_line: u8) {
390 self.state.interrupt_line = interrupt_line;
391 }
392
393 pub fn set_base_addresses(&mut self, base_addresses: &[u32; N]) {
395 self.state.base_addresses = *base_addresses;
396 }
397
398 pub fn set_command(&mut self, command: cfg_space::Command) {
400 self.state.command = command;
401 }
402
403 pub fn sync_command_register(&mut self, command: cfg_space::Command) {
405 tracing::info!(
406 "ConfigSpaceCommonHeaderEmulator: syncing command register - intx_disable={}, mmio_enabled={}",
407 command.intx_disable(),
408 command.mmio_enabled()
409 );
410 self.update_intx_disable(command.intx_disable());
411 self.update_mmio_enabled(command.mmio_enabled());
412 }
413
414 pub fn update_intx_disable(&mut self, disabled: bool) {
416 tracing::info!(
417 "ConfigSpaceCommonHeaderEmulator: updating intx_disable={}",
418 disabled
419 );
420 if let Some(intx_interrupt) = &self.intx_interrupt {
421 intx_interrupt.set_disabled(disabled)
422 }
423 }
424
425 pub fn update_mmio_enabled(&mut self, enabled: bool) {
427 tracing::info!(
428 "ConfigSpaceCommonHeaderEmulator: updating mmio_enabled={}",
429 enabled
430 );
431 if enabled {
432 let mut full_base_addresses = [0u32; 6];
435 let mut full_bar_masks = [0u32; 6];
436
437 full_base_addresses[..N].copy_from_slice(&self.state.base_addresses[..N]);
439 full_bar_masks[..N].copy_from_slice(&self.bar_masks[..N]);
440
441 self.active_bars = BarMappings::parse(&full_base_addresses, &full_bar_masks);
442 for (bar, mapping) in self.mapped_memory.iter_mut().enumerate() {
443 if let Some(mapping) = mapping {
444 let base = self.active_bars.get(bar as u8).expect("bar exists");
445 match mapping.map_to_guest(base) {
446 Ok(_) => {}
447 Err(err) => {
448 tracelimit::error_ratelimited!(
449 error = &err as &dyn std::error::Error,
450 bar,
451 base,
452 "failed to map bar",
453 )
454 }
455 }
456 }
457 }
458 } else {
459 self.active_bars = Default::default();
460 for mapping in self.mapped_memory.iter_mut().flatten() {
461 mapping.unmap_from_guest();
462 }
463 }
464 }
465
466 pub fn read_u32(&self, offset: u16, value: &mut u32) -> CommonHeaderResult {
471 use cfg_space::CommonHeader;
472
473 tracing::trace!(
474 "ConfigSpaceCommonHeaderEmulator: read_u32 offset={:#x}",
475 offset
476 );
477
478 *value = match CommonHeader(offset) {
479 CommonHeader::DEVICE_VENDOR => {
480 (self.hardware_ids.device_id as u32) << 16 | self.hardware_ids.vendor_id as u32
481 }
482 CommonHeader::STATUS_COMMAND => {
483 let mut status =
484 cfg_space::Status::new().with_capabilities_list(!self.capabilities.is_empty());
485
486 if let Some(intx_interrupt) = &self.intx_interrupt {
487 if intx_interrupt.interrupt_status.load(Ordering::SeqCst) {
488 status.set_interrupt_status(true);
489 }
490 }
491
492 (status.into_bits() as u32) << 16 | self.state.command.into_bits() as u32
493 }
494 CommonHeader::CLASS_REVISION => {
495 (u8::from(self.hardware_ids.base_class) as u32) << 24
496 | (u8::from(self.hardware_ids.sub_class) as u32) << 16
497 | (u8::from(self.hardware_ids.prog_if) as u32) << 8
498 | self.hardware_ids.revision_id as u32
499 }
500 CommonHeader::RESERVED_CAP_PTR => {
501 if self.capabilities.is_empty() {
502 0
503 } else {
504 0x40
505 }
506 }
507 _ if (0x40..0x100).contains(&offset) => {
509 return self.read_capabilities(offset, value);
510 }
511 _ if (0x100..0x1000).contains(&offset) => {
513 return self.read_extended_capabilities(offset, value);
514 }
515 _ if self.is_bar_offset(offset) => {
517 return self.read_bar(offset, value);
518 }
519 _ => {
521 return CommonHeaderResult::Unhandled;
522 }
523 };
524
525 tracing::trace!(
526 "ConfigSpaceCommonHeaderEmulator: read_u32 offset={:#x} -> value={:#x}",
527 offset,
528 *value
529 );
530 CommonHeaderResult::Handled
532 }
533
534 pub fn write_u32(&mut self, offset: u16, val: u32) -> CommonHeaderResult {
537 use cfg_space::CommonHeader;
538
539 tracing::trace!(
540 "ConfigSpaceCommonHeaderEmulator: write_u32 offset={:#x} val={:#x}",
541 offset,
542 val
543 );
544
545 match CommonHeader(offset) {
546 CommonHeader::STATUS_COMMAND => {
547 let mut command = cfg_space::Command::from_bits(val as u16);
548 if command.into_bits() & !SUPPORTED_COMMAND_BITS != 0 {
549 tracelimit::warn_ratelimited!(offset, val, "setting invalid command bits");
550 command =
552 cfg_space::Command::from_bits(command.into_bits() & SUPPORTED_COMMAND_BITS);
553 };
554
555 if self.state.command.intx_disable() != command.intx_disable() {
556 self.update_intx_disable(command.intx_disable())
557 }
558
559 if self.state.command.mmio_enabled() != command.mmio_enabled() {
560 self.update_mmio_enabled(command.mmio_enabled())
561 }
562
563 self.state.command = command;
564 }
565 _ if (0x40..0x100).contains(&offset) => {
567 return self.write_capabilities(offset, val);
568 }
569 _ if (0x100..0x1000).contains(&offset) => {
571 return self.write_extended_capabilities(offset, val);
572 }
573 _ if self.is_bar_offset(offset) => {
575 return self.write_bar(offset, val);
576 }
577 _ => {
579 return CommonHeaderResult::Unhandled;
580 }
581 }
582
583 CommonHeaderResult::Handled
585 }
586
587 fn read_bar(&self, offset: u16, value: &mut u32) -> CommonHeaderResult {
589 if !self.is_bar_offset(offset) {
590 return CommonHeaderResult::Unhandled;
591 }
592
593 let bar_index = self.get_bar_index(offset);
594 if bar_index < N {
595 *value = self.state.base_addresses[bar_index];
596 } else {
597 *value = 0;
598 }
599 CommonHeaderResult::Handled
600 }
601
602 fn write_bar(&mut self, offset: u16, val: u32) -> CommonHeaderResult {
604 if !self.is_bar_offset(offset) {
605 return CommonHeaderResult::Unhandled;
606 }
607
608 if !self.state.command.mmio_enabled() {
610 let bar_index = self.get_bar_index(offset);
611 if bar_index < N {
612 let mut bar_value = val & self.bar_masks[bar_index];
613
614 if bar_index & 1 == 0 && self.bar_masks[bar_index] != 0 {
616 bar_value = cfg_space::BarEncodingBits::from_bits(bar_value)
617 .with_type_64_bit(true)
618 .into_bits();
619 }
620
621 self.state.base_addresses[bar_index] = bar_value;
622 }
623 }
624 CommonHeaderResult::Handled
625 }
626
627 fn read_capabilities(&self, offset: u16, value: &mut u32) -> CommonHeaderResult {
629 if (0x40..0x100).contains(&offset) {
630 if let Some((cap_index, cap_offset)) =
631 self.get_capability_index_and_offset(offset - 0x40)
632 {
633 *value = self.capabilities[cap_index].read_u32(cap_offset);
634 if cap_offset == 0 {
635 let next = if cap_index < self.capabilities.len() - 1 {
636 offset as u32 + self.capabilities[cap_index].len() as u32
637 } else {
638 0
639 };
640 assert!(*value & 0xff00 == 0);
641 *value |= next << 8;
642 }
643 CommonHeaderResult::Handled
644 } else {
645 tracelimit::warn_ratelimited!(offset, "unhandled config space read");
646 CommonHeaderResult::Failed(IoError::InvalidRegister)
647 }
648 } else {
649 CommonHeaderResult::Failed(IoError::InvalidRegister)
650 }
651 }
652
653 fn write_capabilities(&mut self, offset: u16, val: u32) -> CommonHeaderResult {
655 if (0x40..0x100).contains(&offset) {
656 if let Some((cap_index, cap_offset)) =
657 self.get_capability_index_and_offset(offset - 0x40)
658 {
659 self.capabilities[cap_index].write_u32(cap_offset, val);
660 CommonHeaderResult::Handled
661 } else {
662 tracelimit::warn_ratelimited!(offset, value = val, "unhandled config space write");
663 CommonHeaderResult::Failed(IoError::InvalidRegister)
664 }
665 } else {
666 CommonHeaderResult::Failed(IoError::InvalidRegister)
667 }
668 }
669
670 fn read_extended_capabilities(&self, offset: u16, value: &mut u32) -> CommonHeaderResult {
672 if (0x100..0x1000).contains(&offset) {
673 if self.is_pcie_device() {
674 *value = 0xffffffff;
675 CommonHeaderResult::Handled
676 } else {
677 tracelimit::warn_ratelimited!(offset, "unhandled extended config space read");
678 CommonHeaderResult::Failed(IoError::InvalidRegister)
679 }
680 } else {
681 CommonHeaderResult::Failed(IoError::InvalidRegister)
682 }
683 }
684
685 fn write_extended_capabilities(&mut self, offset: u16, val: u32) -> CommonHeaderResult {
687 if (0x100..0x1000).contains(&offset) {
688 if self.is_pcie_device() {
689 CommonHeaderResult::Handled
691 } else {
692 tracelimit::warn_ratelimited!(
693 offset,
694 value = val,
695 "unhandled extended config space write"
696 );
697 CommonHeaderResult::Failed(IoError::InvalidRegister)
698 }
699 } else {
700 CommonHeaderResult::Failed(IoError::InvalidRegister)
701 }
702 }
703
704 pub fn find_bar(&self, address: u64) -> Option<(u8, u16)> {
708 self.active_bars.find(address)
709 }
710
711 pub fn is_pcie_device(&self) -> bool {
713 self.capabilities
714 .iter()
715 .any(|cap| cap.capability_id() == CapabilityId::PCI_EXPRESS)
716 }
717
718 fn get_capability_index_and_offset(&self, offset: u16) -> Option<(usize, u16)> {
720 let mut cap_offset = 0;
721 for i in 0..self.capabilities.len() {
722 let cap_size = self.capabilities[i].len() as u16;
723 if offset < cap_offset + cap_size {
724 return Some((i, offset - cap_offset));
725 }
726 cap_offset += cap_size;
727 }
728 None
729 }
730
731 fn is_bar_offset(&self, offset: u16) -> bool {
733 let bar_start = cfg_space::HeaderType00::BAR0.0;
735 let bar_end = bar_start + (N as u16) * 4;
736 (bar_start..bar_end).contains(&offset) && offset.is_multiple_of(4)
737 }
738
739 fn get_bar_index(&self, offset: u16) -> usize {
741 ((offset - cfg_space::HeaderType00::BAR0.0) / 4) as usize
742 }
743
744 #[cfg(test)]
746 pub fn bar_masks(&self) -> &[u32; N] {
747 &self.bar_masks
748 }
749}
750
751#[derive(Debug, Inspect)]
752struct ConfigSpaceType0EmulatorState {
753 latency_timer: u8,
755}
756
757impl ConfigSpaceType0EmulatorState {
758 fn new() -> Self {
759 Self { latency_timer: 0 }
760 }
761}
762
763#[derive(Inspect)]
765pub struct ConfigSpaceType0Emulator {
766 #[inspect(flatten)]
768 common: ConfigSpaceCommonHeaderEmulatorType0,
769 state: ConfigSpaceType0EmulatorState,
771}
772
773mod inspect_helpers {
774 use super::*;
775
776 pub(crate) fn bars_generic<const N: usize>(bars: &[u32; N]) -> impl Inspect + '_ {
777 inspect::AsHex(inspect::iter_by_index(bars).prefix("bar"))
778 }
779}
780
781#[derive(Inspect)]
783#[inspect(tag = "kind")]
784pub enum BarMemoryKind {
785 Intercept(#[inspect(rename = "handle")] Box<dyn ControlMmioIntercept>),
787 SharedMem(#[inspect(skip)] Box<dyn MappableGuestMemory>),
789 Dummy,
791}
792
793impl std::fmt::Debug for BarMemoryKind {
794 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
795 match self {
796 Self::Intercept(control) => {
797 write!(f, "Intercept(region_name: {}, ..)", control.region_name())
798 }
799 Self::SharedMem(_) => write!(f, "Mmap(..)"),
800 Self::Dummy => write!(f, "Dummy"),
801 }
802 }
803}
804
805impl BarMemoryKind {
806 fn map_to_guest(&mut self, gpa: u64) -> std::io::Result<()> {
807 match self {
808 BarMemoryKind::Intercept(control) => {
809 control.map(gpa);
810 Ok(())
811 }
812 BarMemoryKind::SharedMem(control) => control.map_to_guest(gpa, true),
813 BarMemoryKind::Dummy => Ok(()),
814 }
815 }
816
817 fn unmap_from_guest(&mut self) {
818 match self {
819 BarMemoryKind::Intercept(control) => control.unmap(),
820 BarMemoryKind::SharedMem(control) => control.unmap_from_guest(),
821 BarMemoryKind::Dummy => {}
822 }
823 }
824}
825
826#[derive(Debug)]
831pub struct DeviceBars {
832 bars: [Option<(u64, BarMemoryKind)>; 6],
833}
834
835impl DeviceBars {
836 pub fn new() -> DeviceBars {
838 DeviceBars {
839 bars: Default::default(),
840 }
841 }
842
843 pub fn bar0(mut self, len: u64, memory: BarMemoryKind) -> Self {
845 self.bars[0] = Some((len, memory));
846 self
847 }
848
849 pub fn bar2(mut self, len: u64, memory: BarMemoryKind) -> Self {
851 self.bars[2] = Some((len, memory));
852 self
853 }
854
855 pub fn bar4(mut self, len: u64, memory: BarMemoryKind) -> Self {
857 self.bars[4] = Some((len, memory));
858 self
859 }
860}
861
862impl ConfigSpaceType0Emulator {
863 pub fn new(
865 hardware_ids: HardwareIds,
866 capabilities: Vec<Box<dyn PciCapability>>,
867 bars: DeviceBars,
868 ) -> Self {
869 let common = ConfigSpaceCommonHeaderEmulator::new(hardware_ids, capabilities, bars);
870
871 Self {
872 common,
873 state: ConfigSpaceType0EmulatorState::new(),
874 }
875 }
876
877 pub fn with_multi_function_bit(mut self, bit: bool) -> Self {
879 self.common = self.common.with_multi_function_bit(bit);
880 self
881 }
882
883 pub fn set_interrupt_pin(
887 &mut self,
888 pin: PciInterruptPin,
889 line: LineInterrupt,
890 ) -> Arc<IntxInterrupt> {
891 self.common.set_interrupt_pin(pin, line)
892 }
893
894 pub fn reset(&mut self) {
896 self.common.reset();
897 self.state = ConfigSpaceType0EmulatorState::new();
898 }
899
900 pub fn read_u32(&self, offset: u16, value: &mut u32) -> IoResult {
902 use cfg_space::HeaderType00;
903
904 match self.common.read_u32(offset, value) {
906 CommonHeaderResult::Handled => return IoResult::Ok,
907 CommonHeaderResult::Failed(err) => return IoResult::Err(err),
908 CommonHeaderResult::Unhandled => {
909 }
911 }
912
913 *value = match HeaderType00(offset) {
915 HeaderType00::BIST_HEADER => {
916 let mut v = (self.state.latency_timer as u32) << 8;
917 if self.common.multi_function_bit() {
918 v |= 0x80 << 16;
920 }
921 v
922 }
923 HeaderType00::CARDBUS_CIS_PTR => 0,
924 HeaderType00::SUBSYSTEM_ID => {
925 (self.common.hardware_ids().type0_sub_system_id as u32) << 16
926 | self.common.hardware_ids().type0_sub_vendor_id as u32
927 }
928 HeaderType00::EXPANSION_ROM_BASE => 0,
929 HeaderType00::RESERVED => 0,
930 HeaderType00::LATENCY_INTERRUPT => {
931 (self.state.latency_timer as u32) << 16
933 | (self.common.interrupt_pin() as u32) << 8
934 | self.common.interrupt_line() as u32
935 }
936 _ => {
937 tracelimit::warn_ratelimited!(offset, "unexpected config space read");
938 return IoResult::Err(IoError::InvalidRegister);
939 }
940 };
941
942 IoResult::Ok
943 }
944
945 pub fn write_u32(&mut self, offset: u16, val: u32) -> IoResult {
947 use cfg_space::HeaderType00;
948
949 match self.common.write_u32(offset, val) {
951 CommonHeaderResult::Handled => return IoResult::Ok,
952 CommonHeaderResult::Failed(err) => return IoResult::Err(err),
953 CommonHeaderResult::Unhandled => {
954 }
956 }
957
958 match HeaderType00(offset) {
960 HeaderType00::BIST_HEADER => {
961 }
964 HeaderType00::LATENCY_INTERRUPT => {
965 self.common.set_interrupt_line((val & 0xff) as u8);
969 self.state.latency_timer = (val >> 16) as u8;
970 }
971 _ if offset < 0x40 && offset.is_multiple_of(4) => (),
973 _ => {
974 tracelimit::warn_ratelimited!(offset, value = val, "unexpected config space write");
975 return IoResult::Err(IoError::InvalidRegister);
976 }
977 }
978
979 IoResult::Ok
980 }
981
982 pub fn find_bar(&self, address: u64) -> Option<(u8, u16)> {
984 self.common.find_bar(address)
985 }
986
987 pub fn is_pcie_device(&self) -> bool {
989 self.common.is_pcie_device()
990 }
991
992 pub fn set_presence_detect_state(&mut self, present: bool) {
999 for capability in self.common.capabilities_mut() {
1000 if let Some(pcie_cap) = capability.as_pci_express_mut() {
1001 pcie_cap.set_presence_detect_state(present);
1002 return;
1003 }
1004 }
1005
1006 }
1008}
1009
1010#[derive(Debug, Inspect)]
1011struct ConfigSpaceType1EmulatorState {
1012 subordinate_bus_number: u8,
1015 secondary_bus_number: u8,
1019 primary_bus_number: u8,
1022 memory_base: u16,
1026 memory_limit: u16,
1030 prefetch_base: u16,
1035 prefetch_limit: u16,
1040 prefetch_base_upper: u32,
1045 prefetch_limit_upper: u32,
1050 bridge_control: u16,
1053}
1054
1055impl ConfigSpaceType1EmulatorState {
1056 fn new() -> Self {
1057 Self {
1058 subordinate_bus_number: 0,
1059 secondary_bus_number: 0,
1060 primary_bus_number: 0,
1061 memory_base: 0,
1062 memory_limit: 0,
1063 prefetch_base: 0,
1064 prefetch_limit: 0,
1065 prefetch_base_upper: 0,
1066 prefetch_limit_upper: 0,
1067 bridge_control: 0,
1068 }
1069 }
1070}
1071
1072#[derive(Inspect)]
1074pub struct ConfigSpaceType1Emulator {
1075 #[inspect(flatten)]
1077 common: ConfigSpaceCommonHeaderEmulatorType1,
1078 state: ConfigSpaceType1EmulatorState,
1080}
1081
1082impl ConfigSpaceType1Emulator {
1083 pub fn new(hardware_ids: HardwareIds, capabilities: Vec<Box<dyn PciCapability>>) -> Self {
1085 let common =
1086 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, capabilities, DeviceBars::new());
1087
1088 Self {
1089 common,
1090 state: ConfigSpaceType1EmulatorState::new(),
1091 }
1092 }
1093
1094 pub fn reset(&mut self) {
1096 self.common.reset();
1097 self.state = ConfigSpaceType1EmulatorState::new();
1098 }
1099
1100 pub fn with_multi_function_bit(mut self, multi_function: bool) -> Self {
1102 self.common = self.common.with_multi_function_bit(multi_function);
1103 self
1104 }
1105
1106 pub fn assigned_bus_range(&self) -> RangeInclusive<u8> {
1108 let secondary = self.state.secondary_bus_number;
1109 let subordinate = self.state.subordinate_bus_number;
1110 if secondary <= subordinate {
1111 secondary..=subordinate
1112 } else {
1113 0..=0
1114 }
1115 }
1116
1117 fn decode_memory_range(&self, base_register: u16, limit_register: u16) -> (u32, u32) {
1118 let base_addr = ((base_register & !0b1111) as u32) << 16;
1119 let limit_addr = ((limit_register & !0b1111) as u32) << 16 | 0xF_FFFF;
1120 (base_addr, limit_addr)
1121 }
1122
1123 pub fn assigned_memory_range(&self) -> Option<RangeInclusive<u32>> {
1126 let (base_addr, limit_addr) =
1127 self.decode_memory_range(self.state.memory_base, self.state.memory_limit);
1128 if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1129 Some(base_addr..=limit_addr)
1130 } else {
1131 None
1132 }
1133 }
1134
1135 pub fn assigned_prefetch_range(&self) -> Option<RangeInclusive<u64>> {
1138 let (base_low, limit_low) =
1139 self.decode_memory_range(self.state.prefetch_base, self.state.prefetch_limit);
1140 let base_addr = (self.state.prefetch_base_upper as u64) << 32 | base_low as u64;
1141 let limit_addr = (self.state.prefetch_limit_upper as u64) << 32 | limit_low as u64;
1142 if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1143 Some(base_addr..=limit_addr)
1144 } else {
1145 None
1146 }
1147 }
1148
1149 pub fn read_u32(&self, offset: u16, value: &mut u32) -> IoResult {
1151 use cfg_space::HeaderType01;
1152
1153 match self.common.read_u32(offset, value) {
1155 CommonHeaderResult::Handled => return IoResult::Ok,
1156 CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1157 CommonHeaderResult::Unhandled => {
1158 }
1160 }
1161
1162 *value = match HeaderType01(offset) {
1164 HeaderType01::BIST_HEADER => {
1165 if self.common.multi_function_bit() {
1167 0x00810000 } else {
1169 0x00010000 }
1171 }
1172 HeaderType01::LATENCY_BUS_NUMBERS => {
1173 (self.state.subordinate_bus_number as u32) << 16
1174 | (self.state.secondary_bus_number as u32) << 8
1175 | self.state.primary_bus_number as u32
1176 }
1177 HeaderType01::SEC_STATUS_IO_RANGE => 0,
1178 HeaderType01::MEMORY_RANGE => {
1179 (self.state.memory_limit as u32) << 16 | self.state.memory_base as u32
1180 }
1181 HeaderType01::PREFETCH_RANGE => {
1182 ((self.state.prefetch_limit | 0b0001) as u32) << 16
1185 | (self.state.prefetch_base | 0b0001) as u32
1186 }
1187 HeaderType01::PREFETCH_BASE_UPPER => self.state.prefetch_base_upper,
1188 HeaderType01::PREFETCH_LIMIT_UPPER => self.state.prefetch_limit_upper,
1189 HeaderType01::IO_RANGE_UPPER => 0,
1190 HeaderType01::EXPANSION_ROM_BASE => 0,
1191 HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1192 (self.state.bridge_control as u32) << 16 | self.common.interrupt_line() as u32
1195 }
1196 _ => {
1197 tracelimit::warn_ratelimited!(offset, "unexpected config space read");
1198 return IoResult::Err(IoError::InvalidRegister);
1199 }
1200 };
1201
1202 IoResult::Ok
1203 }
1204
1205 pub fn write_u32(&mut self, offset: u16, val: u32) -> IoResult {
1207 use cfg_space::HeaderType01;
1208
1209 match self.common.write_u32(offset, val) {
1211 CommonHeaderResult::Handled => return IoResult::Ok,
1212 CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1213 CommonHeaderResult::Unhandled => {
1214 }
1216 }
1217
1218 match HeaderType01(offset) {
1220 HeaderType01::BIST_HEADER => {
1221 }
1224 HeaderType01::LATENCY_BUS_NUMBERS => {
1225 self.state.subordinate_bus_number = (val >> 16) as u8;
1226 self.state.secondary_bus_number = (val >> 8) as u8;
1227 self.state.primary_bus_number = val as u8;
1228 }
1229 HeaderType01::MEMORY_RANGE => {
1230 self.state.memory_base = val as u16;
1231 self.state.memory_limit = (val >> 16) as u16;
1232 }
1233 HeaderType01::PREFETCH_RANGE => {
1234 self.state.prefetch_base = val as u16;
1235 self.state.prefetch_limit = (val >> 16) as u16;
1236 }
1237 HeaderType01::PREFETCH_BASE_UPPER => {
1238 self.state.prefetch_base_upper = val;
1239 }
1240 HeaderType01::PREFETCH_LIMIT_UPPER => {
1241 self.state.prefetch_limit_upper = val;
1242 }
1243 HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1244 self.common.set_interrupt_line((val & 0xff) as u8);
1247 self.state.bridge_control = (val >> 16) as u16;
1248 }
1249 _ if offset < 0x40 && offset.is_multiple_of(4) => (),
1251 _ => {
1252 tracelimit::warn_ratelimited!(offset, value = val, "unexpected config space write");
1253 return IoResult::Err(IoError::InvalidRegister);
1254 }
1255 }
1256
1257 IoResult::Ok
1258 }
1259
1260 pub fn is_pcie_device(&self) -> bool {
1262 self.common.is_pcie_device()
1263 }
1264
1265 pub fn set_presence_detect_state(&mut self, present: bool) {
1272 for cap in self.common.capabilities_mut() {
1274 if cap.capability_id() == CapabilityId::PCI_EXPRESS {
1275 if let Some(pcie_cap) = cap.as_pci_express_mut() {
1277 pcie_cap.set_presence_detect_state(present);
1278 return;
1279 }
1280 }
1281 }
1282 }
1284}
1285
1286mod save_restore {
1287 use super::*;
1288 use thiserror::Error;
1289 use vmcore::save_restore::RestoreError;
1290 use vmcore::save_restore::SaveError;
1291 use vmcore::save_restore::SaveRestore;
1292
1293 mod state {
1294 use mesh::payload::Protobuf;
1295 use vmcore::save_restore::SavedStateBlob;
1296 use vmcore::save_restore::SavedStateRoot;
1297
1298 #[derive(Protobuf, SavedStateRoot)]
1302 #[mesh(package = "pci.cfg_space_emu")]
1303 pub struct SavedState {
1304 #[mesh(1)]
1306 pub command: u16,
1307 #[mesh(2)]
1308 pub base_addresses: [u32; 6],
1309 #[mesh(3)]
1310 pub interrupt_line: u8,
1311 #[mesh(4)]
1312 pub latency_timer: u8,
1313 #[mesh(5)]
1314 pub capabilities: Vec<(String, SavedStateBlob)>,
1315
1316 #[mesh(6)]
1319 pub subordinate_bus_number: u8,
1320 #[mesh(7)]
1321 pub secondary_bus_number: u8,
1322 #[mesh(8)]
1323 pub primary_bus_number: u8,
1324 #[mesh(9)]
1325 pub memory_base: u16,
1326 #[mesh(10)]
1327 pub memory_limit: u16,
1328 #[mesh(11)]
1329 pub prefetch_base: u16,
1330 #[mesh(12)]
1331 pub prefetch_limit: u16,
1332 #[mesh(13)]
1333 pub prefetch_base_upper: u32,
1334 #[mesh(14)]
1335 pub prefetch_limit_upper: u32,
1336 #[mesh(15)]
1337 pub bridge_control: u16,
1338 }
1339 }
1340
1341 #[derive(Debug, Error)]
1342 enum ConfigSpaceRestoreError {
1343 #[error("found invalid config bits in saved state")]
1344 InvalidConfigBits,
1345 #[error("found unexpected capability {0}")]
1346 InvalidCap(String),
1347 }
1348
1349 impl SaveRestore for ConfigSpaceType0Emulator {
1350 type SavedState = state::SavedState;
1351
1352 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1353 let ConfigSpaceType0EmulatorState { latency_timer } = self.state;
1354
1355 let saved_state = state::SavedState {
1356 command: self.common.command().into_bits(),
1357 base_addresses: *self.common.base_addresses(),
1358 interrupt_line: self.common.interrupt_line(),
1359 latency_timer,
1360 capabilities: self
1361 .common
1362 .capabilities_mut()
1363 .iter_mut()
1364 .map(|cap| {
1365 let id = cap.label().to_owned();
1366 Ok((id, cap.save()?))
1367 })
1368 .collect::<Result<_, _>>()?,
1369 subordinate_bus_number: 0,
1371 secondary_bus_number: 0,
1372 primary_bus_number: 0,
1373 memory_base: 0,
1374 memory_limit: 0,
1375 prefetch_base: 0,
1376 prefetch_limit: 0,
1377 prefetch_base_upper: 0,
1378 prefetch_limit_upper: 0,
1379 bridge_control: 0,
1380 };
1381
1382 Ok(saved_state)
1383 }
1384
1385 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1386 let state::SavedState {
1387 command,
1388 base_addresses,
1389 interrupt_line,
1390 latency_timer,
1391 capabilities,
1392 subordinate_bus_number: _,
1394 secondary_bus_number: _,
1395 primary_bus_number: _,
1396 memory_base: _,
1397 memory_limit: _,
1398 prefetch_base: _,
1399 prefetch_limit: _,
1400 prefetch_base_upper: _,
1401 prefetch_limit_upper: _,
1402 bridge_control: _,
1403 } = state;
1404
1405 self.state = ConfigSpaceType0EmulatorState { latency_timer };
1406
1407 self.common.set_base_addresses(&base_addresses);
1408 self.common.set_interrupt_line(interrupt_line);
1409 self.common
1410 .set_command(cfg_space::Command::from_bits(command));
1411
1412 if command & !SUPPORTED_COMMAND_BITS != 0 {
1413 return Err(RestoreError::InvalidSavedState(
1414 ConfigSpaceRestoreError::InvalidConfigBits.into(),
1415 ));
1416 }
1417
1418 self.common.sync_command_register(self.common.command());
1419
1420 for (id, entry) in capabilities {
1421 tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1422
1423 let mut restored = false;
1426 for cap in self.common.capabilities_mut() {
1427 if cap.label() == id {
1428 cap.restore(entry)?;
1429 restored = true;
1430 break;
1431 }
1432 }
1433
1434 if !restored {
1435 return Err(RestoreError::InvalidSavedState(
1436 ConfigSpaceRestoreError::InvalidCap(id).into(),
1437 ));
1438 }
1439 }
1440
1441 Ok(())
1442 }
1443 }
1444
1445 impl SaveRestore for ConfigSpaceType1Emulator {
1446 type SavedState = state::SavedState;
1447
1448 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1449 let ConfigSpaceType1EmulatorState {
1450 subordinate_bus_number,
1451 secondary_bus_number,
1452 primary_bus_number,
1453 memory_base,
1454 memory_limit,
1455 prefetch_base,
1456 prefetch_limit,
1457 prefetch_base_upper,
1458 prefetch_limit_upper,
1459 bridge_control,
1460 } = self.state;
1461
1462 let type1_base_addresses = self.common.base_addresses();
1464 let mut saved_base_addresses = [0u32; 6];
1465 saved_base_addresses[0] = type1_base_addresses[0];
1466 saved_base_addresses[1] = type1_base_addresses[1];
1467
1468 let saved_state = state::SavedState {
1469 command: self.common.command().into_bits(),
1470 base_addresses: saved_base_addresses,
1471 interrupt_line: self.common.interrupt_line(),
1472 latency_timer: 0, capabilities: self
1474 .common
1475 .capabilities_mut()
1476 .iter_mut()
1477 .map(|cap| {
1478 let id = cap.label().to_owned();
1479 Ok((id, cap.save()?))
1480 })
1481 .collect::<Result<_, _>>()?,
1482 subordinate_bus_number,
1484 secondary_bus_number,
1485 primary_bus_number,
1486 memory_base,
1487 memory_limit,
1488 prefetch_base,
1489 prefetch_limit,
1490 prefetch_base_upper,
1491 prefetch_limit_upper,
1492 bridge_control,
1493 };
1494
1495 Ok(saved_state)
1496 }
1497
1498 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1499 let state::SavedState {
1500 command,
1501 base_addresses,
1502 interrupt_line,
1503 latency_timer: _, capabilities,
1505 subordinate_bus_number,
1506 secondary_bus_number,
1507 primary_bus_number,
1508 memory_base,
1509 memory_limit,
1510 prefetch_base,
1511 prefetch_limit,
1512 prefetch_base_upper,
1513 prefetch_limit_upper,
1514 bridge_control,
1515 } = state;
1516
1517 self.state = ConfigSpaceType1EmulatorState {
1518 subordinate_bus_number,
1519 secondary_bus_number,
1520 primary_bus_number,
1521 memory_base,
1522 memory_limit,
1523 prefetch_base,
1524 prefetch_limit,
1525 prefetch_base_upper,
1526 prefetch_limit_upper,
1527 bridge_control,
1528 };
1529
1530 let mut full_base_addresses = [0u32; 6];
1532 for (i, &addr) in base_addresses.iter().enumerate().take(2) {
1533 full_base_addresses[i] = addr;
1534 }
1535 self.common
1536 .set_base_addresses(&[full_base_addresses[0], full_base_addresses[1]]);
1537 self.common.set_interrupt_line(interrupt_line);
1538 self.common
1539 .set_command(cfg_space::Command::from_bits(command));
1540
1541 if command & !SUPPORTED_COMMAND_BITS != 0 {
1542 return Err(RestoreError::InvalidSavedState(
1543 ConfigSpaceRestoreError::InvalidConfigBits.into(),
1544 ));
1545 }
1546
1547 self.common.sync_command_register(self.common.command());
1548
1549 for (id, entry) in capabilities {
1550 tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1551
1552 let mut restored = false;
1553 for cap in self.common.capabilities_mut() {
1554 if cap.label() == id {
1555 cap.restore(entry)?;
1556 restored = true;
1557 break;
1558 }
1559 }
1560
1561 if !restored {
1562 return Err(RestoreError::InvalidSavedState(
1563 ConfigSpaceRestoreError::InvalidCap(id).into(),
1564 ));
1565 }
1566 }
1567
1568 Ok(())
1569 }
1570 }
1571}
1572
1573#[cfg(test)]
1574mod tests {
1575 use super::*;
1576 use crate::capabilities::pci_express::PciExpressCapability;
1577 use crate::capabilities::read_only::ReadOnlyCapability;
1578 use crate::spec::caps::pci_express::DevicePortType;
1579 use crate::spec::hwid::ClassCode;
1580 use crate::spec::hwid::ProgrammingInterface;
1581 use crate::spec::hwid::Subclass;
1582
1583 fn create_type0_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType0Emulator {
1584 ConfigSpaceType0Emulator::new(
1585 HardwareIds {
1586 vendor_id: 0x1111,
1587 device_id: 0x2222,
1588 revision_id: 1,
1589 prog_if: ProgrammingInterface::NONE,
1590 sub_class: Subclass::NONE,
1591 base_class: ClassCode::UNCLASSIFIED,
1592 type0_sub_vendor_id: 0x3333,
1593 type0_sub_system_id: 0x4444,
1594 },
1595 caps,
1596 DeviceBars::new(),
1597 )
1598 }
1599
1600 fn create_type1_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType1Emulator {
1601 ConfigSpaceType1Emulator::new(
1602 HardwareIds {
1603 vendor_id: 0x1111,
1604 device_id: 0x2222,
1605 revision_id: 1,
1606 prog_if: ProgrammingInterface::NONE,
1607 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1608 base_class: ClassCode::BRIDGE,
1609 type0_sub_vendor_id: 0,
1610 type0_sub_system_id: 0,
1611 },
1612 caps,
1613 )
1614 }
1615
1616 fn read_cfg(emulator: &ConfigSpaceType1Emulator, offset: u16) -> u32 {
1617 let mut val = 0;
1618 emulator.read_u32(offset, &mut val).unwrap();
1619 val
1620 }
1621
1622 #[test]
1623 fn test_type1_probe() {
1624 let emu = create_type1_emulator(vec![]);
1625 assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1626 assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0); let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1629 assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1630 assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0x10_0000); }
1632
1633 #[test]
1634 fn test_type1_bus_number_assignment() {
1635 let mut emu = create_type1_emulator(vec![]);
1636
1637 assert_eq!(read_cfg(&emu, 0x18), 0);
1640 assert_eq!(emu.assigned_bus_range(), 0..=0);
1641
1642 emu.write_u32(0x18, 0x0000_1000).unwrap();
1646 assert_eq!(read_cfg(&emu, 0x18), 0x0000_1000);
1647 assert_eq!(emu.assigned_bus_range(), 0..=0);
1648 emu.write_u32(0x18, 0x0012_1000).unwrap();
1649 assert_eq!(read_cfg(&emu, 0x18), 0x0012_1000);
1650 assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1651
1652 emu.write_u32(0x18, 0x0012_1033).unwrap();
1655 assert_eq!(read_cfg(&emu, 0x18), 0x0012_1033);
1656 assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1657
1658 emu.write_u32(0x18, 0x0047_4411).unwrap();
1660 assert_eq!(read_cfg(&emu, 0x18), 0x0047_4411);
1661 assert_eq!(emu.assigned_bus_range(), 0x44..=0x47);
1662
1663 emu.write_u32(0x18, 0x0088_8800).unwrap();
1665 assert_eq!(emu.assigned_bus_range(), 0x88..=0x88);
1666
1667 emu.write_u32(0x18, 0x0087_8800).unwrap();
1669 assert_eq!(emu.assigned_bus_range(), 0..=0);
1670 }
1671
1672 #[test]
1673 fn test_type1_memory_assignment() {
1674 const MMIO_ENABLED: u32 = 0x0000_0002;
1675 const MMIO_DISABLED: u32 = 0x0000_0000;
1676
1677 let mut emu = create_type1_emulator(vec![]);
1678 assert!(emu.assigned_memory_range().is_none());
1679
1680 emu.write_u32(0x20, 0xDEAD_BEEF).unwrap();
1683 assert!(emu.assigned_memory_range().is_none());
1684
1685 emu.write_u32(0x20, 0xFFF0_FF00).unwrap();
1687 assert!(emu.assigned_memory_range().is_none());
1688 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1690 assert_eq!(emu.assigned_memory_range(), Some(0xFF00_0000..=0xFFFF_FFFF));
1691 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1693 assert!(emu.assigned_memory_range().is_none());
1694
1695 emu.write_u32(0x20, 0xBBB0_BBB0).unwrap();
1697 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1698 assert_eq!(emu.assigned_memory_range(), Some(0xBBB0_0000..=0xBBBF_FFFF));
1699 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1700 assert!(emu.assigned_memory_range().is_none());
1701
1702 emu.write_u32(0x20, 0xAA00_BB00).unwrap();
1705 assert!(emu.assigned_memory_range().is_none());
1706 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1707 assert!(emu.assigned_memory_range().is_none());
1708 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1709 assert!(emu.assigned_memory_range().is_none());
1710 }
1711
1712 #[test]
1713 fn test_type1_prefetch_assignment() {
1714 const MMIO_ENABLED: u32 = 0x0000_0002;
1715 const MMIO_DISABLED: u32 = 0x0000_0000;
1716
1717 let mut emu = create_type1_emulator(vec![]);
1718 assert!(emu.assigned_prefetch_range().is_none());
1719
1720 emu.write_u32(0x24, 0xFFF0_FF00).unwrap(); emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); assert!(emu.assigned_prefetch_range().is_none());
1725 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1727 assert_eq!(
1728 emu.assigned_prefetch_range(),
1729 Some(0x00AA_BBCC_FF00_0000..=0x00DD_EEFF_FFFF_FFFF)
1730 );
1731 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1733 assert!(emu.assigned_prefetch_range().is_none());
1734
1735 emu.write_u32(0x24, 0xFF00_FFF0).unwrap(); emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); assert!(emu.assigned_prefetch_range().is_none());
1744 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1745 assert_eq!(
1746 emu.assigned_prefetch_range(),
1747 Some(0x00AA_BBCC_FFF0_0000..=0x00DD_EEFF_FF0F_FFFF)
1748 );
1749 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1750 assert!(emu.assigned_prefetch_range().is_none());
1751
1752 emu.write_u32(0x24, 0xDD00_DD00).unwrap(); emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); emu.write_u32(0x2C, 0x00AA_BBCC).unwrap(); assert!(emu.assigned_prefetch_range().is_none());
1757 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1758 assert_eq!(
1759 emu.assigned_prefetch_range(),
1760 Some(0x00AA_BBCC_DD00_0000..=0x00AA_BBCC_DD0F_FFFF)
1761 );
1762 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1763 assert!(emu.assigned_prefetch_range().is_none());
1764 }
1765
1766 #[test]
1767 fn test_type1_is_pcie_device() {
1768 let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1770 assert!(!emu.is_pcie_device());
1771
1772 let emu = create_type1_emulator(vec![Box::new(PciExpressCapability::new(
1774 DevicePortType::RootPort,
1775 None,
1776 ))]);
1777 assert!(emu.is_pcie_device());
1778
1779 let emu = create_type1_emulator(vec![
1781 Box::new(ReadOnlyCapability::new("foo", 0)),
1782 Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1783 Box::new(ReadOnlyCapability::new("bar", 0)),
1784 ]);
1785 assert!(emu.is_pcie_device());
1786 }
1787
1788 #[test]
1789 fn test_type0_is_pcie_device() {
1790 let emu = ConfigSpaceType0Emulator::new(
1792 HardwareIds {
1793 vendor_id: 0x1111,
1794 device_id: 0x2222,
1795 revision_id: 1,
1796 prog_if: ProgrammingInterface::NONE,
1797 sub_class: Subclass::NONE,
1798 base_class: ClassCode::UNCLASSIFIED,
1799 type0_sub_vendor_id: 0,
1800 type0_sub_system_id: 0,
1801 },
1802 vec![Box::new(ReadOnlyCapability::new("foo", 0))],
1803 DeviceBars::new(),
1804 );
1805 assert!(!emu.is_pcie_device());
1806
1807 let emu = ConfigSpaceType0Emulator::new(
1809 HardwareIds {
1810 vendor_id: 0x1111,
1811 device_id: 0x2222,
1812 revision_id: 1,
1813 prog_if: ProgrammingInterface::NONE,
1814 sub_class: Subclass::NONE,
1815 base_class: ClassCode::UNCLASSIFIED,
1816 type0_sub_vendor_id: 0,
1817 type0_sub_system_id: 0,
1818 },
1819 vec![Box::new(PciExpressCapability::new(
1820 DevicePortType::Endpoint,
1821 None,
1822 ))],
1823 DeviceBars::new(),
1824 );
1825 assert!(emu.is_pcie_device());
1826
1827 let emu = ConfigSpaceType0Emulator::new(
1829 HardwareIds {
1830 vendor_id: 0x1111,
1831 device_id: 0x2222,
1832 revision_id: 1,
1833 prog_if: ProgrammingInterface::NONE,
1834 sub_class: Subclass::NONE,
1835 base_class: ClassCode::UNCLASSIFIED,
1836 type0_sub_vendor_id: 0,
1837 type0_sub_system_id: 0,
1838 },
1839 vec![
1840 Box::new(ReadOnlyCapability::new("foo", 0)),
1841 Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1842 Box::new(ReadOnlyCapability::new("bar", 0)),
1843 ],
1844 DeviceBars::new(),
1845 );
1846 assert!(emu.is_pcie_device());
1847
1848 let emu = ConfigSpaceType0Emulator::new(
1850 HardwareIds {
1851 vendor_id: 0x1111,
1852 device_id: 0x2222,
1853 revision_id: 1,
1854 prog_if: ProgrammingInterface::NONE,
1855 sub_class: Subclass::NONE,
1856 base_class: ClassCode::UNCLASSIFIED,
1857 type0_sub_vendor_id: 0,
1858 type0_sub_system_id: 0,
1859 },
1860 vec![],
1861 DeviceBars::new(),
1862 );
1863 assert!(!emu.is_pcie_device());
1864 }
1865
1866 #[test]
1867 fn test_capability_ids() {
1868 let pcie_cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
1870 assert_eq!(pcie_cap.capability_id(), CapabilityId::PCI_EXPRESS);
1871
1872 let read_only_cap = ReadOnlyCapability::new("test", 0u32);
1873 assert_eq!(read_only_cap.capability_id(), CapabilityId::VENDOR_SPECIFIC);
1874 }
1875
1876 #[test]
1877 fn test_common_header_emulator_type0() {
1878 let hardware_ids = HardwareIds {
1880 vendor_id: 0x1111,
1881 device_id: 0x2222,
1882 revision_id: 1,
1883 prog_if: ProgrammingInterface::NONE,
1884 sub_class: Subclass::NONE,
1885 base_class: ClassCode::UNCLASSIFIED,
1886 type0_sub_vendor_id: 0,
1887 type0_sub_system_id: 0,
1888 };
1889
1890 let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1891
1892 let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1893 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1894
1895 assert_eq!(common_emu.hardware_ids().vendor_id, 0x1111);
1896 assert_eq!(common_emu.hardware_ids().device_id, 0x2222);
1897 assert!(!common_emu.multi_function_bit());
1898 assert!(!common_emu.is_pcie_device());
1899 assert_ne!(common_emu.bar_masks()[0], 0); }
1901
1902 #[test]
1903 fn test_common_header_emulator_type1() {
1904 let hardware_ids = HardwareIds {
1906 vendor_id: 0x3333,
1907 device_id: 0x4444,
1908 revision_id: 1,
1909 prog_if: ProgrammingInterface::NONE,
1910 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1911 base_class: ClassCode::BRIDGE,
1912 type0_sub_vendor_id: 0,
1913 type0_sub_system_id: 0,
1914 };
1915
1916 let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1917
1918 let mut common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
1919 ConfigSpaceCommonHeaderEmulator::new(
1920 hardware_ids,
1921 vec![Box::new(PciExpressCapability::new(
1922 DevicePortType::RootPort,
1923 None,
1924 ))],
1925 bars,
1926 )
1927 .with_multi_function_bit(true);
1928
1929 assert_eq!(common_emu.hardware_ids().vendor_id, 0x3333);
1930 assert_eq!(common_emu.hardware_ids().device_id, 0x4444);
1931 assert!(common_emu.multi_function_bit());
1932 assert!(common_emu.is_pcie_device());
1933 assert_ne!(common_emu.bar_masks()[0], 0); assert_eq!(common_emu.bar_masks().len(), 2);
1935
1936 common_emu.reset();
1938 assert_eq!(common_emu.capabilities().len(), 1); }
1940
1941 #[test]
1942 fn test_common_header_emulator_no_bars() {
1943 let hardware_ids = HardwareIds {
1945 vendor_id: 0x5555,
1946 device_id: 0x6666,
1947 revision_id: 1,
1948 prog_if: ProgrammingInterface::NONE,
1949 sub_class: Subclass::NONE,
1950 base_class: ClassCode::UNCLASSIFIED,
1951 type0_sub_vendor_id: 0,
1952 type0_sub_system_id: 0,
1953 };
1954
1955 let bars = DeviceBars::new();
1957
1958 let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1959 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1960
1961 assert_eq!(common_emu.hardware_ids().vendor_id, 0x5555);
1962 assert_eq!(common_emu.hardware_ids().device_id, 0x6666);
1963
1964 for &mask in common_emu.bar_masks() {
1966 assert_eq!(mask, 0);
1967 }
1968 }
1969
1970 #[test]
1971 fn test_common_header_emulator_type1_ignores_extra_bars() {
1972 let hardware_ids = HardwareIds {
1974 vendor_id: 0x7777,
1975 device_id: 0x8888,
1976 revision_id: 1,
1977 prog_if: ProgrammingInterface::NONE,
1978 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1979 base_class: ClassCode::BRIDGE,
1980 type0_sub_vendor_id: 0,
1981 type0_sub_system_id: 0,
1982 };
1983
1984 let bars = DeviceBars::new()
1986 .bar0(4096, BarMemoryKind::Dummy)
1987 .bar2(8192, BarMemoryKind::Dummy)
1988 .bar4(16384, BarMemoryKind::Dummy);
1989
1990 let common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
1991 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1992
1993 assert_eq!(common_emu.hardware_ids().vendor_id, 0x7777);
1994 assert_eq!(common_emu.hardware_ids().device_id, 0x8888);
1995
1996 assert_ne!(common_emu.bar_masks()[0], 0); assert_ne!(common_emu.bar_masks()[1], 0); assert_eq!(common_emu.bar_masks().len(), 2); }
2004
2005 #[test]
2006 fn test_common_header_extended_capabilities() {
2007 let mut common_emu_no_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2009 HardwareIds {
2010 vendor_id: 0x1111,
2011 device_id: 0x2222,
2012 revision_id: 1,
2013 prog_if: ProgrammingInterface::NONE,
2014 sub_class: Subclass::NONE,
2015 base_class: ClassCode::UNCLASSIFIED,
2016 type0_sub_vendor_id: 0,
2017 type0_sub_system_id: 0,
2018 },
2019 vec![Box::new(ReadOnlyCapability::new("foo", 0))],
2020 DeviceBars::new(),
2021 );
2022 assert!(!common_emu_no_pcie.is_pcie_device());
2023
2024 let mut common_emu_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2025 HardwareIds {
2026 vendor_id: 0x1111,
2027 device_id: 0x2222,
2028 revision_id: 1,
2029 prog_if: ProgrammingInterface::NONE,
2030 sub_class: Subclass::NONE,
2031 base_class: ClassCode::UNCLASSIFIED,
2032 type0_sub_vendor_id: 0,
2033 type0_sub_system_id: 0,
2034 },
2035 vec![Box::new(PciExpressCapability::new(
2036 DevicePortType::Endpoint,
2037 None,
2038 ))],
2039 DeviceBars::new(),
2040 );
2041 assert!(common_emu_pcie.is_pcie_device());
2042
2043 let mut value = 0;
2045 assert!(matches!(
2046 common_emu_no_pcie.read_extended_capabilities(0x100, &mut value),
2047 CommonHeaderResult::Failed(IoError::InvalidRegister)
2048 ));
2049
2050 let mut value = 0;
2052 assert!(matches!(
2053 common_emu_pcie.read_extended_capabilities(0x100, &mut value),
2054 CommonHeaderResult::Handled
2055 ));
2056 assert_eq!(value, 0xffffffff);
2057
2058 assert!(matches!(
2060 common_emu_no_pcie.write_extended_capabilities(0x100, 0x1234),
2061 CommonHeaderResult::Failed(IoError::InvalidRegister)
2062 ));
2063
2064 assert!(matches!(
2066 common_emu_pcie.write_extended_capabilities(0x100, 0x1234),
2067 CommonHeaderResult::Handled
2068 ));
2069
2070 let mut value = 0;
2072 assert!(matches!(
2073 common_emu_pcie.read_extended_capabilities(0x99, &mut value),
2074 CommonHeaderResult::Failed(IoError::InvalidRegister)
2075 ));
2076 assert!(matches!(
2077 common_emu_pcie.read_extended_capabilities(0x1000, &mut value),
2078 CommonHeaderResult::Failed(IoError::InvalidRegister)
2079 ));
2080 }
2081
2082 #[test]
2083 fn test_type0_emulator_save_restore() {
2084 use vmcore::save_restore::SaveRestore;
2085
2086 let mut emu = create_type0_emulator(vec![]);
2088
2089 emu.write_u32(0x04, 0x0007).unwrap(); let mut test_val = 0u32;
2094 emu.read_u32(0x04, &mut test_val).unwrap();
2095 assert_eq!(test_val & 0x0007, 0x0007);
2096
2097 emu.write_u32(0x3C, 0x0040_0000).unwrap(); let saved_state = emu.save().expect("save should succeed");
2102
2103 emu.reset();
2105
2106 emu.read_u32(0x04, &mut test_val).unwrap();
2108 assert_eq!(test_val & 0x0007, 0x0000); emu.restore(saved_state).expect("restore should succeed");
2112
2113 emu.read_u32(0x04, &mut test_val).unwrap();
2115 assert_eq!(test_val & 0x0007, 0x0007); }
2117
2118 #[test]
2119 fn test_type1_emulator_save_restore() {
2120 use vmcore::save_restore::SaveRestore;
2121
2122 let mut emu = create_type1_emulator(vec![]);
2124
2125 emu.write_u32(0x04, 0x0003).unwrap(); emu.write_u32(0x18, 0x0012_1000).unwrap(); emu.write_u32(0x20, 0xFFF0_FF00).unwrap(); emu.write_u32(0x24, 0xFFF0_FF00).unwrap(); emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); emu.write_u32(0x3C, 0x0001_0000).unwrap(); let mut test_val = 0u32;
2136 emu.read_u32(0x04, &mut test_val).unwrap();
2137 assert_eq!(test_val & 0x0003, 0x0003);
2138 emu.read_u32(0x18, &mut test_val).unwrap();
2139 assert_eq!(test_val, 0x0012_1000);
2140 emu.read_u32(0x20, &mut test_val).unwrap();
2141 assert_eq!(test_val, 0xFFF0_FF00);
2142 emu.read_u32(0x28, &mut test_val).unwrap();
2143 assert_eq!(test_val, 0x00AA_BBCC);
2144 emu.read_u32(0x2C, &mut test_val).unwrap();
2145 assert_eq!(test_val, 0x00DD_EEFF);
2146 emu.read_u32(0x3C, &mut test_val).unwrap();
2147 assert_eq!(test_val >> 16, 0x0001); let saved_state = emu.save().expect("save should succeed");
2151
2152 emu.reset();
2154
2155 emu.read_u32(0x04, &mut test_val).unwrap();
2157 assert_eq!(test_val & 0x0003, 0x0000);
2158 emu.read_u32(0x18, &mut test_val).unwrap();
2159 assert_eq!(test_val, 0x0000_0000);
2160
2161 emu.restore(saved_state).expect("restore should succeed");
2163
2164 emu.read_u32(0x04, &mut test_val).unwrap();
2166 assert_eq!(test_val & 0x0003, 0x0003);
2167 emu.read_u32(0x18, &mut test_val).unwrap();
2168 assert_eq!(test_val, 0x0012_1000);
2169 emu.read_u32(0x20, &mut test_val).unwrap();
2170 assert_eq!(test_val, 0xFFF0_FF00);
2171 emu.read_u32(0x28, &mut test_val).unwrap();
2172 assert_eq!(test_val, 0x00AA_BBCC);
2173 emu.read_u32(0x2C, &mut test_val).unwrap();
2174 assert_eq!(test_val, 0x00DD_EEFF);
2175 emu.read_u32(0x3C, &mut test_val).unwrap();
2176 assert_eq!(test_val >> 16, 0x0001); }
2178
2179 #[test]
2180 fn test_config_space_type1_set_presence_detect_state() {
2181 let pcie_cap =
2186 PciExpressCapability::new(DevicePortType::RootPort, None).with_hotplug_support(1);
2187
2188 let mut emulator = create_type1_emulator(vec![Box::new(pcie_cap)]);
2189
2190 let mut slot_status_val = 0u32;
2192 let result = emulator.read_u32(0x58, &mut slot_status_val); assert!(matches!(result, IoResult::Ok));
2194 let initial_presence_detect = (slot_status_val >> 22) & 0x1; assert_eq!(
2196 initial_presence_detect, 0,
2197 "Initial presence detect state should be 0"
2198 );
2199
2200 emulator.set_presence_detect_state(true);
2202 let result = emulator.read_u32(0x58, &mut slot_status_val);
2203 assert!(matches!(result, IoResult::Ok));
2204 let present_presence_detect = (slot_status_val >> 22) & 0x1;
2205 assert_eq!(
2206 present_presence_detect, 1,
2207 "Presence detect state should be 1 when device is present"
2208 );
2209
2210 emulator.set_presence_detect_state(false);
2212 let result = emulator.read_u32(0x58, &mut slot_status_val);
2213 assert!(matches!(result, IoResult::Ok));
2214 let absent_presence_detect = (slot_status_val >> 22) & 0x1;
2215 assert_eq!(
2216 absent_presence_detect, 0,
2217 "Presence detect state should be 0 when device is not present"
2218 );
2219 }
2220
2221 #[test]
2222 fn test_config_space_type1_set_presence_detect_state_without_pcie() {
2223 let mut emulator = create_type1_emulator(vec![]); emulator.set_presence_detect_state(true);
2230 emulator.set_presence_detect_state(false);
2231 }
2232
2233 #[test]
2234 fn test_interrupt_pin_register() {
2235 use vmcore::line_interrupt::LineInterrupt;
2236
2237 let mut emu = ConfigSpaceType0Emulator::new(
2239 HardwareIds {
2240 vendor_id: 0x1111,
2241 device_id: 0x2222,
2242 revision_id: 1,
2243 prog_if: ProgrammingInterface::NONE,
2244 sub_class: Subclass::NONE,
2245 base_class: ClassCode::UNCLASSIFIED,
2246 type0_sub_vendor_id: 0,
2247 type0_sub_system_id: 0,
2248 },
2249 vec![],
2250 DeviceBars::new(),
2251 );
2252
2253 let mut val = 0u32;
2255 emu.read_u32(0x3C, &mut val).unwrap(); assert_eq!(val & 0xFF00, 0); let line_interrupt = LineInterrupt::detached();
2260 emu.set_interrupt_pin(PciInterruptPin::IntA, line_interrupt);
2261
2262 emu.read_u32(0x3C, &mut val).unwrap();
2264 assert_eq!((val >> 8) & 0xFF, 1); emu.write_u32(0x3C, 0x00110042).unwrap(); emu.read_u32(0x3C, &mut val).unwrap();
2269 assert_eq!(val & 0xFF, 0x42); assert_eq!((val >> 8) & 0xFF, 1); assert_eq!((val >> 16) & 0xFF, 0x11); let mut emu_d = ConfigSpaceType0Emulator::new(
2275 HardwareIds {
2276 vendor_id: 0x1111,
2277 device_id: 0x2222,
2278 revision_id: 1,
2279 prog_if: ProgrammingInterface::NONE,
2280 sub_class: Subclass::NONE,
2281 base_class: ClassCode::UNCLASSIFIED,
2282 type0_sub_vendor_id: 0,
2283 type0_sub_system_id: 0,
2284 },
2285 vec![],
2286 DeviceBars::new(),
2287 );
2288
2289 let line_interrupt_d = LineInterrupt::detached();
2290 emu_d.set_interrupt_pin(PciInterruptPin::IntD, line_interrupt_d);
2291
2292 emu_d.read_u32(0x3C, &mut val).unwrap();
2293 assert_eq!((val >> 8) & 0xFF, 4); }
2295
2296 #[test]
2297 fn test_header_type_functionality() {
2298 assert_eq!(HeaderType::Type0.bar_count(), 6);
2300 assert_eq!(HeaderType::Type1.bar_count(), 2);
2301 assert_eq!(usize::from(HeaderType::Type0), 6);
2302 assert_eq!(usize::from(HeaderType::Type1), 2);
2303
2304 assert_eq!(header_type_consts::TYPE0_BAR_COUNT, 6);
2306 assert_eq!(header_type_consts::TYPE1_BAR_COUNT, 2);
2307
2308 let emu_type0 = create_type0_emulator(vec![]);
2310 assert_eq!(emu_type0.common.bar_count(), 6);
2311 assert_eq!(emu_type0.common.header_type(), HeaderType::Type0);
2312 assert!(emu_type0.common.validate_header_type(HeaderType::Type0));
2313 assert!(!emu_type0.common.validate_header_type(HeaderType::Type1));
2314
2315 let emu_type1 = create_type1_emulator(vec![]);
2317 assert_eq!(emu_type1.common.bar_count(), 2);
2318 assert_eq!(emu_type1.common.header_type(), HeaderType::Type1);
2319 assert!(emu_type1.common.validate_header_type(HeaderType::Type1));
2320 assert!(!emu_type1.common.validate_header_type(HeaderType::Type0));
2321 }
2322}