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, u64)> {
708 self.active_bars.find(address)
709 }
710
711 pub fn bar_address(&self, bar: u8) -> Option<u64> {
713 self.active_bars.get(bar)
714 }
715
716 pub fn is_pcie_device(&self) -> bool {
718 self.capabilities
719 .iter()
720 .any(|cap| cap.capability_id() == CapabilityId::PCI_EXPRESS)
721 }
722
723 fn get_capability_index_and_offset(&self, offset: u16) -> Option<(usize, u16)> {
725 let mut cap_offset = 0;
726 for i in 0..self.capabilities.len() {
727 let cap_size = self.capabilities[i].len() as u16;
728 if offset < cap_offset + cap_size {
729 return Some((i, offset - cap_offset));
730 }
731 cap_offset += cap_size;
732 }
733 None
734 }
735
736 fn is_bar_offset(&self, offset: u16) -> bool {
738 let bar_start = cfg_space::HeaderType00::BAR0.0;
740 let bar_end = bar_start + (N as u16) * 4;
741 (bar_start..bar_end).contains(&offset) && offset.is_multiple_of(4)
742 }
743
744 fn get_bar_index(&self, offset: u16) -> usize {
746 ((offset - cfg_space::HeaderType00::BAR0.0) / 4) as usize
747 }
748
749 #[cfg(test)]
751 pub fn bar_masks(&self) -> &[u32; N] {
752 &self.bar_masks
753 }
754}
755
756#[derive(Debug, Inspect)]
757struct ConfigSpaceType0EmulatorState {
758 latency_timer: u8,
760}
761
762impl ConfigSpaceType0EmulatorState {
763 fn new() -> Self {
764 Self { latency_timer: 0 }
765 }
766}
767
768#[derive(Inspect)]
770pub struct ConfigSpaceType0Emulator {
771 #[inspect(flatten)]
773 common: ConfigSpaceCommonHeaderEmulatorType0,
774 state: ConfigSpaceType0EmulatorState,
776}
777
778mod inspect_helpers {
779 use super::*;
780
781 pub(crate) fn bars_generic<const N: usize>(bars: &[u32; N]) -> impl Inspect + '_ {
782 inspect::AsHex(inspect::iter_by_index(bars).prefix("bar"))
783 }
784}
785
786#[derive(Inspect)]
788#[inspect(tag = "kind")]
789pub enum BarMemoryKind {
790 Intercept(#[inspect(rename = "handle")] Box<dyn ControlMmioIntercept>),
792 SharedMem(#[inspect(skip)] Box<dyn MappableGuestMemory>),
794 Dummy,
796}
797
798impl std::fmt::Debug for BarMemoryKind {
799 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
800 match self {
801 Self::Intercept(control) => {
802 write!(f, "Intercept(region_name: {}, ..)", control.region_name())
803 }
804 Self::SharedMem(_) => write!(f, "Mmap(..)"),
805 Self::Dummy => write!(f, "Dummy"),
806 }
807 }
808}
809
810impl BarMemoryKind {
811 fn map_to_guest(&mut self, gpa: u64) -> std::io::Result<()> {
812 match self {
813 BarMemoryKind::Intercept(control) => {
814 control.map(gpa);
815 Ok(())
816 }
817 BarMemoryKind::SharedMem(control) => control.map_to_guest(gpa, true),
818 BarMemoryKind::Dummy => Ok(()),
819 }
820 }
821
822 fn unmap_from_guest(&mut self) {
823 match self {
824 BarMemoryKind::Intercept(control) => control.unmap(),
825 BarMemoryKind::SharedMem(control) => control.unmap_from_guest(),
826 BarMemoryKind::Dummy => {}
827 }
828 }
829}
830
831#[derive(Debug)]
836pub struct DeviceBars {
837 bars: [Option<(u64, BarMemoryKind)>; 6],
838}
839
840impl DeviceBars {
841 pub fn new() -> DeviceBars {
843 DeviceBars {
844 bars: Default::default(),
845 }
846 }
847
848 pub fn bar0(mut self, len: u64, memory: BarMemoryKind) -> Self {
850 self.bars[0] = Some((len, memory));
851 self
852 }
853
854 pub fn bar2(mut self, len: u64, memory: BarMemoryKind) -> Self {
856 self.bars[2] = Some((len, memory));
857 self
858 }
859
860 pub fn bar4(mut self, len: u64, memory: BarMemoryKind) -> Self {
862 self.bars[4] = Some((len, memory));
863 self
864 }
865}
866
867impl ConfigSpaceType0Emulator {
868 pub fn new(
870 hardware_ids: HardwareIds,
871 capabilities: Vec<Box<dyn PciCapability>>,
872 bars: DeviceBars,
873 ) -> Self {
874 let common = ConfigSpaceCommonHeaderEmulator::new(hardware_ids, capabilities, bars);
875
876 Self {
877 common,
878 state: ConfigSpaceType0EmulatorState::new(),
879 }
880 }
881
882 pub fn with_multi_function_bit(mut self, bit: bool) -> Self {
884 self.common = self.common.with_multi_function_bit(bit);
885 self
886 }
887
888 pub fn set_interrupt_pin(
892 &mut self,
893 pin: PciInterruptPin,
894 line: LineInterrupt,
895 ) -> Arc<IntxInterrupt> {
896 self.common.set_interrupt_pin(pin, line)
897 }
898
899 pub fn reset(&mut self) {
901 self.common.reset();
902 self.state = ConfigSpaceType0EmulatorState::new();
903 }
904
905 pub fn read_u32(&self, offset: u16, value: &mut u32) -> IoResult {
907 use cfg_space::HeaderType00;
908
909 match self.common.read_u32(offset, value) {
911 CommonHeaderResult::Handled => return IoResult::Ok,
912 CommonHeaderResult::Failed(err) => return IoResult::Err(err),
913 CommonHeaderResult::Unhandled => {
914 }
916 }
917
918 *value = match HeaderType00(offset) {
920 HeaderType00::BIST_HEADER => {
921 let mut v = (self.state.latency_timer as u32) << 8;
922 if self.common.multi_function_bit() {
923 v |= 0x80 << 16;
925 }
926 v
927 }
928 HeaderType00::CARDBUS_CIS_PTR => 0,
929 HeaderType00::SUBSYSTEM_ID => {
930 (self.common.hardware_ids().type0_sub_system_id as u32) << 16
931 | self.common.hardware_ids().type0_sub_vendor_id as u32
932 }
933 HeaderType00::EXPANSION_ROM_BASE => 0,
934 HeaderType00::RESERVED => 0,
935 HeaderType00::LATENCY_INTERRUPT => {
936 (self.state.latency_timer as u32) << 16
938 | (self.common.interrupt_pin() as u32) << 8
939 | self.common.interrupt_line() as u32
940 }
941 _ => {
942 tracelimit::warn_ratelimited!(offset, "unexpected config space read");
943 return IoResult::Err(IoError::InvalidRegister);
944 }
945 };
946
947 IoResult::Ok
948 }
949
950 pub fn write_u32(&mut self, offset: u16, val: u32) -> IoResult {
952 use cfg_space::HeaderType00;
953
954 match self.common.write_u32(offset, val) {
956 CommonHeaderResult::Handled => return IoResult::Ok,
957 CommonHeaderResult::Failed(err) => return IoResult::Err(err),
958 CommonHeaderResult::Unhandled => {
959 }
961 }
962
963 match HeaderType00(offset) {
965 HeaderType00::BIST_HEADER => {
966 }
969 HeaderType00::LATENCY_INTERRUPT => {
970 self.common.set_interrupt_line((val & 0xff) as u8);
974 self.state.latency_timer = (val >> 16) as u8;
975 }
976 _ if offset < 0x40 && offset.is_multiple_of(4) => (),
978 _ => {
979 tracelimit::warn_ratelimited!(offset, value = val, "unexpected config space write");
980 return IoResult::Err(IoError::InvalidRegister);
981 }
982 }
983
984 IoResult::Ok
985 }
986
987 pub fn find_bar(&self, address: u64) -> Option<(u8, u64)> {
989 self.common.find_bar(address)
990 }
991
992 pub fn bar_address(&self, bar: u8) -> Option<u64> {
994 self.common.bar_address(bar)
995 }
996
997 pub fn is_pcie_device(&self) -> bool {
999 self.common.is_pcie_device()
1000 }
1001
1002 pub fn set_presence_detect_state(&mut self, present: bool) {
1009 for capability in self.common.capabilities_mut() {
1010 if let Some(pcie_cap) = capability.as_pci_express_mut() {
1011 pcie_cap.set_presence_detect_state(present);
1012 return;
1013 }
1014 }
1015
1016 }
1018}
1019
1020#[derive(Debug, Inspect)]
1021struct ConfigSpaceType1EmulatorState {
1022 #[inspect(hex)]
1025 subordinate_bus_number: u8,
1026 #[inspect(hex)]
1030 secondary_bus_number: u8,
1031 #[inspect(hex)]
1034 primary_bus_number: u8,
1035 #[inspect(hex)]
1039 memory_base: u16,
1040 #[inspect(hex)]
1044 memory_limit: u16,
1045 #[inspect(hex)]
1050 prefetch_base: u16,
1051 #[inspect(hex)]
1056 prefetch_limit: u16,
1057 #[inspect(hex)]
1062 prefetch_base_upper: u32,
1063 #[inspect(hex)]
1068 prefetch_limit_upper: u32,
1069 #[inspect(hex)]
1072 bridge_control: u16,
1073}
1074
1075impl ConfigSpaceType1EmulatorState {
1076 fn new() -> Self {
1077 Self {
1078 subordinate_bus_number: 0,
1079 secondary_bus_number: 0,
1080 primary_bus_number: 0,
1081 memory_base: 0,
1082 memory_limit: 0,
1083 prefetch_base: 0,
1084 prefetch_limit: 0,
1085 prefetch_base_upper: 0,
1086 prefetch_limit_upper: 0,
1087 bridge_control: 0,
1088 }
1089 }
1090}
1091
1092#[derive(Inspect)]
1094pub struct ConfigSpaceType1Emulator {
1095 #[inspect(flatten)]
1097 common: ConfigSpaceCommonHeaderEmulatorType1,
1098 state: ConfigSpaceType1EmulatorState,
1100}
1101
1102impl ConfigSpaceType1Emulator {
1103 pub fn new(hardware_ids: HardwareIds, capabilities: Vec<Box<dyn PciCapability>>) -> Self {
1105 let common =
1106 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, capabilities, DeviceBars::new());
1107
1108 Self {
1109 common,
1110 state: ConfigSpaceType1EmulatorState::new(),
1111 }
1112 }
1113
1114 pub fn reset(&mut self) {
1116 self.common.reset();
1117 self.state = ConfigSpaceType1EmulatorState::new();
1118 }
1119
1120 pub fn with_multi_function_bit(mut self, multi_function: bool) -> Self {
1122 self.common = self.common.with_multi_function_bit(multi_function);
1123 self
1124 }
1125
1126 pub fn assigned_bus_range(&self) -> RangeInclusive<u8> {
1128 let secondary = self.state.secondary_bus_number;
1129 let subordinate = self.state.subordinate_bus_number;
1130 if secondary <= subordinate {
1131 secondary..=subordinate
1132 } else {
1133 0..=0
1134 }
1135 }
1136
1137 fn decode_memory_range(&self, base_register: u16, limit_register: u16) -> (u32, u32) {
1138 let base_addr = ((base_register & !0b1111) as u32) << 16;
1139 let limit_addr = ((limit_register & !0b1111) as u32) << 16 | 0xF_FFFF;
1140 (base_addr, limit_addr)
1141 }
1142
1143 pub fn assigned_memory_range(&self) -> Option<RangeInclusive<u32>> {
1146 let (base_addr, limit_addr) =
1147 self.decode_memory_range(self.state.memory_base, self.state.memory_limit);
1148 if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1149 Some(base_addr..=limit_addr)
1150 } else {
1151 None
1152 }
1153 }
1154
1155 pub fn assigned_prefetch_range(&self) -> Option<RangeInclusive<u64>> {
1158 let (base_low, limit_low) =
1159 self.decode_memory_range(self.state.prefetch_base, self.state.prefetch_limit);
1160 let base_addr = (self.state.prefetch_base_upper as u64) << 32 | base_low as u64;
1161 let limit_addr = (self.state.prefetch_limit_upper as u64) << 32 | limit_low as u64;
1162 if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1163 Some(base_addr..=limit_addr)
1164 } else {
1165 None
1166 }
1167 }
1168
1169 pub fn read_u32(&self, offset: u16, value: &mut u32) -> IoResult {
1171 use cfg_space::HeaderType01;
1172
1173 match self.common.read_u32(offset, value) {
1175 CommonHeaderResult::Handled => return IoResult::Ok,
1176 CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1177 CommonHeaderResult::Unhandled => {
1178 }
1180 }
1181
1182 *value = match HeaderType01(offset) {
1184 HeaderType01::BIST_HEADER => {
1185 if self.common.multi_function_bit() {
1187 0x00810000 } else {
1189 0x00010000 }
1191 }
1192 HeaderType01::LATENCY_BUS_NUMBERS => {
1193 (self.state.subordinate_bus_number as u32) << 16
1194 | (self.state.secondary_bus_number as u32) << 8
1195 | self.state.primary_bus_number as u32
1196 }
1197 HeaderType01::SEC_STATUS_IO_RANGE => 0,
1198 HeaderType01::MEMORY_RANGE => {
1199 (self.state.memory_limit as u32) << 16 | self.state.memory_base as u32
1200 }
1201 HeaderType01::PREFETCH_RANGE => {
1202 ((self.state.prefetch_limit | 0b0001) as u32) << 16
1205 | (self.state.prefetch_base | 0b0001) as u32
1206 }
1207 HeaderType01::PREFETCH_BASE_UPPER => self.state.prefetch_base_upper,
1208 HeaderType01::PREFETCH_LIMIT_UPPER => self.state.prefetch_limit_upper,
1209 HeaderType01::IO_RANGE_UPPER => 0,
1210 HeaderType01::EXPANSION_ROM_BASE => 0,
1211 HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1212 (self.state.bridge_control as u32) << 16 | self.common.interrupt_line() as u32
1215 }
1216 _ => {
1217 tracelimit::warn_ratelimited!(offset, "unexpected config space read");
1218 return IoResult::Err(IoError::InvalidRegister);
1219 }
1220 };
1221
1222 IoResult::Ok
1223 }
1224
1225 pub fn write_u32(&mut self, offset: u16, val: u32) -> IoResult {
1227 use cfg_space::HeaderType01;
1228
1229 match self.common.write_u32(offset, val) {
1231 CommonHeaderResult::Handled => return IoResult::Ok,
1232 CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1233 CommonHeaderResult::Unhandled => {
1234 }
1236 }
1237
1238 match HeaderType01(offset) {
1240 HeaderType01::BIST_HEADER => {
1241 }
1244 HeaderType01::LATENCY_BUS_NUMBERS => {
1245 self.state.subordinate_bus_number = (val >> 16) as u8;
1246 self.state.secondary_bus_number = (val >> 8) as u8;
1247 self.state.primary_bus_number = val as u8;
1248 }
1249 HeaderType01::MEMORY_RANGE => {
1250 self.state.memory_base = val as u16;
1251 self.state.memory_limit = (val >> 16) as u16;
1252 }
1253 HeaderType01::PREFETCH_RANGE => {
1254 self.state.prefetch_base = val as u16;
1255 self.state.prefetch_limit = (val >> 16) as u16;
1256 }
1257 HeaderType01::PREFETCH_BASE_UPPER => {
1258 self.state.prefetch_base_upper = val;
1259 }
1260 HeaderType01::PREFETCH_LIMIT_UPPER => {
1261 self.state.prefetch_limit_upper = val;
1262 }
1263 HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1264 self.common.set_interrupt_line((val & 0xff) as u8);
1267 self.state.bridge_control = (val >> 16) as u16;
1268 }
1269 _ if offset < 0x40 && offset.is_multiple_of(4) => (),
1271 _ => {
1272 tracelimit::warn_ratelimited!(offset, value = val, "unexpected config space write");
1273 return IoResult::Err(IoError::InvalidRegister);
1274 }
1275 }
1276
1277 IoResult::Ok
1278 }
1279
1280 pub fn is_pcie_device(&self) -> bool {
1282 self.common.is_pcie_device()
1283 }
1284
1285 pub fn set_presence_detect_state(&mut self, present: bool) {
1292 for cap in self.common.capabilities_mut() {
1294 if cap.capability_id() == CapabilityId::PCI_EXPRESS {
1295 if let Some(pcie_cap) = cap.as_pci_express_mut() {
1297 pcie_cap.set_presence_detect_state(present);
1298 return;
1299 }
1300 }
1301 }
1302 }
1304
1305 pub fn capabilities(&self) -> &[Box<dyn PciCapability>] {
1307 self.common.capabilities()
1308 }
1309
1310 pub fn capabilities_mut(&mut self) -> &mut [Box<dyn PciCapability>] {
1312 self.common.capabilities_mut()
1313 }
1314}
1315
1316mod save_restore {
1317 use super::*;
1318 use thiserror::Error;
1319 use vmcore::save_restore::RestoreError;
1320 use vmcore::save_restore::SaveError;
1321 use vmcore::save_restore::SaveRestore;
1322
1323 mod state {
1324 use mesh::payload::Protobuf;
1325 use vmcore::save_restore::SavedStateBlob;
1326 use vmcore::save_restore::SavedStateRoot;
1327
1328 #[derive(Protobuf, SavedStateRoot)]
1332 #[mesh(package = "pci.cfg_space_emu")]
1333 pub struct SavedState {
1334 #[mesh(1)]
1336 pub command: u16,
1337 #[mesh(2)]
1338 pub base_addresses: [u32; 6],
1339 #[mesh(3)]
1340 pub interrupt_line: u8,
1341 #[mesh(4)]
1342 pub latency_timer: u8,
1343 #[mesh(5)]
1344 pub capabilities: Vec<(String, SavedStateBlob)>,
1345
1346 #[mesh(6)]
1349 pub subordinate_bus_number: u8,
1350 #[mesh(7)]
1351 pub secondary_bus_number: u8,
1352 #[mesh(8)]
1353 pub primary_bus_number: u8,
1354 #[mesh(9)]
1355 pub memory_base: u16,
1356 #[mesh(10)]
1357 pub memory_limit: u16,
1358 #[mesh(11)]
1359 pub prefetch_base: u16,
1360 #[mesh(12)]
1361 pub prefetch_limit: u16,
1362 #[mesh(13)]
1363 pub prefetch_base_upper: u32,
1364 #[mesh(14)]
1365 pub prefetch_limit_upper: u32,
1366 #[mesh(15)]
1367 pub bridge_control: u16,
1368 }
1369 }
1370
1371 #[derive(Debug, Error)]
1372 enum ConfigSpaceRestoreError {
1373 #[error("found invalid config bits in saved state")]
1374 InvalidConfigBits,
1375 #[error("found unexpected capability {0}")]
1376 InvalidCap(String),
1377 }
1378
1379 impl SaveRestore for ConfigSpaceType0Emulator {
1380 type SavedState = state::SavedState;
1381
1382 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1383 let ConfigSpaceType0EmulatorState { latency_timer } = self.state;
1384
1385 let saved_state = state::SavedState {
1386 command: self.common.command().into_bits(),
1387 base_addresses: *self.common.base_addresses(),
1388 interrupt_line: self.common.interrupt_line(),
1389 latency_timer,
1390 capabilities: self
1391 .common
1392 .capabilities_mut()
1393 .iter_mut()
1394 .map(|cap| {
1395 let id = cap.label().to_owned();
1396 Ok((id, cap.save()?))
1397 })
1398 .collect::<Result<_, _>>()?,
1399 subordinate_bus_number: 0,
1401 secondary_bus_number: 0,
1402 primary_bus_number: 0,
1403 memory_base: 0,
1404 memory_limit: 0,
1405 prefetch_base: 0,
1406 prefetch_limit: 0,
1407 prefetch_base_upper: 0,
1408 prefetch_limit_upper: 0,
1409 bridge_control: 0,
1410 };
1411
1412 Ok(saved_state)
1413 }
1414
1415 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1416 let state::SavedState {
1417 command,
1418 base_addresses,
1419 interrupt_line,
1420 latency_timer,
1421 capabilities,
1422 subordinate_bus_number: _,
1424 secondary_bus_number: _,
1425 primary_bus_number: _,
1426 memory_base: _,
1427 memory_limit: _,
1428 prefetch_base: _,
1429 prefetch_limit: _,
1430 prefetch_base_upper: _,
1431 prefetch_limit_upper: _,
1432 bridge_control: _,
1433 } = state;
1434
1435 self.state = ConfigSpaceType0EmulatorState { latency_timer };
1436
1437 self.common.set_base_addresses(&base_addresses);
1438 self.common.set_interrupt_line(interrupt_line);
1439 self.common
1440 .set_command(cfg_space::Command::from_bits(command));
1441
1442 if command & !SUPPORTED_COMMAND_BITS != 0 {
1443 return Err(RestoreError::InvalidSavedState(
1444 ConfigSpaceRestoreError::InvalidConfigBits.into(),
1445 ));
1446 }
1447
1448 self.common.sync_command_register(self.common.command());
1449
1450 for (id, entry) in capabilities {
1451 tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1452
1453 let mut restored = false;
1456 for cap in self.common.capabilities_mut() {
1457 if cap.label() == id {
1458 cap.restore(entry)?;
1459 restored = true;
1460 break;
1461 }
1462 }
1463
1464 if !restored {
1465 return Err(RestoreError::InvalidSavedState(
1466 ConfigSpaceRestoreError::InvalidCap(id).into(),
1467 ));
1468 }
1469 }
1470
1471 Ok(())
1472 }
1473 }
1474
1475 impl SaveRestore for ConfigSpaceType1Emulator {
1476 type SavedState = state::SavedState;
1477
1478 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1479 let ConfigSpaceType1EmulatorState {
1480 subordinate_bus_number,
1481 secondary_bus_number,
1482 primary_bus_number,
1483 memory_base,
1484 memory_limit,
1485 prefetch_base,
1486 prefetch_limit,
1487 prefetch_base_upper,
1488 prefetch_limit_upper,
1489 bridge_control,
1490 } = self.state;
1491
1492 let type1_base_addresses = self.common.base_addresses();
1494 let mut saved_base_addresses = [0u32; 6];
1495 saved_base_addresses[0] = type1_base_addresses[0];
1496 saved_base_addresses[1] = type1_base_addresses[1];
1497
1498 let saved_state = state::SavedState {
1499 command: self.common.command().into_bits(),
1500 base_addresses: saved_base_addresses,
1501 interrupt_line: self.common.interrupt_line(),
1502 latency_timer: 0, capabilities: self
1504 .common
1505 .capabilities_mut()
1506 .iter_mut()
1507 .map(|cap| {
1508 let id = cap.label().to_owned();
1509 Ok((id, cap.save()?))
1510 })
1511 .collect::<Result<_, _>>()?,
1512 subordinate_bus_number,
1514 secondary_bus_number,
1515 primary_bus_number,
1516 memory_base,
1517 memory_limit,
1518 prefetch_base,
1519 prefetch_limit,
1520 prefetch_base_upper,
1521 prefetch_limit_upper,
1522 bridge_control,
1523 };
1524
1525 Ok(saved_state)
1526 }
1527
1528 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1529 let state::SavedState {
1530 command,
1531 base_addresses,
1532 interrupt_line,
1533 latency_timer: _, capabilities,
1535 subordinate_bus_number,
1536 secondary_bus_number,
1537 primary_bus_number,
1538 memory_base,
1539 memory_limit,
1540 prefetch_base,
1541 prefetch_limit,
1542 prefetch_base_upper,
1543 prefetch_limit_upper,
1544 bridge_control,
1545 } = state;
1546
1547 self.state = ConfigSpaceType1EmulatorState {
1548 subordinate_bus_number,
1549 secondary_bus_number,
1550 primary_bus_number,
1551 memory_base,
1552 memory_limit,
1553 prefetch_base,
1554 prefetch_limit,
1555 prefetch_base_upper,
1556 prefetch_limit_upper,
1557 bridge_control,
1558 };
1559
1560 let mut full_base_addresses = [0u32; 6];
1562 for (i, &addr) in base_addresses.iter().enumerate().take(2) {
1563 full_base_addresses[i] = addr;
1564 }
1565 self.common
1566 .set_base_addresses(&[full_base_addresses[0], full_base_addresses[1]]);
1567 self.common.set_interrupt_line(interrupt_line);
1568 self.common
1569 .set_command(cfg_space::Command::from_bits(command));
1570
1571 if command & !SUPPORTED_COMMAND_BITS != 0 {
1572 return Err(RestoreError::InvalidSavedState(
1573 ConfigSpaceRestoreError::InvalidConfigBits.into(),
1574 ));
1575 }
1576
1577 self.common.sync_command_register(self.common.command());
1578
1579 for (id, entry) in capabilities {
1580 tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1581
1582 let mut restored = false;
1583 for cap in self.common.capabilities_mut() {
1584 if cap.label() == id {
1585 cap.restore(entry)?;
1586 restored = true;
1587 break;
1588 }
1589 }
1590
1591 if !restored {
1592 return Err(RestoreError::InvalidSavedState(
1593 ConfigSpaceRestoreError::InvalidCap(id).into(),
1594 ));
1595 }
1596 }
1597
1598 Ok(())
1599 }
1600 }
1601}
1602
1603#[cfg(test)]
1604mod tests {
1605 use super::*;
1606 use crate::capabilities::pci_express::PciExpressCapability;
1607 use crate::capabilities::read_only::ReadOnlyCapability;
1608 use crate::spec::caps::pci_express::DevicePortType;
1609 use crate::spec::hwid::ClassCode;
1610 use crate::spec::hwid::ProgrammingInterface;
1611 use crate::spec::hwid::Subclass;
1612
1613 fn create_type0_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType0Emulator {
1614 ConfigSpaceType0Emulator::new(
1615 HardwareIds {
1616 vendor_id: 0x1111,
1617 device_id: 0x2222,
1618 revision_id: 1,
1619 prog_if: ProgrammingInterface::NONE,
1620 sub_class: Subclass::NONE,
1621 base_class: ClassCode::UNCLASSIFIED,
1622 type0_sub_vendor_id: 0x3333,
1623 type0_sub_system_id: 0x4444,
1624 },
1625 caps,
1626 DeviceBars::new(),
1627 )
1628 }
1629
1630 fn create_type1_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType1Emulator {
1631 ConfigSpaceType1Emulator::new(
1632 HardwareIds {
1633 vendor_id: 0x1111,
1634 device_id: 0x2222,
1635 revision_id: 1,
1636 prog_if: ProgrammingInterface::NONE,
1637 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1638 base_class: ClassCode::BRIDGE,
1639 type0_sub_vendor_id: 0,
1640 type0_sub_system_id: 0,
1641 },
1642 caps,
1643 )
1644 }
1645
1646 fn read_cfg(emulator: &ConfigSpaceType1Emulator, offset: u16) -> u32 {
1647 let mut val = 0;
1648 emulator.read_u32(offset, &mut val).unwrap();
1649 val
1650 }
1651
1652 #[test]
1653 fn test_type1_probe() {
1654 let emu = create_type1_emulator(vec![]);
1655 assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1656 assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0); let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1659 assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1660 assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0x10_0000); }
1662
1663 #[test]
1664 fn test_type1_bus_number_assignment() {
1665 let mut emu = create_type1_emulator(vec![]);
1666
1667 assert_eq!(read_cfg(&emu, 0x18), 0);
1670 assert_eq!(emu.assigned_bus_range(), 0..=0);
1671
1672 emu.write_u32(0x18, 0x0000_1000).unwrap();
1676 assert_eq!(read_cfg(&emu, 0x18), 0x0000_1000);
1677 assert_eq!(emu.assigned_bus_range(), 0..=0);
1678 emu.write_u32(0x18, 0x0012_1000).unwrap();
1679 assert_eq!(read_cfg(&emu, 0x18), 0x0012_1000);
1680 assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1681
1682 emu.write_u32(0x18, 0x0012_1033).unwrap();
1685 assert_eq!(read_cfg(&emu, 0x18), 0x0012_1033);
1686 assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1687
1688 emu.write_u32(0x18, 0x0047_4411).unwrap();
1690 assert_eq!(read_cfg(&emu, 0x18), 0x0047_4411);
1691 assert_eq!(emu.assigned_bus_range(), 0x44..=0x47);
1692
1693 emu.write_u32(0x18, 0x0088_8800).unwrap();
1695 assert_eq!(emu.assigned_bus_range(), 0x88..=0x88);
1696
1697 emu.write_u32(0x18, 0x0087_8800).unwrap();
1699 assert_eq!(emu.assigned_bus_range(), 0..=0);
1700 }
1701
1702 #[test]
1703 fn test_type1_memory_assignment() {
1704 const MMIO_ENABLED: u32 = 0x0000_0002;
1705 const MMIO_DISABLED: u32 = 0x0000_0000;
1706
1707 let mut emu = create_type1_emulator(vec![]);
1708 assert!(emu.assigned_memory_range().is_none());
1709
1710 emu.write_u32(0x20, 0xDEAD_BEEF).unwrap();
1713 assert!(emu.assigned_memory_range().is_none());
1714
1715 emu.write_u32(0x20, 0xFFF0_FF00).unwrap();
1717 assert!(emu.assigned_memory_range().is_none());
1718 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1720 assert_eq!(emu.assigned_memory_range(), Some(0xFF00_0000..=0xFFFF_FFFF));
1721 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1723 assert!(emu.assigned_memory_range().is_none());
1724
1725 emu.write_u32(0x20, 0xBBB0_BBB0).unwrap();
1727 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1728 assert_eq!(emu.assigned_memory_range(), Some(0xBBB0_0000..=0xBBBF_FFFF));
1729 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1730 assert!(emu.assigned_memory_range().is_none());
1731
1732 emu.write_u32(0x20, 0xAA00_BB00).unwrap();
1735 assert!(emu.assigned_memory_range().is_none());
1736 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1737 assert!(emu.assigned_memory_range().is_none());
1738 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1739 assert!(emu.assigned_memory_range().is_none());
1740 }
1741
1742 #[test]
1743 fn test_type1_prefetch_assignment() {
1744 const MMIO_ENABLED: u32 = 0x0000_0002;
1745 const MMIO_DISABLED: u32 = 0x0000_0000;
1746
1747 let mut emu = create_type1_emulator(vec![]);
1748 assert!(emu.assigned_prefetch_range().is_none());
1749
1750 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());
1755 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1757 assert_eq!(
1758 emu.assigned_prefetch_range(),
1759 Some(0x00AA_BBCC_FF00_0000..=0x00DD_EEFF_FFFF_FFFF)
1760 );
1761 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1763 assert!(emu.assigned_prefetch_range().is_none());
1764
1765 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());
1774 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1775 assert_eq!(
1776 emu.assigned_prefetch_range(),
1777 Some(0x00AA_BBCC_FFF0_0000..=0x00DD_EEFF_FF0F_FFFF)
1778 );
1779 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1780 assert!(emu.assigned_prefetch_range().is_none());
1781
1782 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());
1787 emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1788 assert_eq!(
1789 emu.assigned_prefetch_range(),
1790 Some(0x00AA_BBCC_DD00_0000..=0x00AA_BBCC_DD0F_FFFF)
1791 );
1792 emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1793 assert!(emu.assigned_prefetch_range().is_none());
1794 }
1795
1796 #[test]
1797 fn test_type1_is_pcie_device() {
1798 let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1800 assert!(!emu.is_pcie_device());
1801
1802 let emu = create_type1_emulator(vec![Box::new(PciExpressCapability::new(
1804 DevicePortType::RootPort,
1805 None,
1806 ))]);
1807 assert!(emu.is_pcie_device());
1808
1809 let emu = create_type1_emulator(vec![
1811 Box::new(ReadOnlyCapability::new("foo", 0)),
1812 Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1813 Box::new(ReadOnlyCapability::new("bar", 0)),
1814 ]);
1815 assert!(emu.is_pcie_device());
1816 }
1817
1818 #[test]
1819 fn test_type0_is_pcie_device() {
1820 let emu = ConfigSpaceType0Emulator::new(
1822 HardwareIds {
1823 vendor_id: 0x1111,
1824 device_id: 0x2222,
1825 revision_id: 1,
1826 prog_if: ProgrammingInterface::NONE,
1827 sub_class: Subclass::NONE,
1828 base_class: ClassCode::UNCLASSIFIED,
1829 type0_sub_vendor_id: 0,
1830 type0_sub_system_id: 0,
1831 },
1832 vec![Box::new(ReadOnlyCapability::new("foo", 0))],
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![Box::new(PciExpressCapability::new(
1850 DevicePortType::Endpoint,
1851 None,
1852 ))],
1853 DeviceBars::new(),
1854 );
1855 assert!(emu.is_pcie_device());
1856
1857 let emu = ConfigSpaceType0Emulator::new(
1859 HardwareIds {
1860 vendor_id: 0x1111,
1861 device_id: 0x2222,
1862 revision_id: 1,
1863 prog_if: ProgrammingInterface::NONE,
1864 sub_class: Subclass::NONE,
1865 base_class: ClassCode::UNCLASSIFIED,
1866 type0_sub_vendor_id: 0,
1867 type0_sub_system_id: 0,
1868 },
1869 vec![
1870 Box::new(ReadOnlyCapability::new("foo", 0)),
1871 Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1872 Box::new(ReadOnlyCapability::new("bar", 0)),
1873 ],
1874 DeviceBars::new(),
1875 );
1876 assert!(emu.is_pcie_device());
1877
1878 let emu = ConfigSpaceType0Emulator::new(
1880 HardwareIds {
1881 vendor_id: 0x1111,
1882 device_id: 0x2222,
1883 revision_id: 1,
1884 prog_if: ProgrammingInterface::NONE,
1885 sub_class: Subclass::NONE,
1886 base_class: ClassCode::UNCLASSIFIED,
1887 type0_sub_vendor_id: 0,
1888 type0_sub_system_id: 0,
1889 },
1890 vec![],
1891 DeviceBars::new(),
1892 );
1893 assert!(!emu.is_pcie_device());
1894 }
1895
1896 #[test]
1897 fn test_capability_ids() {
1898 let pcie_cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
1900 assert_eq!(pcie_cap.capability_id(), CapabilityId::PCI_EXPRESS);
1901
1902 let read_only_cap = ReadOnlyCapability::new("test", 0u32);
1903 assert_eq!(read_only_cap.capability_id(), CapabilityId::VENDOR_SPECIFIC);
1904 }
1905
1906 #[test]
1907 fn test_common_header_emulator_type0() {
1908 let hardware_ids = HardwareIds {
1910 vendor_id: 0x1111,
1911 device_id: 0x2222,
1912 revision_id: 1,
1913 prog_if: ProgrammingInterface::NONE,
1914 sub_class: Subclass::NONE,
1915 base_class: ClassCode::UNCLASSIFIED,
1916 type0_sub_vendor_id: 0,
1917 type0_sub_system_id: 0,
1918 };
1919
1920 let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1921
1922 let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1923 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1924
1925 assert_eq!(common_emu.hardware_ids().vendor_id, 0x1111);
1926 assert_eq!(common_emu.hardware_ids().device_id, 0x2222);
1927 assert!(!common_emu.multi_function_bit());
1928 assert!(!common_emu.is_pcie_device());
1929 assert_ne!(common_emu.bar_masks()[0], 0); }
1931
1932 #[test]
1933 fn test_common_header_emulator_type1() {
1934 let hardware_ids = HardwareIds {
1936 vendor_id: 0x3333,
1937 device_id: 0x4444,
1938 revision_id: 1,
1939 prog_if: ProgrammingInterface::NONE,
1940 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1941 base_class: ClassCode::BRIDGE,
1942 type0_sub_vendor_id: 0,
1943 type0_sub_system_id: 0,
1944 };
1945
1946 let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1947
1948 let mut common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
1949 ConfigSpaceCommonHeaderEmulator::new(
1950 hardware_ids,
1951 vec![Box::new(PciExpressCapability::new(
1952 DevicePortType::RootPort,
1953 None,
1954 ))],
1955 bars,
1956 )
1957 .with_multi_function_bit(true);
1958
1959 assert_eq!(common_emu.hardware_ids().vendor_id, 0x3333);
1960 assert_eq!(common_emu.hardware_ids().device_id, 0x4444);
1961 assert!(common_emu.multi_function_bit());
1962 assert!(common_emu.is_pcie_device());
1963 assert_ne!(common_emu.bar_masks()[0], 0); assert_eq!(common_emu.bar_masks().len(), 2);
1965
1966 common_emu.reset();
1968 assert_eq!(common_emu.capabilities().len(), 1); }
1970
1971 #[test]
1972 fn test_common_header_emulator_no_bars() {
1973 let hardware_ids = HardwareIds {
1975 vendor_id: 0x5555,
1976 device_id: 0x6666,
1977 revision_id: 1,
1978 prog_if: ProgrammingInterface::NONE,
1979 sub_class: Subclass::NONE,
1980 base_class: ClassCode::UNCLASSIFIED,
1981 type0_sub_vendor_id: 0,
1982 type0_sub_system_id: 0,
1983 };
1984
1985 let bars = DeviceBars::new();
1987
1988 let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1989 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1990
1991 assert_eq!(common_emu.hardware_ids().vendor_id, 0x5555);
1992 assert_eq!(common_emu.hardware_ids().device_id, 0x6666);
1993
1994 for &mask in common_emu.bar_masks() {
1996 assert_eq!(mask, 0);
1997 }
1998 }
1999
2000 #[test]
2001 fn test_common_header_emulator_type1_ignores_extra_bars() {
2002 let hardware_ids = HardwareIds {
2004 vendor_id: 0x7777,
2005 device_id: 0x8888,
2006 revision_id: 1,
2007 prog_if: ProgrammingInterface::NONE,
2008 sub_class: Subclass::BRIDGE_PCI_TO_PCI,
2009 base_class: ClassCode::BRIDGE,
2010 type0_sub_vendor_id: 0,
2011 type0_sub_system_id: 0,
2012 };
2013
2014 let bars = DeviceBars::new()
2016 .bar0(4096, BarMemoryKind::Dummy)
2017 .bar2(8192, BarMemoryKind::Dummy)
2018 .bar4(16384, BarMemoryKind::Dummy);
2019
2020 let common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
2021 ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
2022
2023 assert_eq!(common_emu.hardware_ids().vendor_id, 0x7777);
2024 assert_eq!(common_emu.hardware_ids().device_id, 0x8888);
2025
2026 assert_ne!(common_emu.bar_masks()[0], 0); assert_ne!(common_emu.bar_masks()[1], 0); assert_eq!(common_emu.bar_masks().len(), 2); }
2034
2035 #[test]
2036 fn test_common_header_extended_capabilities() {
2037 let mut common_emu_no_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2039 HardwareIds {
2040 vendor_id: 0x1111,
2041 device_id: 0x2222,
2042 revision_id: 1,
2043 prog_if: ProgrammingInterface::NONE,
2044 sub_class: Subclass::NONE,
2045 base_class: ClassCode::UNCLASSIFIED,
2046 type0_sub_vendor_id: 0,
2047 type0_sub_system_id: 0,
2048 },
2049 vec![Box::new(ReadOnlyCapability::new("foo", 0))],
2050 DeviceBars::new(),
2051 );
2052 assert!(!common_emu_no_pcie.is_pcie_device());
2053
2054 let mut common_emu_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2055 HardwareIds {
2056 vendor_id: 0x1111,
2057 device_id: 0x2222,
2058 revision_id: 1,
2059 prog_if: ProgrammingInterface::NONE,
2060 sub_class: Subclass::NONE,
2061 base_class: ClassCode::UNCLASSIFIED,
2062 type0_sub_vendor_id: 0,
2063 type0_sub_system_id: 0,
2064 },
2065 vec![Box::new(PciExpressCapability::new(
2066 DevicePortType::Endpoint,
2067 None,
2068 ))],
2069 DeviceBars::new(),
2070 );
2071 assert!(common_emu_pcie.is_pcie_device());
2072
2073 let mut value = 0;
2075 assert!(matches!(
2076 common_emu_no_pcie.read_extended_capabilities(0x100, &mut value),
2077 CommonHeaderResult::Failed(IoError::InvalidRegister)
2078 ));
2079
2080 let mut value = 0;
2082 assert!(matches!(
2083 common_emu_pcie.read_extended_capabilities(0x100, &mut value),
2084 CommonHeaderResult::Handled
2085 ));
2086 assert_eq!(value, 0xffffffff);
2087
2088 assert!(matches!(
2090 common_emu_no_pcie.write_extended_capabilities(0x100, 0x1234),
2091 CommonHeaderResult::Failed(IoError::InvalidRegister)
2092 ));
2093
2094 assert!(matches!(
2096 common_emu_pcie.write_extended_capabilities(0x100, 0x1234),
2097 CommonHeaderResult::Handled
2098 ));
2099
2100 let mut value = 0;
2102 assert!(matches!(
2103 common_emu_pcie.read_extended_capabilities(0x99, &mut value),
2104 CommonHeaderResult::Failed(IoError::InvalidRegister)
2105 ));
2106 assert!(matches!(
2107 common_emu_pcie.read_extended_capabilities(0x1000, &mut value),
2108 CommonHeaderResult::Failed(IoError::InvalidRegister)
2109 ));
2110 }
2111
2112 #[test]
2113 fn test_type0_emulator_save_restore() {
2114 use vmcore::save_restore::SaveRestore;
2115
2116 let mut emu = create_type0_emulator(vec![]);
2118
2119 emu.write_u32(0x04, 0x0007).unwrap(); let mut test_val = 0u32;
2124 emu.read_u32(0x04, &mut test_val).unwrap();
2125 assert_eq!(test_val & 0x0007, 0x0007);
2126
2127 emu.write_u32(0x3C, 0x0040_0000).unwrap(); let saved_state = emu.save().expect("save should succeed");
2132
2133 emu.reset();
2135
2136 emu.read_u32(0x04, &mut test_val).unwrap();
2138 assert_eq!(test_val & 0x0007, 0x0000); emu.restore(saved_state).expect("restore should succeed");
2142
2143 emu.read_u32(0x04, &mut test_val).unwrap();
2145 assert_eq!(test_val & 0x0007, 0x0007); }
2147
2148 #[test]
2149 fn test_type1_emulator_save_restore() {
2150 use vmcore::save_restore::SaveRestore;
2151
2152 let mut emu = create_type1_emulator(vec![]);
2154
2155 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;
2166 emu.read_u32(0x04, &mut test_val).unwrap();
2167 assert_eq!(test_val & 0x0003, 0x0003);
2168 emu.read_u32(0x18, &mut test_val).unwrap();
2169 assert_eq!(test_val, 0x0012_1000);
2170 emu.read_u32(0x20, &mut test_val).unwrap();
2171 assert_eq!(test_val, 0xFFF0_FF00);
2172 emu.read_u32(0x28, &mut test_val).unwrap();
2173 assert_eq!(test_val, 0x00AA_BBCC);
2174 emu.read_u32(0x2C, &mut test_val).unwrap();
2175 assert_eq!(test_val, 0x00DD_EEFF);
2176 emu.read_u32(0x3C, &mut test_val).unwrap();
2177 assert_eq!(test_val >> 16, 0x0001); let saved_state = emu.save().expect("save should succeed");
2181
2182 emu.reset();
2184
2185 emu.read_u32(0x04, &mut test_val).unwrap();
2187 assert_eq!(test_val & 0x0003, 0x0000);
2188 emu.read_u32(0x18, &mut test_val).unwrap();
2189 assert_eq!(test_val, 0x0000_0000);
2190
2191 emu.restore(saved_state).expect("restore should succeed");
2193
2194 emu.read_u32(0x04, &mut test_val).unwrap();
2196 assert_eq!(test_val & 0x0003, 0x0003);
2197 emu.read_u32(0x18, &mut test_val).unwrap();
2198 assert_eq!(test_val, 0x0012_1000);
2199 emu.read_u32(0x20, &mut test_val).unwrap();
2200 assert_eq!(test_val, 0xFFF0_FF00);
2201 emu.read_u32(0x28, &mut test_val).unwrap();
2202 assert_eq!(test_val, 0x00AA_BBCC);
2203 emu.read_u32(0x2C, &mut test_val).unwrap();
2204 assert_eq!(test_val, 0x00DD_EEFF);
2205 emu.read_u32(0x3C, &mut test_val).unwrap();
2206 assert_eq!(test_val >> 16, 0x0001); }
2208
2209 #[test]
2210 fn test_config_space_type1_set_presence_detect_state() {
2211 let pcie_cap =
2216 PciExpressCapability::new(DevicePortType::RootPort, None).with_hotplug_support(1);
2217
2218 let mut emulator = create_type1_emulator(vec![Box::new(pcie_cap)]);
2219
2220 let mut slot_status_val = 0u32;
2222 let result = emulator.read_u32(0x58, &mut slot_status_val); assert!(matches!(result, IoResult::Ok));
2224 let initial_presence_detect = (slot_status_val >> 22) & 0x1; assert_eq!(
2226 initial_presence_detect, 0,
2227 "Initial presence detect state should be 0"
2228 );
2229
2230 emulator.set_presence_detect_state(true);
2232 let result = emulator.read_u32(0x58, &mut slot_status_val);
2233 assert!(matches!(result, IoResult::Ok));
2234 let present_presence_detect = (slot_status_val >> 22) & 0x1;
2235 assert_eq!(
2236 present_presence_detect, 1,
2237 "Presence detect state should be 1 when device is present"
2238 );
2239
2240 emulator.set_presence_detect_state(false);
2242 let result = emulator.read_u32(0x58, &mut slot_status_val);
2243 assert!(matches!(result, IoResult::Ok));
2244 let absent_presence_detect = (slot_status_val >> 22) & 0x1;
2245 assert_eq!(
2246 absent_presence_detect, 0,
2247 "Presence detect state should be 0 when device is not present"
2248 );
2249 }
2250
2251 #[test]
2252 fn test_config_space_type1_set_presence_detect_state_without_pcie() {
2253 let mut emulator = create_type1_emulator(vec![]); emulator.set_presence_detect_state(true);
2260 emulator.set_presence_detect_state(false);
2261 }
2262
2263 #[test]
2264 fn test_interrupt_pin_register() {
2265 use vmcore::line_interrupt::LineInterrupt;
2266
2267 let mut emu = ConfigSpaceType0Emulator::new(
2269 HardwareIds {
2270 vendor_id: 0x1111,
2271 device_id: 0x2222,
2272 revision_id: 1,
2273 prog_if: ProgrammingInterface::NONE,
2274 sub_class: Subclass::NONE,
2275 base_class: ClassCode::UNCLASSIFIED,
2276 type0_sub_vendor_id: 0,
2277 type0_sub_system_id: 0,
2278 },
2279 vec![],
2280 DeviceBars::new(),
2281 );
2282
2283 let mut val = 0u32;
2285 emu.read_u32(0x3C, &mut val).unwrap(); assert_eq!(val & 0xFF00, 0); let line_interrupt = LineInterrupt::detached();
2290 emu.set_interrupt_pin(PciInterruptPin::IntA, line_interrupt);
2291
2292 emu.read_u32(0x3C, &mut val).unwrap();
2294 assert_eq!((val >> 8) & 0xFF, 1); emu.write_u32(0x3C, 0x00110042).unwrap(); emu.read_u32(0x3C, &mut val).unwrap();
2299 assert_eq!(val & 0xFF, 0x42); assert_eq!((val >> 8) & 0xFF, 1); assert_eq!((val >> 16) & 0xFF, 0x11); let mut emu_d = ConfigSpaceType0Emulator::new(
2305 HardwareIds {
2306 vendor_id: 0x1111,
2307 device_id: 0x2222,
2308 revision_id: 1,
2309 prog_if: ProgrammingInterface::NONE,
2310 sub_class: Subclass::NONE,
2311 base_class: ClassCode::UNCLASSIFIED,
2312 type0_sub_vendor_id: 0,
2313 type0_sub_system_id: 0,
2314 },
2315 vec![],
2316 DeviceBars::new(),
2317 );
2318
2319 let line_interrupt_d = LineInterrupt::detached();
2320 emu_d.set_interrupt_pin(PciInterruptPin::IntD, line_interrupt_d);
2321
2322 emu_d.read_u32(0x3C, &mut val).unwrap();
2323 assert_eq!((val >> 8) & 0xFF, 4); }
2325
2326 #[test]
2327 fn test_header_type_functionality() {
2328 assert_eq!(HeaderType::Type0.bar_count(), 6);
2330 assert_eq!(HeaderType::Type1.bar_count(), 2);
2331 assert_eq!(usize::from(HeaderType::Type0), 6);
2332 assert_eq!(usize::from(HeaderType::Type1), 2);
2333
2334 assert_eq!(header_type_consts::TYPE0_BAR_COUNT, 6);
2336 assert_eq!(header_type_consts::TYPE1_BAR_COUNT, 2);
2337
2338 let emu_type0 = create_type0_emulator(vec![]);
2340 assert_eq!(emu_type0.common.bar_count(), 6);
2341 assert_eq!(emu_type0.common.header_type(), HeaderType::Type0);
2342 assert!(emu_type0.common.validate_header_type(HeaderType::Type0));
2343 assert!(!emu_type0.common.validate_header_type(HeaderType::Type1));
2344
2345 let emu_type1 = create_type1_emulator(vec![]);
2347 assert_eq!(emu_type1.common.bar_count(), 2);
2348 assert_eq!(emu_type1.common.header_type(), HeaderType::Type1);
2349 assert!(emu_type1.common.validate_header_type(HeaderType::Type1));
2350 assert!(!emu_type1.common.validate_header_type(HeaderType::Type0));
2351 }
2352
2353 #[test]
2356 fn find_bar_returns_full_u64_offset_for_large_bar() {
2357 use crate::bar_mapping::BarMappings;
2358
2359 let bar_base: u64 = 0x1_0000_0000;
2364 let bar_size: u64 = 0x2_0000; let mask64 = !(bar_size - 1); let mut base_addresses = [0u32; 6];
2368 let mut bar_masks = [0u32; 6];
2369
2370 bar_masks[0] = cfg_space::BarEncodingBits::from_bits(mask64 as u32)
2372 .with_type_64_bit(true)
2373 .into_bits();
2374 bar_masks[1] = (mask64 >> 32) as u32;
2375 base_addresses[0] = bar_base as u32;
2376 base_addresses[1] = (bar_base >> 32) as u32;
2377
2378 let bar_mappings = BarMappings::parse(&base_addresses, &bar_masks);
2379
2380 let expected_offset: u64 = 0x1_2345;
2382 let address: u64 = bar_base + expected_offset;
2383
2384 let (found_bar, offset) = bar_mappings
2385 .find(address)
2386 .expect("address should resolve to BAR 0");
2387 assert_eq!(found_bar, 0);
2388 assert_eq!(offset, expected_offset);
2389 }
2390}