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)]
1299 #[mesh(package = "pci.cfg_space_emu")]
1300 pub struct SavedState {
1301 #[mesh(1)]
1302 pub command: u16,
1303 #[mesh(2)]
1304 pub base_addresses: [u32; 6],
1305 #[mesh(3)]
1306 pub interrupt_line: u8,
1307 #[mesh(4)]
1308 pub latency_timer: u8,
1309 #[mesh(5)]
1310 pub capabilities: Vec<(String, SavedStateBlob)>,
1311 }
1312 }
1313
1314 #[derive(Debug, Error)]
1315 enum ConfigSpaceRestoreError {
1316 #[error("found invalid config bits in saved state")]
1317 InvalidConfigBits,
1318 #[error("found unexpected capability {0}")]
1319 InvalidCap(String),
1320 }
1321
1322 impl<const N: usize> SaveRestore for ConfigSpaceCommonHeaderEmulator<N> {
1323 type SavedState = state::SavedState;
1324
1325 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1326 tracing::info!(
1327 "ConfigSpaceCommonHeaderEmulator<{}>: starting save operation",
1328 N
1329 );
1330
1331 let ConfigSpaceCommonHeaderEmulatorState {
1332 command,
1333 base_addresses,
1334 interrupt_line,
1335 } = self.state;
1336
1337 let mut saved_base_addresses = [0u32; 6];
1339 for (i, &addr) in base_addresses.iter().enumerate() {
1340 if i < 6 {
1341 saved_base_addresses[i] = addr;
1342 }
1343 }
1344
1345 tracing::info!(
1346 "ConfigSpaceCommonHeaderEmulator<{}>: saving state - command={:#x}, interrupt_line={}, base_addresses={:?}",
1347 N,
1348 command.into_bits(),
1349 interrupt_line,
1350 saved_base_addresses
1351 );
1352
1353 let saved_state = state::SavedState {
1354 command: command.into_bits(),
1355 base_addresses: saved_base_addresses,
1356 interrupt_line,
1357 latency_timer: 0, capabilities: self
1359 .capabilities
1360 .iter_mut()
1361 .map(|cap| {
1362 let id = cap.label().to_owned();
1363 Ok((id, cap.save()?))
1364 })
1365 .collect::<Result<_, _>>()?,
1366 };
1367
1368 tracing::info!(
1369 "ConfigSpaceCommonHeaderEmulator<{}>: save operation completed successfully",
1370 N
1371 );
1372 Ok(saved_state)
1373 }
1374
1375 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1376 tracing::info!(
1377 "ConfigSpaceCommonHeaderEmulator<{}>: starting restore operation",
1378 N
1379 );
1380
1381 let state::SavedState {
1382 command,
1383 base_addresses,
1384 interrupt_line,
1385 latency_timer: _, capabilities,
1387 } = state;
1388
1389 tracing::info!(
1390 "ConfigSpaceCommonHeaderEmulator<{}>: restoring state - command={:#x}, interrupt_line={}, base_addresses={:?}",
1391 N,
1392 command,
1393 interrupt_line,
1394 base_addresses
1395 );
1396
1397 let mut restored_base_addresses = {
1399 const ZERO: u32 = 0;
1400 [ZERO; N]
1401 };
1402 for (i, &addr) in base_addresses.iter().enumerate() {
1403 if i < N {
1404 restored_base_addresses[i] = addr;
1405 }
1406 }
1407
1408 self.state = ConfigSpaceCommonHeaderEmulatorState {
1409 command: cfg_space::Command::from_bits(command),
1410 base_addresses: restored_base_addresses,
1411 interrupt_line,
1412 };
1413
1414 if command & !SUPPORTED_COMMAND_BITS != 0 {
1415 tracing::warn!(
1416 "ConfigSpaceCommonHeaderEmulator<{}>: invalid command bits found: {:#x}",
1417 N,
1418 command
1419 );
1420 return Err(RestoreError::InvalidSavedState(
1421 ConfigSpaceRestoreError::InvalidConfigBits.into(),
1422 ));
1423 }
1424
1425 tracing::info!(
1426 "ConfigSpaceCommonHeaderEmulator<{}>: syncing command register",
1427 N
1428 );
1429 self.sync_command_register(self.state.command);
1430
1431 tracing::info!(
1432 "ConfigSpaceCommonHeaderEmulator<{}>: restoring {} capabilities",
1433 N,
1434 capabilities.len()
1435 );
1436 for (id, entry) in capabilities {
1437 tracing::debug!(
1438 save_id = id.as_str(),
1439 "restoring pci common header capability"
1440 );
1441
1442 let mut restored = false;
1445 for cap in self.capabilities.iter_mut() {
1446 if cap.label() == id {
1447 cap.restore(entry)?;
1448 restored = true;
1449 break;
1450 }
1451 }
1452
1453 if !restored {
1454 tracing::error!(
1455 "ConfigSpaceCommonHeaderEmulator<{}>: failed to find capability: {}",
1456 N,
1457 id
1458 );
1459 return Err(RestoreError::InvalidSavedState(
1460 ConfigSpaceRestoreError::InvalidCap(id).into(),
1461 ));
1462 }
1463 }
1464
1465 tracing::info!(
1466 "ConfigSpaceCommonHeaderEmulator<{}>: restore operation completed successfully",
1467 N
1468 );
1469 Ok(())
1470 }
1471 }
1472
1473 mod type0_state {
1474 use super::state;
1475 use mesh::payload::Protobuf;
1476 use vmcore::save_restore::SavedStateRoot;
1477
1478 #[derive(Protobuf, SavedStateRoot)]
1479 #[mesh(package = "pci.cfg_space_emu")]
1480 pub struct SavedType0State {
1481 #[mesh(1)]
1482 pub latency_timer: u8,
1483 #[mesh(2)]
1484 pub common_header: state::SavedState,
1485 }
1486 }
1487
1488 impl SaveRestore for ConfigSpaceType0Emulator {
1489 type SavedState = type0_state::SavedType0State;
1490
1491 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1492 tracing::info!("ConfigSpaceType0Emulator: starting save operation");
1493
1494 let ConfigSpaceType0EmulatorState { latency_timer } = self.state;
1495
1496 tracing::info!(
1497 "ConfigSpaceType0Emulator: saving latency_timer={}",
1498 latency_timer
1499 );
1500
1501 let saved_state = type0_state::SavedType0State {
1502 latency_timer,
1503 common_header: self.common.save()?,
1504 };
1505
1506 tracing::info!("ConfigSpaceType0Emulator: save operation completed successfully");
1507 Ok(saved_state)
1508 }
1509
1510 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1511 tracing::info!("ConfigSpaceType0Emulator: starting restore operation");
1512
1513 let type0_state::SavedType0State {
1514 latency_timer,
1515 common_header,
1516 } = state;
1517
1518 tracing::info!(
1519 "ConfigSpaceType0Emulator: restoring latency_timer={}",
1520 latency_timer
1521 );
1522
1523 self.state = ConfigSpaceType0EmulatorState { latency_timer };
1524
1525 tracing::info!("ConfigSpaceType0Emulator: delegating to common header restore");
1526 self.common.restore(common_header)?;
1527
1528 tracing::info!("ConfigSpaceType0Emulator: restore operation completed successfully");
1529 Ok(())
1530 }
1531 }
1532
1533 mod type1_state {
1534 use super::state;
1535 use mesh::payload::Protobuf;
1536 use vmcore::save_restore::SavedStateRoot;
1537
1538 #[derive(Protobuf, SavedStateRoot)]
1539 #[mesh(package = "pci.cfg_space_emu")]
1540 pub struct SavedType1State {
1541 #[mesh(1)]
1542 pub subordinate_bus_number: u8,
1543 #[mesh(2)]
1544 pub secondary_bus_number: u8,
1545 #[mesh(3)]
1546 pub primary_bus_number: u8,
1547 #[mesh(4)]
1548 pub memory_base: u16,
1549 #[mesh(5)]
1550 pub memory_limit: u16,
1551 #[mesh(6)]
1552 pub prefetch_base: u16,
1553 #[mesh(7)]
1554 pub prefetch_limit: u16,
1555 #[mesh(8)]
1556 pub prefetch_base_upper: u32,
1557 #[mesh(9)]
1558 pub prefetch_limit_upper: u32,
1559 #[mesh(10)]
1560 pub bridge_control: u16,
1561 #[mesh(11)]
1562 pub common_header: state::SavedState,
1563 }
1564 }
1565
1566 impl SaveRestore for ConfigSpaceType1Emulator {
1567 type SavedState = type1_state::SavedType1State;
1568
1569 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1570 let ConfigSpaceType1EmulatorState {
1571 subordinate_bus_number,
1572 secondary_bus_number,
1573 primary_bus_number,
1574 memory_base,
1575 memory_limit,
1576 prefetch_base,
1577 prefetch_limit,
1578 prefetch_base_upper,
1579 prefetch_limit_upper,
1580 bridge_control,
1581 } = self.state;
1582
1583 let saved_state = type1_state::SavedType1State {
1584 subordinate_bus_number,
1585 secondary_bus_number,
1586 primary_bus_number,
1587 memory_base,
1588 memory_limit,
1589 prefetch_base,
1590 prefetch_limit,
1591 prefetch_base_upper,
1592 prefetch_limit_upper,
1593 bridge_control,
1594 common_header: self.common.save()?,
1595 };
1596
1597 Ok(saved_state)
1598 }
1599
1600 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1601 let type1_state::SavedType1State {
1602 subordinate_bus_number,
1603 secondary_bus_number,
1604 primary_bus_number,
1605 memory_base,
1606 memory_limit,
1607 prefetch_base,
1608 prefetch_limit,
1609 prefetch_base_upper,
1610 prefetch_limit_upper,
1611 bridge_control,
1612 common_header,
1613 } = state;
1614
1615 self.state = ConfigSpaceType1EmulatorState {
1616 subordinate_bus_number,
1617 secondary_bus_number,
1618 primary_bus_number,
1619 memory_base,
1620 memory_limit,
1621 prefetch_base,
1622 prefetch_limit,
1623 prefetch_base_upper,
1624 prefetch_limit_upper,
1625 bridge_control,
1626 };
1627
1628 self.common.restore(common_header)?;
1629
1630 Ok(())
1631 }
1632 }
1633}
1634
1635#[cfg(test)]
1636mod tests {
1637 use super::*;
1638 use crate::capabilities::pci_express::PciExpressCapability;
1639 use crate::capabilities::read_only::ReadOnlyCapability;
1640 use crate::spec::caps::pci_express::DevicePortType;
1641 use crate::spec::hwid::ClassCode;
1642 use crate::spec::hwid::ProgrammingInterface;
1643 use crate::spec::hwid::Subclass;
1644
1645 fn create_type0_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType0Emulator {
1646 ConfigSpaceType0Emulator::new(
1647 HardwareIds {
1648 vendor_id: 0x1111,
1649 device_id: 0x2222,
1650 revision_id: 1,
1651 prog_if: ProgrammingInterface::NONE,
1652 sub_class: Subclass::NONE,
1653 base_class: ClassCode::UNCLASSIFIED,
1654 type0_sub_vendor_id: 0x3333,
1655 type0_sub_system_id: 0x4444,
1656 },
1657 caps,
1658 DeviceBars::new(),
1659 )
1660 }
1661
1662 fn create_type1_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType1Emulator {
1663 ConfigSpaceType1Emulator::new(
1664 HardwareIds {
1665 vendor_id: 0x1111,
1666 device_id: 0x2222,
1667 revision_id: 1,
1668 prog_if: ProgrammingInterface::NONE,
1669 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1670 base_class: ClassCode::BRIDGE,
1671 type0_sub_vendor_id: 0,
1672 type0_sub_system_id: 0,
1673 },
1674 caps,
1675 )
1676 }
1677
1678 fn read_cfg(emulator: &ConfigSpaceType1Emulator, offset: u16) -> u32 {
1679 let mut val = 0;
1680 emulator.read_u32(offset, &mut val).unwrap();
1681 val
1682 }
1683
1684 #[test]
1685 fn test_type1_probe() {
1686 let emu = create_type1_emulator(vec![]);
1687 assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1688 assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0); let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1691 assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1692 assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0x10_0000); }
1694
1695 #[test]
1696 fn test_type1_bus_number_assignment() {
1697 let mut emu = create_type1_emulator(vec![]);
1698
1699 assert_eq!(read_cfg(&emu, 0x18), 0);
1702 assert_eq!(emu.assigned_bus_range(), 0..=0);
1703
1704 emu.write_u32(0x18, 0x0000_1000).unwrap();
1708 assert_eq!(read_cfg(&emu, 0x18), 0x0000_1000);
1709 assert_eq!(emu.assigned_bus_range(), 0..=0);
1710 emu.write_u32(0x18, 0x0012_1000).unwrap();
1711 assert_eq!(read_cfg(&emu, 0x18), 0x0012_1000);
1712 assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1713
1714 emu.write_u32(0x18, 0x0012_1033).unwrap();
1717 assert_eq!(read_cfg(&emu, 0x18), 0x0012_1033);
1718 assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1719
1720 emu.write_u32(0x18, 0x0047_4411).unwrap();
1722 assert_eq!(read_cfg(&emu, 0x18), 0x0047_4411);
1723 assert_eq!(emu.assigned_bus_range(), 0x44..=0x47);
1724
1725 emu.write_u32(0x18, 0x0088_8800).unwrap();
1727 assert_eq!(emu.assigned_bus_range(), 0x88..=0x88);
1728
1729 emu.write_u32(0x18, 0x0087_8800).unwrap();
1731 assert_eq!(emu.assigned_bus_range(), 0..=0);
1732 }
1733
1734 #[test]
1735 fn test_type1_memory_assignment() {
1736 const MMIO_ENABLED: u32 = 0x0000_0002;
1737 const MMIO_DISABLED: u32 = 0x0000_0000;
1738
1739 let mut emu = create_type1_emulator(vec![]);
1740 assert!(emu.assigned_memory_range().is_none());
1741
1742 emu.write_u32(0x20, 0xDEAD_BEEF).unwrap();
1745 assert!(emu.assigned_memory_range().is_none());
1746
1747 emu.write_u32(0x20, 0xFFF0_FF00).unwrap();
1749 assert!(emu.assigned_memory_range().is_none());
1750 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1752 assert_eq!(emu.assigned_memory_range(), Some(0xFF00_0000..=0xFFFF_FFFF));
1753 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1755 assert!(emu.assigned_memory_range().is_none());
1756
1757 emu.write_u32(0x20, 0xBBB0_BBB0).unwrap();
1759 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1760 assert_eq!(emu.assigned_memory_range(), Some(0xBBB0_0000..=0xBBBF_FFFF));
1761 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1762 assert!(emu.assigned_memory_range().is_none());
1763
1764 emu.write_u32(0x20, 0xAA00_BB00).unwrap();
1767 assert!(emu.assigned_memory_range().is_none());
1768 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1769 assert!(emu.assigned_memory_range().is_none());
1770 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1771 assert!(emu.assigned_memory_range().is_none());
1772 }
1773
1774 #[test]
1775 fn test_type1_prefetch_assignment() {
1776 const MMIO_ENABLED: u32 = 0x0000_0002;
1777 const MMIO_DISABLED: u32 = 0x0000_0000;
1778
1779 let mut emu = create_type1_emulator(vec![]);
1780 assert!(emu.assigned_prefetch_range().is_none());
1781
1782 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());
1787 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1789 assert_eq!(
1790 emu.assigned_prefetch_range(),
1791 Some(0x00AA_BBCC_FF00_0000..=0x00DD_EEFF_FFFF_FFFF)
1792 );
1793 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1795 assert!(emu.assigned_prefetch_range().is_none());
1796
1797 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());
1806 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1807 assert_eq!(
1808 emu.assigned_prefetch_range(),
1809 Some(0x00AA_BBCC_FFF0_0000..=0x00DD_EEFF_FF0F_FFFF)
1810 );
1811 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1812 assert!(emu.assigned_prefetch_range().is_none());
1813
1814 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());
1819 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1820 assert_eq!(
1821 emu.assigned_prefetch_range(),
1822 Some(0x00AA_BBCC_DD00_0000..=0x00AA_BBCC_DD0F_FFFF)
1823 );
1824 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1825 assert!(emu.assigned_prefetch_range().is_none());
1826 }
1827
1828 #[test]
1829 fn test_type1_is_pcie_device() {
1830 let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1832 assert!(!emu.is_pcie_device());
1833
1834 let emu = create_type1_emulator(vec![Box::new(PciExpressCapability::new(
1836 DevicePortType::RootPort,
1837 None,
1838 ))]);
1839 assert!(emu.is_pcie_device());
1840
1841 let emu = create_type1_emulator(vec![
1843 Box::new(ReadOnlyCapability::new("foo", 0)),
1844 Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1845 Box::new(ReadOnlyCapability::new("bar", 0)),
1846 ]);
1847 assert!(emu.is_pcie_device());
1848 }
1849
1850 #[test]
1851 fn test_type0_is_pcie_device() {
1852 let emu = ConfigSpaceType0Emulator::new(
1854 HardwareIds {
1855 vendor_id: 0x1111,
1856 device_id: 0x2222,
1857 revision_id: 1,
1858 prog_if: ProgrammingInterface::NONE,
1859 sub_class: Subclass::NONE,
1860 base_class: ClassCode::UNCLASSIFIED,
1861 type0_sub_vendor_id: 0,
1862 type0_sub_system_id: 0,
1863 },
1864 vec![Box::new(ReadOnlyCapability::new("foo", 0))],
1865 DeviceBars::new(),
1866 );
1867 assert!(!emu.is_pcie_device());
1868
1869 let emu = ConfigSpaceType0Emulator::new(
1871 HardwareIds {
1872 vendor_id: 0x1111,
1873 device_id: 0x2222,
1874 revision_id: 1,
1875 prog_if: ProgrammingInterface::NONE,
1876 sub_class: Subclass::NONE,
1877 base_class: ClassCode::UNCLASSIFIED,
1878 type0_sub_vendor_id: 0,
1879 type0_sub_system_id: 0,
1880 },
1881 vec![Box::new(PciExpressCapability::new(
1882 DevicePortType::Endpoint,
1883 None,
1884 ))],
1885 DeviceBars::new(),
1886 );
1887 assert!(emu.is_pcie_device());
1888
1889 let emu = ConfigSpaceType0Emulator::new(
1891 HardwareIds {
1892 vendor_id: 0x1111,
1893 device_id: 0x2222,
1894 revision_id: 1,
1895 prog_if: ProgrammingInterface::NONE,
1896 sub_class: Subclass::NONE,
1897 base_class: ClassCode::UNCLASSIFIED,
1898 type0_sub_vendor_id: 0,
1899 type0_sub_system_id: 0,
1900 },
1901 vec![
1902 Box::new(ReadOnlyCapability::new("foo", 0)),
1903 Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1904 Box::new(ReadOnlyCapability::new("bar", 0)),
1905 ],
1906 DeviceBars::new(),
1907 );
1908 assert!(emu.is_pcie_device());
1909
1910 let emu = ConfigSpaceType0Emulator::new(
1912 HardwareIds {
1913 vendor_id: 0x1111,
1914 device_id: 0x2222,
1915 revision_id: 1,
1916 prog_if: ProgrammingInterface::NONE,
1917 sub_class: Subclass::NONE,
1918 base_class: ClassCode::UNCLASSIFIED,
1919 type0_sub_vendor_id: 0,
1920 type0_sub_system_id: 0,
1921 },
1922 vec![],
1923 DeviceBars::new(),
1924 );
1925 assert!(!emu.is_pcie_device());
1926 }
1927
1928 #[test]
1929 fn test_capability_ids() {
1930 let pcie_cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
1932 assert_eq!(pcie_cap.capability_id(), CapabilityId::PCI_EXPRESS);
1933
1934 let read_only_cap = ReadOnlyCapability::new("test", 0u32);
1935 assert_eq!(read_only_cap.capability_id(), CapabilityId::VENDOR_SPECIFIC);
1936 }
1937
1938 #[test]
1939 fn test_common_header_emulator_type0() {
1940 let hardware_ids = HardwareIds {
1942 vendor_id: 0x1111,
1943 device_id: 0x2222,
1944 revision_id: 1,
1945 prog_if: ProgrammingInterface::NONE,
1946 sub_class: Subclass::NONE,
1947 base_class: ClassCode::UNCLASSIFIED,
1948 type0_sub_vendor_id: 0,
1949 type0_sub_system_id: 0,
1950 };
1951
1952 let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1953
1954 let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1955 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1956
1957 assert_eq!(common_emu.hardware_ids().vendor_id, 0x1111);
1958 assert_eq!(common_emu.hardware_ids().device_id, 0x2222);
1959 assert!(!common_emu.multi_function_bit());
1960 assert!(!common_emu.is_pcie_device());
1961 assert_ne!(common_emu.bar_masks()[0], 0); }
1963
1964 #[test]
1965 fn test_common_header_emulator_type1() {
1966 let hardware_ids = HardwareIds {
1968 vendor_id: 0x3333,
1969 device_id: 0x4444,
1970 revision_id: 1,
1971 prog_if: ProgrammingInterface::NONE,
1972 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1973 base_class: ClassCode::BRIDGE,
1974 type0_sub_vendor_id: 0,
1975 type0_sub_system_id: 0,
1976 };
1977
1978 let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1979
1980 let mut common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
1981 ConfigSpaceCommonHeaderEmulator::new(
1982 hardware_ids,
1983 vec![Box::new(PciExpressCapability::new(
1984 DevicePortType::RootPort,
1985 None,
1986 ))],
1987 bars,
1988 )
1989 .with_multi_function_bit(true);
1990
1991 assert_eq!(common_emu.hardware_ids().vendor_id, 0x3333);
1992 assert_eq!(common_emu.hardware_ids().device_id, 0x4444);
1993 assert!(common_emu.multi_function_bit());
1994 assert!(common_emu.is_pcie_device());
1995 assert_ne!(common_emu.bar_masks()[0], 0); assert_eq!(common_emu.bar_masks().len(), 2);
1997
1998 common_emu.reset();
2000 assert_eq!(common_emu.capabilities().len(), 1); }
2002
2003 #[test]
2004 fn test_common_header_emulator_no_bars() {
2005 let hardware_ids = HardwareIds {
2007 vendor_id: 0x5555,
2008 device_id: 0x6666,
2009 revision_id: 1,
2010 prog_if: ProgrammingInterface::NONE,
2011 sub_class: Subclass::NONE,
2012 base_class: ClassCode::UNCLASSIFIED,
2013 type0_sub_vendor_id: 0,
2014 type0_sub_system_id: 0,
2015 };
2016
2017 let bars = DeviceBars::new();
2019
2020 let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
2021 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
2022
2023 assert_eq!(common_emu.hardware_ids().vendor_id, 0x5555);
2024 assert_eq!(common_emu.hardware_ids().device_id, 0x6666);
2025
2026 for &mask in common_emu.bar_masks() {
2028 assert_eq!(mask, 0);
2029 }
2030 }
2031
2032 #[test]
2033 fn test_common_header_emulator_type1_ignores_extra_bars() {
2034 let hardware_ids = HardwareIds {
2036 vendor_id: 0x7777,
2037 device_id: 0x8888,
2038 revision_id: 1,
2039 prog_if: ProgrammingInterface::NONE,
2040 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
2041 base_class: ClassCode::BRIDGE,
2042 type0_sub_vendor_id: 0,
2043 type0_sub_system_id: 0,
2044 };
2045
2046 let bars = DeviceBars::new()
2048 .bar0(4096, BarMemoryKind::Dummy)
2049 .bar2(8192, BarMemoryKind::Dummy)
2050 .bar4(16384, BarMemoryKind::Dummy);
2051
2052 let common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
2053 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
2054
2055 assert_eq!(common_emu.hardware_ids().vendor_id, 0x7777);
2056 assert_eq!(common_emu.hardware_ids().device_id, 0x8888);
2057
2058 assert_ne!(common_emu.bar_masks()[0], 0); assert_ne!(common_emu.bar_masks()[1], 0); assert_eq!(common_emu.bar_masks().len(), 2); }
2066
2067 #[test]
2068 fn test_common_header_extended_capabilities() {
2069 let mut common_emu_no_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2071 HardwareIds {
2072 vendor_id: 0x1111,
2073 device_id: 0x2222,
2074 revision_id: 1,
2075 prog_if: ProgrammingInterface::NONE,
2076 sub_class: Subclass::NONE,
2077 base_class: ClassCode::UNCLASSIFIED,
2078 type0_sub_vendor_id: 0,
2079 type0_sub_system_id: 0,
2080 },
2081 vec![Box::new(ReadOnlyCapability::new("foo", 0))],
2082 DeviceBars::new(),
2083 );
2084 assert!(!common_emu_no_pcie.is_pcie_device());
2085
2086 let mut common_emu_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2087 HardwareIds {
2088 vendor_id: 0x1111,
2089 device_id: 0x2222,
2090 revision_id: 1,
2091 prog_if: ProgrammingInterface::NONE,
2092 sub_class: Subclass::NONE,
2093 base_class: ClassCode::UNCLASSIFIED,
2094 type0_sub_vendor_id: 0,
2095 type0_sub_system_id: 0,
2096 },
2097 vec![Box::new(PciExpressCapability::new(
2098 DevicePortType::Endpoint,
2099 None,
2100 ))],
2101 DeviceBars::new(),
2102 );
2103 assert!(common_emu_pcie.is_pcie_device());
2104
2105 let mut value = 0;
2107 assert!(matches!(
2108 common_emu_no_pcie.read_extended_capabilities(0x100, &mut value),
2109 CommonHeaderResult::Failed(IoError::InvalidRegister)
2110 ));
2111
2112 let mut value = 0;
2114 assert!(matches!(
2115 common_emu_pcie.read_extended_capabilities(0x100, &mut value),
2116 CommonHeaderResult::Handled
2117 ));
2118 assert_eq!(value, 0xffffffff);
2119
2120 assert!(matches!(
2122 common_emu_no_pcie.write_extended_capabilities(0x100, 0x1234),
2123 CommonHeaderResult::Failed(IoError::InvalidRegister)
2124 ));
2125
2126 assert!(matches!(
2128 common_emu_pcie.write_extended_capabilities(0x100, 0x1234),
2129 CommonHeaderResult::Handled
2130 ));
2131
2132 let mut value = 0;
2134 assert!(matches!(
2135 common_emu_pcie.read_extended_capabilities(0x99, &mut value),
2136 CommonHeaderResult::Failed(IoError::InvalidRegister)
2137 ));
2138 assert!(matches!(
2139 common_emu_pcie.read_extended_capabilities(0x1000, &mut value),
2140 CommonHeaderResult::Failed(IoError::InvalidRegister)
2141 ));
2142 }
2143
2144 #[test]
2145 fn test_common_header_emulator_save_restore() {
2146 use vmcore::save_restore::SaveRestore;
2147
2148 let hardware_ids = HardwareIds {
2150 vendor_id: 0x1111,
2151 device_id: 0x2222,
2152 revision_id: 1,
2153 prog_if: ProgrammingInterface::NONE,
2154 sub_class: Subclass::NONE,
2155 base_class: ClassCode::UNCLASSIFIED,
2156 type0_sub_vendor_id: 0,
2157 type0_sub_system_id: 0,
2158 };
2159
2160 let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
2161
2162 let mut common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
2163 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
2164
2165 let mut test_val = 0u32;
2167 let result = common_emu.write_u32(0x04, 0x0007); assert_eq!(result, CommonHeaderResult::Handled);
2169 let result = common_emu.read_u32(0x04, &mut test_val);
2170 assert_eq!(result, CommonHeaderResult::Handled);
2171 assert_eq!(test_val & 0x0007, 0x0007);
2172
2173 let saved_state = common_emu.save().expect("save should succeed");
2175
2176 common_emu.reset();
2178 let result = common_emu.read_u32(0x04, &mut test_val);
2179 assert_eq!(result, CommonHeaderResult::Handled);
2180 assert_eq!(test_val & 0x0007, 0x0000); common_emu
2184 .restore(saved_state)
2185 .expect("restore should succeed");
2186 let result = common_emu.read_u32(0x04, &mut test_val);
2187 assert_eq!(result, CommonHeaderResult::Handled);
2188 assert_eq!(test_val & 0x0007, 0x0007); let hardware_ids = HardwareIds {
2192 vendor_id: 0x3333,
2193 device_id: 0x4444,
2194 revision_id: 1,
2195 prog_if: ProgrammingInterface::NONE,
2196 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
2197 base_class: ClassCode::BRIDGE,
2198 type0_sub_vendor_id: 0,
2199 type0_sub_system_id: 0,
2200 };
2201
2202 let bars = DeviceBars::new(); let mut common_emu_type1: ConfigSpaceCommonHeaderEmulatorType1 =
2205 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
2206
2207 let result = common_emu_type1.write_u32(0x04, 0x0003); assert_eq!(result, CommonHeaderResult::Handled);
2210 let result = common_emu_type1.read_u32(0x04, &mut test_val);
2211 assert_eq!(result, CommonHeaderResult::Handled);
2212 assert_eq!(test_val & 0x0003, 0x0003);
2213
2214 let saved_state = common_emu_type1.save().expect("save should succeed");
2216
2217 common_emu_type1.reset();
2219 let result = common_emu_type1.read_u32(0x04, &mut test_val);
2220 assert_eq!(result, CommonHeaderResult::Handled);
2221 assert_eq!(test_val & 0x0003, 0x0000); common_emu_type1
2225 .restore(saved_state)
2226 .expect("restore should succeed");
2227 let result = common_emu_type1.read_u32(0x04, &mut test_val);
2228 assert_eq!(result, CommonHeaderResult::Handled);
2229 assert_eq!(test_val & 0x0003, 0x0003); }
2231
2232 #[test]
2233 fn test_config_space_type1_set_presence_detect_state() {
2234 let pcie_cap =
2239 PciExpressCapability::new(DevicePortType::RootPort, None).with_hotplug_support(1);
2240
2241 let mut emulator = create_type1_emulator(vec![Box::new(pcie_cap)]);
2242
2243 let mut slot_status_val = 0u32;
2245 let result = emulator.read_u32(0x58, &mut slot_status_val); assert!(matches!(result, IoResult::Ok));
2247 let initial_presence_detect = (slot_status_val >> 22) & 0x1; assert_eq!(
2249 initial_presence_detect, 0,
2250 "Initial presence detect state should be 0"
2251 );
2252
2253 emulator.set_presence_detect_state(true);
2255 let result = emulator.read_u32(0x58, &mut slot_status_val);
2256 assert!(matches!(result, IoResult::Ok));
2257 let present_presence_detect = (slot_status_val >> 22) & 0x1;
2258 assert_eq!(
2259 present_presence_detect, 1,
2260 "Presence detect state should be 1 when device is present"
2261 );
2262
2263 emulator.set_presence_detect_state(false);
2265 let result = emulator.read_u32(0x58, &mut slot_status_val);
2266 assert!(matches!(result, IoResult::Ok));
2267 let absent_presence_detect = (slot_status_val >> 22) & 0x1;
2268 assert_eq!(
2269 absent_presence_detect, 0,
2270 "Presence detect state should be 0 when device is not present"
2271 );
2272 }
2273
2274 #[test]
2275 fn test_config_space_type1_set_presence_detect_state_without_pcie() {
2276 let mut emulator = create_type1_emulator(vec![]); emulator.set_presence_detect_state(true);
2283 emulator.set_presence_detect_state(false);
2284 }
2285
2286 #[test]
2287 fn test_interrupt_pin_register() {
2288 use vmcore::line_interrupt::LineInterrupt;
2289
2290 let mut emu = ConfigSpaceType0Emulator::new(
2292 HardwareIds {
2293 vendor_id: 0x1111,
2294 device_id: 0x2222,
2295 revision_id: 1,
2296 prog_if: ProgrammingInterface::NONE,
2297 sub_class: Subclass::NONE,
2298 base_class: ClassCode::UNCLASSIFIED,
2299 type0_sub_vendor_id: 0,
2300 type0_sub_system_id: 0,
2301 },
2302 vec![],
2303 DeviceBars::new(),
2304 );
2305
2306 let mut val = 0u32;
2308 emu.read_u32(0x3C, &mut val).unwrap(); assert_eq!(val & 0xFF00, 0); let line_interrupt = LineInterrupt::detached();
2313 emu.set_interrupt_pin(PciInterruptPin::IntA, line_interrupt);
2314
2315 emu.read_u32(0x3C, &mut val).unwrap();
2317 assert_eq!((val >> 8) & 0xFF, 1); emu.write_u32(0x3C, 0x00110042).unwrap(); emu.read_u32(0x3C, &mut val).unwrap();
2322 assert_eq!(val & 0xFF, 0x42); assert_eq!((val >> 8) & 0xFF, 1); assert_eq!((val >> 16) & 0xFF, 0x11); let mut emu_d = ConfigSpaceType0Emulator::new(
2328 HardwareIds {
2329 vendor_id: 0x1111,
2330 device_id: 0x2222,
2331 revision_id: 1,
2332 prog_if: ProgrammingInterface::NONE,
2333 sub_class: Subclass::NONE,
2334 base_class: ClassCode::UNCLASSIFIED,
2335 type0_sub_vendor_id: 0,
2336 type0_sub_system_id: 0,
2337 },
2338 vec![],
2339 DeviceBars::new(),
2340 );
2341
2342 let line_interrupt_d = LineInterrupt::detached();
2343 emu_d.set_interrupt_pin(PciInterruptPin::IntD, line_interrupt_d);
2344
2345 emu_d.read_u32(0x3C, &mut val).unwrap();
2346 assert_eq!((val >> 8) & 0xFF, 4); }
2348
2349 #[test]
2350 fn test_header_type_functionality() {
2351 assert_eq!(HeaderType::Type0.bar_count(), 6);
2353 assert_eq!(HeaderType::Type1.bar_count(), 2);
2354 assert_eq!(usize::from(HeaderType::Type0), 6);
2355 assert_eq!(usize::from(HeaderType::Type1), 2);
2356
2357 assert_eq!(header_type_consts::TYPE0_BAR_COUNT, 6);
2359 assert_eq!(header_type_consts::TYPE1_BAR_COUNT, 2);
2360
2361 let emu_type0 = create_type0_emulator(vec![]);
2363 assert_eq!(emu_type0.common.bar_count(), 6);
2364 assert_eq!(emu_type0.common.header_type(), HeaderType::Type0);
2365 assert!(emu_type0.common.validate_header_type(HeaderType::Type0));
2366 assert!(!emu_type0.common.validate_header_type(HeaderType::Type1));
2367
2368 let emu_type1 = create_type1_emulator(vec![]);
2370 assert_eq!(emu_type1.common.bar_count(), 2);
2371 assert_eq!(emu_type1.common.header_type(), HeaderType::Type1);
2372 assert!(emu_type1.common.validate_header_type(HeaderType::Type1));
2373 assert!(!emu_type1.common.validate_header_type(HeaderType::Type0));
2374 }
2375}