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 #[inspect(hex)]
1015 subordinate_bus_number: u8,
1016 #[inspect(hex)]
1020 secondary_bus_number: u8,
1021 #[inspect(hex)]
1024 primary_bus_number: u8,
1025 #[inspect(hex)]
1029 memory_base: u16,
1030 #[inspect(hex)]
1034 memory_limit: u16,
1035 #[inspect(hex)]
1040 prefetch_base: u16,
1041 #[inspect(hex)]
1046 prefetch_limit: u16,
1047 #[inspect(hex)]
1052 prefetch_base_upper: u32,
1053 #[inspect(hex)]
1058 prefetch_limit_upper: u32,
1059 #[inspect(hex)]
1062 bridge_control: u16,
1063}
1064
1065impl ConfigSpaceType1EmulatorState {
1066 fn new() -> Self {
1067 Self {
1068 subordinate_bus_number: 0,
1069 secondary_bus_number: 0,
1070 primary_bus_number: 0,
1071 memory_base: 0,
1072 memory_limit: 0,
1073 prefetch_base: 0,
1074 prefetch_limit: 0,
1075 prefetch_base_upper: 0,
1076 prefetch_limit_upper: 0,
1077 bridge_control: 0,
1078 }
1079 }
1080}
1081
1082#[derive(Inspect)]
1084pub struct ConfigSpaceType1Emulator {
1085 #[inspect(flatten)]
1087 common: ConfigSpaceCommonHeaderEmulatorType1,
1088 state: ConfigSpaceType1EmulatorState,
1090}
1091
1092impl ConfigSpaceType1Emulator {
1093 pub fn new(hardware_ids: HardwareIds, capabilities: Vec<Box<dyn PciCapability>>) -> Self {
1095 let common =
1096 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, capabilities, DeviceBars::new());
1097
1098 Self {
1099 common,
1100 state: ConfigSpaceType1EmulatorState::new(),
1101 }
1102 }
1103
1104 pub fn reset(&mut self) {
1106 self.common.reset();
1107 self.state = ConfigSpaceType1EmulatorState::new();
1108 }
1109
1110 pub fn with_multi_function_bit(mut self, multi_function: bool) -> Self {
1112 self.common = self.common.with_multi_function_bit(multi_function);
1113 self
1114 }
1115
1116 pub fn assigned_bus_range(&self) -> RangeInclusive<u8> {
1118 let secondary = self.state.secondary_bus_number;
1119 let subordinate = self.state.subordinate_bus_number;
1120 if secondary <= subordinate {
1121 secondary..=subordinate
1122 } else {
1123 0..=0
1124 }
1125 }
1126
1127 fn decode_memory_range(&self, base_register: u16, limit_register: u16) -> (u32, u32) {
1128 let base_addr = ((base_register & !0b1111) as u32) << 16;
1129 let limit_addr = ((limit_register & !0b1111) as u32) << 16 | 0xF_FFFF;
1130 (base_addr, limit_addr)
1131 }
1132
1133 pub fn assigned_memory_range(&self) -> Option<RangeInclusive<u32>> {
1136 let (base_addr, limit_addr) =
1137 self.decode_memory_range(self.state.memory_base, self.state.memory_limit);
1138 if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1139 Some(base_addr..=limit_addr)
1140 } else {
1141 None
1142 }
1143 }
1144
1145 pub fn assigned_prefetch_range(&self) -> Option<RangeInclusive<u64>> {
1148 let (base_low, limit_low) =
1149 self.decode_memory_range(self.state.prefetch_base, self.state.prefetch_limit);
1150 let base_addr = (self.state.prefetch_base_upper as u64) << 32 | base_low as u64;
1151 let limit_addr = (self.state.prefetch_limit_upper as u64) << 32 | limit_low as u64;
1152 if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1153 Some(base_addr..=limit_addr)
1154 } else {
1155 None
1156 }
1157 }
1158
1159 pub fn read_u32(&self, offset: u16, value: &mut u32) -> IoResult {
1161 use cfg_space::HeaderType01;
1162
1163 match self.common.read_u32(offset, value) {
1165 CommonHeaderResult::Handled => return IoResult::Ok,
1166 CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1167 CommonHeaderResult::Unhandled => {
1168 }
1170 }
1171
1172 *value = match HeaderType01(offset) {
1174 HeaderType01::BIST_HEADER => {
1175 if self.common.multi_function_bit() {
1177 0x00810000 } else {
1179 0x00010000 }
1181 }
1182 HeaderType01::LATENCY_BUS_NUMBERS => {
1183 (self.state.subordinate_bus_number as u32) << 16
1184 | (self.state.secondary_bus_number as u32) << 8
1185 | self.state.primary_bus_number as u32
1186 }
1187 HeaderType01::SEC_STATUS_IO_RANGE => 0,
1188 HeaderType01::MEMORY_RANGE => {
1189 (self.state.memory_limit as u32) << 16 | self.state.memory_base as u32
1190 }
1191 HeaderType01::PREFETCH_RANGE => {
1192 ((self.state.prefetch_limit | 0b0001) as u32) << 16
1195 | (self.state.prefetch_base | 0b0001) as u32
1196 }
1197 HeaderType01::PREFETCH_BASE_UPPER => self.state.prefetch_base_upper,
1198 HeaderType01::PREFETCH_LIMIT_UPPER => self.state.prefetch_limit_upper,
1199 HeaderType01::IO_RANGE_UPPER => 0,
1200 HeaderType01::EXPANSION_ROM_BASE => 0,
1201 HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1202 (self.state.bridge_control as u32) << 16 | self.common.interrupt_line() as u32
1205 }
1206 _ => {
1207 tracelimit::warn_ratelimited!(offset, "unexpected config space read");
1208 return IoResult::Err(IoError::InvalidRegister);
1209 }
1210 };
1211
1212 IoResult::Ok
1213 }
1214
1215 pub fn write_u32(&mut self, offset: u16, val: u32) -> IoResult {
1217 use cfg_space::HeaderType01;
1218
1219 match self.common.write_u32(offset, val) {
1221 CommonHeaderResult::Handled => return IoResult::Ok,
1222 CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1223 CommonHeaderResult::Unhandled => {
1224 }
1226 }
1227
1228 match HeaderType01(offset) {
1230 HeaderType01::BIST_HEADER => {
1231 }
1234 HeaderType01::LATENCY_BUS_NUMBERS => {
1235 self.state.subordinate_bus_number = (val >> 16) as u8;
1236 self.state.secondary_bus_number = (val >> 8) as u8;
1237 self.state.primary_bus_number = val as u8;
1238 }
1239 HeaderType01::MEMORY_RANGE => {
1240 self.state.memory_base = val as u16;
1241 self.state.memory_limit = (val >> 16) as u16;
1242 }
1243 HeaderType01::PREFETCH_RANGE => {
1244 self.state.prefetch_base = val as u16;
1245 self.state.prefetch_limit = (val >> 16) as u16;
1246 }
1247 HeaderType01::PREFETCH_BASE_UPPER => {
1248 self.state.prefetch_base_upper = val;
1249 }
1250 HeaderType01::PREFETCH_LIMIT_UPPER => {
1251 self.state.prefetch_limit_upper = val;
1252 }
1253 HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1254 self.common.set_interrupt_line((val & 0xff) as u8);
1257 self.state.bridge_control = (val >> 16) as u16;
1258 }
1259 _ if offset < 0x40 && offset.is_multiple_of(4) => (),
1261 _ => {
1262 tracelimit::warn_ratelimited!(offset, value = val, "unexpected config space write");
1263 return IoResult::Err(IoError::InvalidRegister);
1264 }
1265 }
1266
1267 IoResult::Ok
1268 }
1269
1270 pub fn is_pcie_device(&self) -> bool {
1272 self.common.is_pcie_device()
1273 }
1274
1275 pub fn set_presence_detect_state(&mut self, present: bool) {
1282 for cap in self.common.capabilities_mut() {
1284 if cap.capability_id() == CapabilityId::PCI_EXPRESS {
1285 if let Some(pcie_cap) = cap.as_pci_express_mut() {
1287 pcie_cap.set_presence_detect_state(present);
1288 return;
1289 }
1290 }
1291 }
1292 }
1294}
1295
1296mod save_restore {
1297 use super::*;
1298 use thiserror::Error;
1299 use vmcore::save_restore::RestoreError;
1300 use vmcore::save_restore::SaveError;
1301 use vmcore::save_restore::SaveRestore;
1302
1303 mod state {
1304 use mesh::payload::Protobuf;
1305 use vmcore::save_restore::SavedStateBlob;
1306 use vmcore::save_restore::SavedStateRoot;
1307
1308 #[derive(Protobuf, SavedStateRoot)]
1312 #[mesh(package = "pci.cfg_space_emu")]
1313 pub struct SavedState {
1314 #[mesh(1)]
1316 pub command: u16,
1317 #[mesh(2)]
1318 pub base_addresses: [u32; 6],
1319 #[mesh(3)]
1320 pub interrupt_line: u8,
1321 #[mesh(4)]
1322 pub latency_timer: u8,
1323 #[mesh(5)]
1324 pub capabilities: Vec<(String, SavedStateBlob)>,
1325
1326 #[mesh(6)]
1329 pub subordinate_bus_number: u8,
1330 #[mesh(7)]
1331 pub secondary_bus_number: u8,
1332 #[mesh(8)]
1333 pub primary_bus_number: u8,
1334 #[mesh(9)]
1335 pub memory_base: u16,
1336 #[mesh(10)]
1337 pub memory_limit: u16,
1338 #[mesh(11)]
1339 pub prefetch_base: u16,
1340 #[mesh(12)]
1341 pub prefetch_limit: u16,
1342 #[mesh(13)]
1343 pub prefetch_base_upper: u32,
1344 #[mesh(14)]
1345 pub prefetch_limit_upper: u32,
1346 #[mesh(15)]
1347 pub bridge_control: u16,
1348 }
1349 }
1350
1351 #[derive(Debug, Error)]
1352 enum ConfigSpaceRestoreError {
1353 #[error("found invalid config bits in saved state")]
1354 InvalidConfigBits,
1355 #[error("found unexpected capability {0}")]
1356 InvalidCap(String),
1357 }
1358
1359 impl SaveRestore for ConfigSpaceType0Emulator {
1360 type SavedState = state::SavedState;
1361
1362 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1363 let ConfigSpaceType0EmulatorState { latency_timer } = self.state;
1364
1365 let saved_state = state::SavedState {
1366 command: self.common.command().into_bits(),
1367 base_addresses: *self.common.base_addresses(),
1368 interrupt_line: self.common.interrupt_line(),
1369 latency_timer,
1370 capabilities: self
1371 .common
1372 .capabilities_mut()
1373 .iter_mut()
1374 .map(|cap| {
1375 let id = cap.label().to_owned();
1376 Ok((id, cap.save()?))
1377 })
1378 .collect::<Result<_, _>>()?,
1379 subordinate_bus_number: 0,
1381 secondary_bus_number: 0,
1382 primary_bus_number: 0,
1383 memory_base: 0,
1384 memory_limit: 0,
1385 prefetch_base: 0,
1386 prefetch_limit: 0,
1387 prefetch_base_upper: 0,
1388 prefetch_limit_upper: 0,
1389 bridge_control: 0,
1390 };
1391
1392 Ok(saved_state)
1393 }
1394
1395 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1396 let state::SavedState {
1397 command,
1398 base_addresses,
1399 interrupt_line,
1400 latency_timer,
1401 capabilities,
1402 subordinate_bus_number: _,
1404 secondary_bus_number: _,
1405 primary_bus_number: _,
1406 memory_base: _,
1407 memory_limit: _,
1408 prefetch_base: _,
1409 prefetch_limit: _,
1410 prefetch_base_upper: _,
1411 prefetch_limit_upper: _,
1412 bridge_control: _,
1413 } = state;
1414
1415 self.state = ConfigSpaceType0EmulatorState { latency_timer };
1416
1417 self.common.set_base_addresses(&base_addresses);
1418 self.common.set_interrupt_line(interrupt_line);
1419 self.common
1420 .set_command(cfg_space::Command::from_bits(command));
1421
1422 if command & !SUPPORTED_COMMAND_BITS != 0 {
1423 return Err(RestoreError::InvalidSavedState(
1424 ConfigSpaceRestoreError::InvalidConfigBits.into(),
1425 ));
1426 }
1427
1428 self.common.sync_command_register(self.common.command());
1429
1430 for (id, entry) in capabilities {
1431 tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1432
1433 let mut restored = false;
1436 for cap in self.common.capabilities_mut() {
1437 if cap.label() == id {
1438 cap.restore(entry)?;
1439 restored = true;
1440 break;
1441 }
1442 }
1443
1444 if !restored {
1445 return Err(RestoreError::InvalidSavedState(
1446 ConfigSpaceRestoreError::InvalidCap(id).into(),
1447 ));
1448 }
1449 }
1450
1451 Ok(())
1452 }
1453 }
1454
1455 impl SaveRestore for ConfigSpaceType1Emulator {
1456 type SavedState = state::SavedState;
1457
1458 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1459 let ConfigSpaceType1EmulatorState {
1460 subordinate_bus_number,
1461 secondary_bus_number,
1462 primary_bus_number,
1463 memory_base,
1464 memory_limit,
1465 prefetch_base,
1466 prefetch_limit,
1467 prefetch_base_upper,
1468 prefetch_limit_upper,
1469 bridge_control,
1470 } = self.state;
1471
1472 let type1_base_addresses = self.common.base_addresses();
1474 let mut saved_base_addresses = [0u32; 6];
1475 saved_base_addresses[0] = type1_base_addresses[0];
1476 saved_base_addresses[1] = type1_base_addresses[1];
1477
1478 let saved_state = state::SavedState {
1479 command: self.common.command().into_bits(),
1480 base_addresses: saved_base_addresses,
1481 interrupt_line: self.common.interrupt_line(),
1482 latency_timer: 0, capabilities: self
1484 .common
1485 .capabilities_mut()
1486 .iter_mut()
1487 .map(|cap| {
1488 let id = cap.label().to_owned();
1489 Ok((id, cap.save()?))
1490 })
1491 .collect::<Result<_, _>>()?,
1492 subordinate_bus_number,
1494 secondary_bus_number,
1495 primary_bus_number,
1496 memory_base,
1497 memory_limit,
1498 prefetch_base,
1499 prefetch_limit,
1500 prefetch_base_upper,
1501 prefetch_limit_upper,
1502 bridge_control,
1503 };
1504
1505 Ok(saved_state)
1506 }
1507
1508 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1509 let state::SavedState {
1510 command,
1511 base_addresses,
1512 interrupt_line,
1513 latency_timer: _, capabilities,
1515 subordinate_bus_number,
1516 secondary_bus_number,
1517 primary_bus_number,
1518 memory_base,
1519 memory_limit,
1520 prefetch_base,
1521 prefetch_limit,
1522 prefetch_base_upper,
1523 prefetch_limit_upper,
1524 bridge_control,
1525 } = state;
1526
1527 self.state = ConfigSpaceType1EmulatorState {
1528 subordinate_bus_number,
1529 secondary_bus_number,
1530 primary_bus_number,
1531 memory_base,
1532 memory_limit,
1533 prefetch_base,
1534 prefetch_limit,
1535 prefetch_base_upper,
1536 prefetch_limit_upper,
1537 bridge_control,
1538 };
1539
1540 let mut full_base_addresses = [0u32; 6];
1542 for (i, &addr) in base_addresses.iter().enumerate().take(2) {
1543 full_base_addresses[i] = addr;
1544 }
1545 self.common
1546 .set_base_addresses(&[full_base_addresses[0], full_base_addresses[1]]);
1547 self.common.set_interrupt_line(interrupt_line);
1548 self.common
1549 .set_command(cfg_space::Command::from_bits(command));
1550
1551 if command & !SUPPORTED_COMMAND_BITS != 0 {
1552 return Err(RestoreError::InvalidSavedState(
1553 ConfigSpaceRestoreError::InvalidConfigBits.into(),
1554 ));
1555 }
1556
1557 self.common.sync_command_register(self.common.command());
1558
1559 for (id, entry) in capabilities {
1560 tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1561
1562 let mut restored = false;
1563 for cap in self.common.capabilities_mut() {
1564 if cap.label() == id {
1565 cap.restore(entry)?;
1566 restored = true;
1567 break;
1568 }
1569 }
1570
1571 if !restored {
1572 return Err(RestoreError::InvalidSavedState(
1573 ConfigSpaceRestoreError::InvalidCap(id).into(),
1574 ));
1575 }
1576 }
1577
1578 Ok(())
1579 }
1580 }
1581}
1582
1583#[cfg(test)]
1584mod tests {
1585 use super::*;
1586 use crate::capabilities::pci_express::PciExpressCapability;
1587 use crate::capabilities::read_only::ReadOnlyCapability;
1588 use crate::spec::caps::pci_express::DevicePortType;
1589 use crate::spec::hwid::ClassCode;
1590 use crate::spec::hwid::ProgrammingInterface;
1591 use crate::spec::hwid::Subclass;
1592
1593 fn create_type0_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType0Emulator {
1594 ConfigSpaceType0Emulator::new(
1595 HardwareIds {
1596 vendor_id: 0x1111,
1597 device_id: 0x2222,
1598 revision_id: 1,
1599 prog_if: ProgrammingInterface::NONE,
1600 sub_class: Subclass::NONE,
1601 base_class: ClassCode::UNCLASSIFIED,
1602 type0_sub_vendor_id: 0x3333,
1603 type0_sub_system_id: 0x4444,
1604 },
1605 caps,
1606 DeviceBars::new(),
1607 )
1608 }
1609
1610 fn create_type1_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType1Emulator {
1611 ConfigSpaceType1Emulator::new(
1612 HardwareIds {
1613 vendor_id: 0x1111,
1614 device_id: 0x2222,
1615 revision_id: 1,
1616 prog_if: ProgrammingInterface::NONE,
1617 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1618 base_class: ClassCode::BRIDGE,
1619 type0_sub_vendor_id: 0,
1620 type0_sub_system_id: 0,
1621 },
1622 caps,
1623 )
1624 }
1625
1626 fn read_cfg(emulator: &ConfigSpaceType1Emulator, offset: u16) -> u32 {
1627 let mut val = 0;
1628 emulator.read_u32(offset, &mut val).unwrap();
1629 val
1630 }
1631
1632 #[test]
1633 fn test_type1_probe() {
1634 let emu = create_type1_emulator(vec![]);
1635 assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1636 assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0); let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1639 assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1640 assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0x10_0000); }
1642
1643 #[test]
1644 fn test_type1_bus_number_assignment() {
1645 let mut emu = create_type1_emulator(vec![]);
1646
1647 assert_eq!(read_cfg(&emu, 0x18), 0);
1650 assert_eq!(emu.assigned_bus_range(), 0..=0);
1651
1652 emu.write_u32(0x18, 0x0000_1000).unwrap();
1656 assert_eq!(read_cfg(&emu, 0x18), 0x0000_1000);
1657 assert_eq!(emu.assigned_bus_range(), 0..=0);
1658 emu.write_u32(0x18, 0x0012_1000).unwrap();
1659 assert_eq!(read_cfg(&emu, 0x18), 0x0012_1000);
1660 assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1661
1662 emu.write_u32(0x18, 0x0012_1033).unwrap();
1665 assert_eq!(read_cfg(&emu, 0x18), 0x0012_1033);
1666 assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1667
1668 emu.write_u32(0x18, 0x0047_4411).unwrap();
1670 assert_eq!(read_cfg(&emu, 0x18), 0x0047_4411);
1671 assert_eq!(emu.assigned_bus_range(), 0x44..=0x47);
1672
1673 emu.write_u32(0x18, 0x0088_8800).unwrap();
1675 assert_eq!(emu.assigned_bus_range(), 0x88..=0x88);
1676
1677 emu.write_u32(0x18, 0x0087_8800).unwrap();
1679 assert_eq!(emu.assigned_bus_range(), 0..=0);
1680 }
1681
1682 #[test]
1683 fn test_type1_memory_assignment() {
1684 const MMIO_ENABLED: u32 = 0x0000_0002;
1685 const MMIO_DISABLED: u32 = 0x0000_0000;
1686
1687 let mut emu = create_type1_emulator(vec![]);
1688 assert!(emu.assigned_memory_range().is_none());
1689
1690 emu.write_u32(0x20, 0xDEAD_BEEF).unwrap();
1693 assert!(emu.assigned_memory_range().is_none());
1694
1695 emu.write_u32(0x20, 0xFFF0_FF00).unwrap();
1697 assert!(emu.assigned_memory_range().is_none());
1698 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1700 assert_eq!(emu.assigned_memory_range(), Some(0xFF00_0000..=0xFFFF_FFFF));
1701 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1703 assert!(emu.assigned_memory_range().is_none());
1704
1705 emu.write_u32(0x20, 0xBBB0_BBB0).unwrap();
1707 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1708 assert_eq!(emu.assigned_memory_range(), Some(0xBBB0_0000..=0xBBBF_FFFF));
1709 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1710 assert!(emu.assigned_memory_range().is_none());
1711
1712 emu.write_u32(0x20, 0xAA00_BB00).unwrap();
1715 assert!(emu.assigned_memory_range().is_none());
1716 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1717 assert!(emu.assigned_memory_range().is_none());
1718 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1719 assert!(emu.assigned_memory_range().is_none());
1720 }
1721
1722 #[test]
1723 fn test_type1_prefetch_assignment() {
1724 const MMIO_ENABLED: u32 = 0x0000_0002;
1725 const MMIO_DISABLED: u32 = 0x0000_0000;
1726
1727 let mut emu = create_type1_emulator(vec![]);
1728 assert!(emu.assigned_prefetch_range().is_none());
1729
1730 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());
1735 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1737 assert_eq!(
1738 emu.assigned_prefetch_range(),
1739 Some(0x00AA_BBCC_FF00_0000..=0x00DD_EEFF_FFFF_FFFF)
1740 );
1741 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1743 assert!(emu.assigned_prefetch_range().is_none());
1744
1745 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());
1754 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1755 assert_eq!(
1756 emu.assigned_prefetch_range(),
1757 Some(0x00AA_BBCC_FFF0_0000..=0x00DD_EEFF_FF0F_FFFF)
1758 );
1759 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1760 assert!(emu.assigned_prefetch_range().is_none());
1761
1762 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());
1767 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1768 assert_eq!(
1769 emu.assigned_prefetch_range(),
1770 Some(0x00AA_BBCC_DD00_0000..=0x00AA_BBCC_DD0F_FFFF)
1771 );
1772 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1773 assert!(emu.assigned_prefetch_range().is_none());
1774 }
1775
1776 #[test]
1777 fn test_type1_is_pcie_device() {
1778 let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1780 assert!(!emu.is_pcie_device());
1781
1782 let emu = create_type1_emulator(vec![Box::new(PciExpressCapability::new(
1784 DevicePortType::RootPort,
1785 None,
1786 ))]);
1787 assert!(emu.is_pcie_device());
1788
1789 let emu = create_type1_emulator(vec![
1791 Box::new(ReadOnlyCapability::new("foo", 0)),
1792 Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1793 Box::new(ReadOnlyCapability::new("bar", 0)),
1794 ]);
1795 assert!(emu.is_pcie_device());
1796 }
1797
1798 #[test]
1799 fn test_type0_is_pcie_device() {
1800 let emu = ConfigSpaceType0Emulator::new(
1802 HardwareIds {
1803 vendor_id: 0x1111,
1804 device_id: 0x2222,
1805 revision_id: 1,
1806 prog_if: ProgrammingInterface::NONE,
1807 sub_class: Subclass::NONE,
1808 base_class: ClassCode::UNCLASSIFIED,
1809 type0_sub_vendor_id: 0,
1810 type0_sub_system_id: 0,
1811 },
1812 vec![Box::new(ReadOnlyCapability::new("foo", 0))],
1813 DeviceBars::new(),
1814 );
1815 assert!(!emu.is_pcie_device());
1816
1817 let emu = ConfigSpaceType0Emulator::new(
1819 HardwareIds {
1820 vendor_id: 0x1111,
1821 device_id: 0x2222,
1822 revision_id: 1,
1823 prog_if: ProgrammingInterface::NONE,
1824 sub_class: Subclass::NONE,
1825 base_class: ClassCode::UNCLASSIFIED,
1826 type0_sub_vendor_id: 0,
1827 type0_sub_system_id: 0,
1828 },
1829 vec![Box::new(PciExpressCapability::new(
1830 DevicePortType::Endpoint,
1831 None,
1832 ))],
1833 DeviceBars::new(),
1834 );
1835 assert!(emu.is_pcie_device());
1836
1837 let emu = ConfigSpaceType0Emulator::new(
1839 HardwareIds {
1840 vendor_id: 0x1111,
1841 device_id: 0x2222,
1842 revision_id: 1,
1843 prog_if: ProgrammingInterface::NONE,
1844 sub_class: Subclass::NONE,
1845 base_class: ClassCode::UNCLASSIFIED,
1846 type0_sub_vendor_id: 0,
1847 type0_sub_system_id: 0,
1848 },
1849 vec![
1850 Box::new(ReadOnlyCapability::new("foo", 0)),
1851 Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1852 Box::new(ReadOnlyCapability::new("bar", 0)),
1853 ],
1854 DeviceBars::new(),
1855 );
1856 assert!(emu.is_pcie_device());
1857
1858 let emu = ConfigSpaceType0Emulator::new(
1860 HardwareIds {
1861 vendor_id: 0x1111,
1862 device_id: 0x2222,
1863 revision_id: 1,
1864 prog_if: ProgrammingInterface::NONE,
1865 sub_class: Subclass::NONE,
1866 base_class: ClassCode::UNCLASSIFIED,
1867 type0_sub_vendor_id: 0,
1868 type0_sub_system_id: 0,
1869 },
1870 vec![],
1871 DeviceBars::new(),
1872 );
1873 assert!(!emu.is_pcie_device());
1874 }
1875
1876 #[test]
1877 fn test_capability_ids() {
1878 let pcie_cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
1880 assert_eq!(pcie_cap.capability_id(), CapabilityId::PCI_EXPRESS);
1881
1882 let read_only_cap = ReadOnlyCapability::new("test", 0u32);
1883 assert_eq!(read_only_cap.capability_id(), CapabilityId::VENDOR_SPECIFIC);
1884 }
1885
1886 #[test]
1887 fn test_common_header_emulator_type0() {
1888 let hardware_ids = HardwareIds {
1890 vendor_id: 0x1111,
1891 device_id: 0x2222,
1892 revision_id: 1,
1893 prog_if: ProgrammingInterface::NONE,
1894 sub_class: Subclass::NONE,
1895 base_class: ClassCode::UNCLASSIFIED,
1896 type0_sub_vendor_id: 0,
1897 type0_sub_system_id: 0,
1898 };
1899
1900 let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1901
1902 let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1903 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1904
1905 assert_eq!(common_emu.hardware_ids().vendor_id, 0x1111);
1906 assert_eq!(common_emu.hardware_ids().device_id, 0x2222);
1907 assert!(!common_emu.multi_function_bit());
1908 assert!(!common_emu.is_pcie_device());
1909 assert_ne!(common_emu.bar_masks()[0], 0); }
1911
1912 #[test]
1913 fn test_common_header_emulator_type1() {
1914 let hardware_ids = HardwareIds {
1916 vendor_id: 0x3333,
1917 device_id: 0x4444,
1918 revision_id: 1,
1919 prog_if: ProgrammingInterface::NONE,
1920 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1921 base_class: ClassCode::BRIDGE,
1922 type0_sub_vendor_id: 0,
1923 type0_sub_system_id: 0,
1924 };
1925
1926 let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1927
1928 let mut common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
1929 ConfigSpaceCommonHeaderEmulator::new(
1930 hardware_ids,
1931 vec![Box::new(PciExpressCapability::new(
1932 DevicePortType::RootPort,
1933 None,
1934 ))],
1935 bars,
1936 )
1937 .with_multi_function_bit(true);
1938
1939 assert_eq!(common_emu.hardware_ids().vendor_id, 0x3333);
1940 assert_eq!(common_emu.hardware_ids().device_id, 0x4444);
1941 assert!(common_emu.multi_function_bit());
1942 assert!(common_emu.is_pcie_device());
1943 assert_ne!(common_emu.bar_masks()[0], 0); assert_eq!(common_emu.bar_masks().len(), 2);
1945
1946 common_emu.reset();
1948 assert_eq!(common_emu.capabilities().len(), 1); }
1950
1951 #[test]
1952 fn test_common_header_emulator_no_bars() {
1953 let hardware_ids = HardwareIds {
1955 vendor_id: 0x5555,
1956 device_id: 0x6666,
1957 revision_id: 1,
1958 prog_if: ProgrammingInterface::NONE,
1959 sub_class: Subclass::NONE,
1960 base_class: ClassCode::UNCLASSIFIED,
1961 type0_sub_vendor_id: 0,
1962 type0_sub_system_id: 0,
1963 };
1964
1965 let bars = DeviceBars::new();
1967
1968 let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1969 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1970
1971 assert_eq!(common_emu.hardware_ids().vendor_id, 0x5555);
1972 assert_eq!(common_emu.hardware_ids().device_id, 0x6666);
1973
1974 for &mask in common_emu.bar_masks() {
1976 assert_eq!(mask, 0);
1977 }
1978 }
1979
1980 #[test]
1981 fn test_common_header_emulator_type1_ignores_extra_bars() {
1982 let hardware_ids = HardwareIds {
1984 vendor_id: 0x7777,
1985 device_id: 0x8888,
1986 revision_id: 1,
1987 prog_if: ProgrammingInterface::NONE,
1988 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1989 base_class: ClassCode::BRIDGE,
1990 type0_sub_vendor_id: 0,
1991 type0_sub_system_id: 0,
1992 };
1993
1994 let bars = DeviceBars::new()
1996 .bar0(4096, BarMemoryKind::Dummy)
1997 .bar2(8192, BarMemoryKind::Dummy)
1998 .bar4(16384, BarMemoryKind::Dummy);
1999
2000 let common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
2001 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
2002
2003 assert_eq!(common_emu.hardware_ids().vendor_id, 0x7777);
2004 assert_eq!(common_emu.hardware_ids().device_id, 0x8888);
2005
2006 assert_ne!(common_emu.bar_masks()[0], 0); assert_ne!(common_emu.bar_masks()[1], 0); assert_eq!(common_emu.bar_masks().len(), 2); }
2014
2015 #[test]
2016 fn test_common_header_extended_capabilities() {
2017 let mut common_emu_no_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2019 HardwareIds {
2020 vendor_id: 0x1111,
2021 device_id: 0x2222,
2022 revision_id: 1,
2023 prog_if: ProgrammingInterface::NONE,
2024 sub_class: Subclass::NONE,
2025 base_class: ClassCode::UNCLASSIFIED,
2026 type0_sub_vendor_id: 0,
2027 type0_sub_system_id: 0,
2028 },
2029 vec![Box::new(ReadOnlyCapability::new("foo", 0))],
2030 DeviceBars::new(),
2031 );
2032 assert!(!common_emu_no_pcie.is_pcie_device());
2033
2034 let mut common_emu_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2035 HardwareIds {
2036 vendor_id: 0x1111,
2037 device_id: 0x2222,
2038 revision_id: 1,
2039 prog_if: ProgrammingInterface::NONE,
2040 sub_class: Subclass::NONE,
2041 base_class: ClassCode::UNCLASSIFIED,
2042 type0_sub_vendor_id: 0,
2043 type0_sub_system_id: 0,
2044 },
2045 vec![Box::new(PciExpressCapability::new(
2046 DevicePortType::Endpoint,
2047 None,
2048 ))],
2049 DeviceBars::new(),
2050 );
2051 assert!(common_emu_pcie.is_pcie_device());
2052
2053 let mut value = 0;
2055 assert!(matches!(
2056 common_emu_no_pcie.read_extended_capabilities(0x100, &mut value),
2057 CommonHeaderResult::Failed(IoError::InvalidRegister)
2058 ));
2059
2060 let mut value = 0;
2062 assert!(matches!(
2063 common_emu_pcie.read_extended_capabilities(0x100, &mut value),
2064 CommonHeaderResult::Handled
2065 ));
2066 assert_eq!(value, 0xffffffff);
2067
2068 assert!(matches!(
2070 common_emu_no_pcie.write_extended_capabilities(0x100, 0x1234),
2071 CommonHeaderResult::Failed(IoError::InvalidRegister)
2072 ));
2073
2074 assert!(matches!(
2076 common_emu_pcie.write_extended_capabilities(0x100, 0x1234),
2077 CommonHeaderResult::Handled
2078 ));
2079
2080 let mut value = 0;
2082 assert!(matches!(
2083 common_emu_pcie.read_extended_capabilities(0x99, &mut value),
2084 CommonHeaderResult::Failed(IoError::InvalidRegister)
2085 ));
2086 assert!(matches!(
2087 common_emu_pcie.read_extended_capabilities(0x1000, &mut value),
2088 CommonHeaderResult::Failed(IoError::InvalidRegister)
2089 ));
2090 }
2091
2092 #[test]
2093 fn test_type0_emulator_save_restore() {
2094 use vmcore::save_restore::SaveRestore;
2095
2096 let mut emu = create_type0_emulator(vec![]);
2098
2099 emu.write_u32(0x04, 0x0007).unwrap(); let mut test_val = 0u32;
2104 emu.read_u32(0x04, &mut test_val).unwrap();
2105 assert_eq!(test_val & 0x0007, 0x0007);
2106
2107 emu.write_u32(0x3C, 0x0040_0000).unwrap(); let saved_state = emu.save().expect("save should succeed");
2112
2113 emu.reset();
2115
2116 emu.read_u32(0x04, &mut test_val).unwrap();
2118 assert_eq!(test_val & 0x0007, 0x0000); emu.restore(saved_state).expect("restore should succeed");
2122
2123 emu.read_u32(0x04, &mut test_val).unwrap();
2125 assert_eq!(test_val & 0x0007, 0x0007); }
2127
2128 #[test]
2129 fn test_type1_emulator_save_restore() {
2130 use vmcore::save_restore::SaveRestore;
2131
2132 let mut emu = create_type1_emulator(vec![]);
2134
2135 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;
2146 emu.read_u32(0x04, &mut test_val).unwrap();
2147 assert_eq!(test_val & 0x0003, 0x0003);
2148 emu.read_u32(0x18, &mut test_val).unwrap();
2149 assert_eq!(test_val, 0x0012_1000);
2150 emu.read_u32(0x20, &mut test_val).unwrap();
2151 assert_eq!(test_val, 0xFFF0_FF00);
2152 emu.read_u32(0x28, &mut test_val).unwrap();
2153 assert_eq!(test_val, 0x00AA_BBCC);
2154 emu.read_u32(0x2C, &mut test_val).unwrap();
2155 assert_eq!(test_val, 0x00DD_EEFF);
2156 emu.read_u32(0x3C, &mut test_val).unwrap();
2157 assert_eq!(test_val >> 16, 0x0001); let saved_state = emu.save().expect("save should succeed");
2161
2162 emu.reset();
2164
2165 emu.read_u32(0x04, &mut test_val).unwrap();
2167 assert_eq!(test_val & 0x0003, 0x0000);
2168 emu.read_u32(0x18, &mut test_val).unwrap();
2169 assert_eq!(test_val, 0x0000_0000);
2170
2171 emu.restore(saved_state).expect("restore should succeed");
2173
2174 emu.read_u32(0x04, &mut test_val).unwrap();
2176 assert_eq!(test_val & 0x0003, 0x0003);
2177 emu.read_u32(0x18, &mut test_val).unwrap();
2178 assert_eq!(test_val, 0x0012_1000);
2179 emu.read_u32(0x20, &mut test_val).unwrap();
2180 assert_eq!(test_val, 0xFFF0_FF00);
2181 emu.read_u32(0x28, &mut test_val).unwrap();
2182 assert_eq!(test_val, 0x00AA_BBCC);
2183 emu.read_u32(0x2C, &mut test_val).unwrap();
2184 assert_eq!(test_val, 0x00DD_EEFF);
2185 emu.read_u32(0x3C, &mut test_val).unwrap();
2186 assert_eq!(test_val >> 16, 0x0001); }
2188
2189 #[test]
2190 fn test_config_space_type1_set_presence_detect_state() {
2191 let pcie_cap =
2196 PciExpressCapability::new(DevicePortType::RootPort, None).with_hotplug_support(1);
2197
2198 let mut emulator = create_type1_emulator(vec![Box::new(pcie_cap)]);
2199
2200 let mut slot_status_val = 0u32;
2202 let result = emulator.read_u32(0x58, &mut slot_status_val); assert!(matches!(result, IoResult::Ok));
2204 let initial_presence_detect = (slot_status_val >> 22) & 0x1; assert_eq!(
2206 initial_presence_detect, 0,
2207 "Initial presence detect state should be 0"
2208 );
2209
2210 emulator.set_presence_detect_state(true);
2212 let result = emulator.read_u32(0x58, &mut slot_status_val);
2213 assert!(matches!(result, IoResult::Ok));
2214 let present_presence_detect = (slot_status_val >> 22) & 0x1;
2215 assert_eq!(
2216 present_presence_detect, 1,
2217 "Presence detect state should be 1 when device is present"
2218 );
2219
2220 emulator.set_presence_detect_state(false);
2222 let result = emulator.read_u32(0x58, &mut slot_status_val);
2223 assert!(matches!(result, IoResult::Ok));
2224 let absent_presence_detect = (slot_status_val >> 22) & 0x1;
2225 assert_eq!(
2226 absent_presence_detect, 0,
2227 "Presence detect state should be 0 when device is not present"
2228 );
2229 }
2230
2231 #[test]
2232 fn test_config_space_type1_set_presence_detect_state_without_pcie() {
2233 let mut emulator = create_type1_emulator(vec![]); emulator.set_presence_detect_state(true);
2240 emulator.set_presence_detect_state(false);
2241 }
2242
2243 #[test]
2244 fn test_interrupt_pin_register() {
2245 use vmcore::line_interrupt::LineInterrupt;
2246
2247 let mut emu = ConfigSpaceType0Emulator::new(
2249 HardwareIds {
2250 vendor_id: 0x1111,
2251 device_id: 0x2222,
2252 revision_id: 1,
2253 prog_if: ProgrammingInterface::NONE,
2254 sub_class: Subclass::NONE,
2255 base_class: ClassCode::UNCLASSIFIED,
2256 type0_sub_vendor_id: 0,
2257 type0_sub_system_id: 0,
2258 },
2259 vec![],
2260 DeviceBars::new(),
2261 );
2262
2263 let mut val = 0u32;
2265 emu.read_u32(0x3C, &mut val).unwrap(); assert_eq!(val & 0xFF00, 0); let line_interrupt = LineInterrupt::detached();
2270 emu.set_interrupt_pin(PciInterruptPin::IntA, line_interrupt);
2271
2272 emu.read_u32(0x3C, &mut val).unwrap();
2274 assert_eq!((val >> 8) & 0xFF, 1); emu.write_u32(0x3C, 0x00110042).unwrap(); emu.read_u32(0x3C, &mut val).unwrap();
2279 assert_eq!(val & 0xFF, 0x42); assert_eq!((val >> 8) & 0xFF, 1); assert_eq!((val >> 16) & 0xFF, 0x11); let mut emu_d = ConfigSpaceType0Emulator::new(
2285 HardwareIds {
2286 vendor_id: 0x1111,
2287 device_id: 0x2222,
2288 revision_id: 1,
2289 prog_if: ProgrammingInterface::NONE,
2290 sub_class: Subclass::NONE,
2291 base_class: ClassCode::UNCLASSIFIED,
2292 type0_sub_vendor_id: 0,
2293 type0_sub_system_id: 0,
2294 },
2295 vec![],
2296 DeviceBars::new(),
2297 );
2298
2299 let line_interrupt_d = LineInterrupt::detached();
2300 emu_d.set_interrupt_pin(PciInterruptPin::IntD, line_interrupt_d);
2301
2302 emu_d.read_u32(0x3C, &mut val).unwrap();
2303 assert_eq!((val >> 8) & 0xFF, 4); }
2305
2306 #[test]
2307 fn test_header_type_functionality() {
2308 assert_eq!(HeaderType::Type0.bar_count(), 6);
2310 assert_eq!(HeaderType::Type1.bar_count(), 2);
2311 assert_eq!(usize::from(HeaderType::Type0), 6);
2312 assert_eq!(usize::from(HeaderType::Type1), 2);
2313
2314 assert_eq!(header_type_consts::TYPE0_BAR_COUNT, 6);
2316 assert_eq!(header_type_consts::TYPE1_BAR_COUNT, 2);
2317
2318 let emu_type0 = create_type0_emulator(vec![]);
2320 assert_eq!(emu_type0.common.bar_count(), 6);
2321 assert_eq!(emu_type0.common.header_type(), HeaderType::Type0);
2322 assert!(emu_type0.common.validate_header_type(HeaderType::Type0));
2323 assert!(!emu_type0.common.validate_header_type(HeaderType::Type1));
2324
2325 let emu_type1 = create_type1_emulator(vec![]);
2327 assert_eq!(emu_type1.common.bar_count(), 2);
2328 assert_eq!(emu_type1.common.header_type(), HeaderType::Type1);
2329 assert!(emu_type1.common.validate_header_type(HeaderType::Type1));
2330 assert!(!emu_type1.common.validate_header_type(HeaderType::Type0));
2331 }
2332}