Skip to main content

pci_core/
cfg_space_emu.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Helpers that implement standardized PCI configuration space functionality.
5//!
6//! To be clear: PCI devices are not required to use these helpers, and may
7//! choose to implement configuration space accesses manually.
8
9use crate::PciInterruptPin;
10use crate::bar_mapping::BarMappings;
11use crate::capabilities::PciCapability;
12use crate::capabilities::extended::PciExtendedCapability;
13use crate::spec::caps::{COMMON_HEADER_END, CapabilityId, EXT_CAP_END, EXT_CAP_START};
14use crate::spec::cfg_space;
15use crate::spec::hwid::HardwareIds;
16use chipset_device::io::IoError;
17use chipset_device::io::IoResult;
18use chipset_device::mmio::ControlMmioIntercept;
19use chipset_device::pci::ByteEnabledDwordRead;
20use chipset_device::pci::ByteEnabledDwordWrite;
21use chipset_device::pci::PciConfigAddress;
22use chipset_device::pci::PciConfigByteEnable;
23use guestmem::MappableGuestMemory;
24use inspect::Inspect;
25use std::ops::RangeInclusive;
26use std::sync::Arc;
27use std::sync::atomic::AtomicBool;
28use std::sync::atomic::Ordering;
29use vmcore::line_interrupt::LineInterrupt;
30
31/// PCI configuration space header type with corresponding BAR count
32///
33/// This enum provides a type-safe way to work with PCI configuration space header types
34/// and their corresponding BAR counts. It improves readability over raw constants.
35///
36/// # Examples
37///
38/// ```rust
39/// # use pci_core::cfg_space_emu::HeaderType;
40/// // Get BAR count for different header types
41/// assert_eq!(HeaderType::Type0.bar_count(), 6);
42/// assert_eq!(HeaderType::Type1.bar_count(), 2);
43///
44/// // Convert to usize for use in generic contexts
45/// let bar_count: usize = HeaderType::Type0.into();
46/// assert_eq!(bar_count, 6);
47/// ```
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum HeaderType {
50    /// Type 0 header with 6 BARs (endpoint devices)
51    Type0,
52    /// Type 1 header with 2 BARs (bridge devices)
53    Type1,
54}
55
56impl HeaderType {
57    /// Get the number of BARs for this header type
58    pub const fn bar_count(self) -> usize {
59        match self {
60            HeaderType::Type0 => 6,
61            HeaderType::Type1 => 2,
62        }
63    }
64}
65
66impl From<HeaderType> for usize {
67    fn from(header_type: HeaderType) -> usize {
68        header_type.bar_count()
69    }
70}
71
72/// Constants for header type BAR counts
73pub mod header_type_consts {
74    use super::HeaderType;
75
76    /// Number of BARs for Type 0 headers
77    pub const TYPE0_BAR_COUNT: usize = HeaderType::Type0.bar_count();
78
79    /// Number of BARs for Type 1 headers
80    pub const TYPE1_BAR_COUNT: usize = HeaderType::Type1.bar_count();
81}
82
83/// Result type for common header emulator operations
84#[derive(Debug)]
85pub enum CommonHeaderResult {
86    /// The access was handled by the common header emulator
87    Handled,
88    /// The access is not handled by common header, caller should handle it
89    Unhandled,
90    /// The access failed with an error
91    Failed(IoError),
92}
93
94impl PartialEq for CommonHeaderResult {
95    fn eq(&self, other: &Self) -> bool {
96        match (self, other) {
97            (Self::Handled, Self::Handled) => true,
98            (Self::Unhandled, Self::Unhandled) => true,
99            (Self::Failed(_), Self::Failed(_)) => true, // Consider all failures equal for testing
100            _ => false,
101        }
102    }
103}
104
105const SUPPORTED_COMMAND_BITS: u16 = cfg_space::Command::new()
106    .with_pio_enabled(true)
107    .with_mmio_enabled(true)
108    .with_bus_master(true)
109    .with_special_cycles(true)
110    .with_enable_memory_write_invalidate(true)
111    .with_vga_palette_snoop(true)
112    .with_parity_error_response(true)
113    .with_enable_serr(true)
114    .with_enable_fast_b2b(true)
115    .with_intx_disable(true)
116    .into_bits();
117
118/// A wrapper around a [`LineInterrupt`] that considers PCI configuration space
119/// interrupt control bits.
120#[derive(Debug, Inspect)]
121pub struct IntxInterrupt {
122    pin: PciInterruptPin,
123    line: LineInterrupt,
124    interrupt_disabled: AtomicBool,
125    interrupt_status: AtomicBool,
126}
127
128impl IntxInterrupt {
129    /// Sets the line level high or low.
130    ///
131    /// NOTE: whether or not this will actually trigger an interrupt will depend
132    /// the status of the Interrupt Disabled bit in the PCI configuration space.
133    pub fn set_level(&self, high: bool) {
134        tracing::debug!(
135            disabled = ?self.interrupt_disabled,
136            status = ?self.interrupt_status,
137            ?high,
138            %self.line,
139            "set_level"
140        );
141
142        // the actual config space bit is set unconditionally
143        self.interrupt_status.store(high, Ordering::SeqCst);
144
145        // ...but whether it also fires an interrupt is a different story
146        if self.interrupt_disabled.load(Ordering::SeqCst) {
147            self.line.set_level(false);
148        } else {
149            self.line.set_level(high);
150        }
151    }
152
153    fn set_disabled(&self, disabled: bool) {
154        tracing::debug!(
155            disabled = ?self.interrupt_disabled,
156            status = ?self.interrupt_status,
157            ?disabled,
158            %self.line,
159            "set_disabled"
160        );
161
162        self.interrupt_disabled.store(disabled, Ordering::SeqCst);
163        if disabled {
164            self.line.set_level(false)
165        } else {
166            if self.interrupt_status.load(Ordering::SeqCst) {
167                self.line.set_level(true)
168            }
169        }
170    }
171}
172
173#[derive(Debug, Inspect)]
174struct ConfigSpaceCommonHeaderEmulatorState<const N: usize> {
175    /// The command register
176    command: cfg_space::Command,
177    /// OS-configured BARs
178    #[inspect(with = "inspect_helpers::bars_generic")]
179    base_addresses: [u32; N],
180    /// The PCI device doesn't actually care about what value is stored here -
181    /// this register is just a bit of standardized "scratch space", ostensibly
182    /// for firmware to communicate IRQ assignments to the OS, but it can really
183    /// be used for just about anything.
184    interrupt_line: u8,
185    /// The bus number captured by this emulator.
186    captured_bus_number: u8,
187    /// The combined devfn (device << 3 | function) captured by this emulator.
188    captured_devfn: u8,
189}
190
191impl<const N: usize> ConfigSpaceCommonHeaderEmulatorState<N> {
192    fn new() -> Self {
193        Self {
194            command: cfg_space::Command::new(),
195            base_addresses: {
196                const ZERO: u32 = 0;
197                [ZERO; N]
198            },
199            interrupt_line: 0,
200            captured_bus_number: 0,
201            captured_devfn: 0,
202        }
203    }
204}
205
206/// Common emulator for shared PCI configuration space functionality.
207/// Generic over the number of BARs (6 for Type 0, 2 for Type 1).
208#[derive(Inspect)]
209pub struct ConfigSpaceCommonHeaderEmulator<const N: usize> {
210    // Fixed configuration
211    #[inspect(with = "inspect_helpers::bars_generic")]
212    bar_masks: [u32; N],
213    hardware_ids: HardwareIds,
214    multi_function_bit: bool,
215
216    // Runtime glue
217    #[inspect(with = r#"|x| inspect::iter_by_index(x).prefix("bar")"#)]
218    mapped_memory: [Option<BarMemoryKind>; N],
219    #[inspect(with = "|x| inspect::iter_by_key(x.iter().map(|cap| (cap.label(), cap)))")]
220    capabilities: Vec<Box<dyn PciCapability>>,
221    #[inspect(with = "|x| inspect::iter_by_key(x.iter().map(|cap| (cap.label(), cap)))")]
222    extended_capabilities: Vec<Box<dyn PciExtendedCapability>>,
223    intx_interrupt: Option<Arc<IntxInterrupt>>,
224
225    // Runtime book-keeping
226    active_bars: BarMappings,
227
228    // Volatile state
229    state: ConfigSpaceCommonHeaderEmulatorState<N>,
230}
231
232impl<const N: usize> Drop for ConfigSpaceCommonHeaderEmulator<N> {
233    fn drop(&mut self) {
234        // Release any live BAR intercept registrations when the device's
235        // config space is torn down (e.g. a PCIe hot-remove). The BAR intercept
236        // controls are owned here in `mapped_memory`; without this, a removed
237        // device's BAR ranges stay registered in the chipset's shared range
238        // map, and a subsequent device that reuses the same GPA (a hot-add on
239        // the same port) fails to install its intercept with an
240        // IoRangeConflict, leaving its BAR undispatched (guest reads all-1s).
241        for mapping in self.mapped_memory.iter_mut().flatten() {
242            mapping.unmap_from_guest();
243        }
244    }
245}
246
247/// Type alias for Type 0 common header emulator (6 BARs)
248pub type ConfigSpaceCommonHeaderEmulatorType0 =
249    ConfigSpaceCommonHeaderEmulator<{ header_type_consts::TYPE0_BAR_COUNT }>;
250
251/// Type alias for Type 1 common header emulator (2 BARs)
252pub type ConfigSpaceCommonHeaderEmulatorType1 =
253    ConfigSpaceCommonHeaderEmulator<{ header_type_consts::TYPE1_BAR_COUNT }>;
254
255impl<const N: usize> ConfigSpaceCommonHeaderEmulator<N> {
256    fn validated_extended_cap_len_bytes(cap: &dyn PciExtendedCapability) -> usize {
257        let len = cap.len();
258        assert!(
259            len != 0,
260            "extended capability '{}' len() must be non-zero",
261            cap.label()
262        );
263        assert!(
264            len.is_multiple_of(4),
265            "extended capability '{}' len() must be 4-byte aligned, got {}",
266            cap.label(),
267            len
268        );
269        len
270    }
271
272    /// Create a new common header emulator
273    pub fn new(
274        hardware_ids: HardwareIds,
275        capabilities: Vec<Box<dyn PciCapability>>,
276        extended_capabilities: Vec<Box<dyn PciExtendedCapability>>,
277        bars: DeviceBars,
278    ) -> Self {
279        let mut bar_masks = {
280            const ZERO: u32 = 0;
281            [ZERO; N]
282        };
283        let mut mapped_memory = {
284            const NONE: Option<BarMemoryKind> = None;
285            [NONE; N]
286        };
287
288        // Only process BARs that fit within our supported range (N)
289        for (bar_index, bar) in bars.bars.into_iter().enumerate().take(N) {
290            let (len, mapped) = match bar {
291                Some(bar) => bar,
292                None => continue,
293            };
294            // use 64-bit aware BARs
295            assert!(bar_index < N.saturating_sub(1));
296            // Round up regions to a power of 2, as required by PCI (and
297            // inherently required by the BAR representation). Round up to at
298            // least one page to avoid various problems in guest OSes.
299            const MIN_BAR_SIZE: u64 = 4096;
300            let len = std::cmp::max(len.next_power_of_two(), MIN_BAR_SIZE);
301            let mask64 = !(len - 1);
302            bar_masks[bar_index] = cfg_space::BarEncodingBits::from_bits(mask64 as u32)
303                .with_type_64_bit(true)
304                .with_prefetchable(true)
305                .into_bits();
306            if bar_index + 1 < N {
307                bar_masks[bar_index + 1] = (mask64 >> 32) as u32;
308            }
309            mapped_memory[bar_index] = Some(mapped);
310        }
311
312        // Validate extended capability packing invariants so next-pointer
313        // traversal remains correct.
314        let mut cap_base = usize::from(EXT_CAP_START);
315        for cap in &extended_capabilities {
316            let len = Self::validated_extended_cap_len_bytes(cap.as_ref());
317
318            cap_base = cap_base
319                .checked_add(len)
320                .expect("extended capability size overflow");
321            assert!(
322                cap_base <= usize::from(EXT_CAP_END),
323                "extended capabilities exceed config space window {:#x}..{:#x} (exclusive end), cap_base={:#x}",
324                EXT_CAP_START,
325                EXT_CAP_END,
326                cap_base
327            );
328        }
329
330        Self {
331            hardware_ids,
332            extended_capabilities,
333            capabilities,
334            bar_masks,
335            mapped_memory,
336            multi_function_bit: false,
337            intx_interrupt: None,
338            active_bars: Default::default(),
339            state: ConfigSpaceCommonHeaderEmulatorState::new(),
340        }
341    }
342
343    /// Get the number of BARs supported by this emulator
344    pub const fn bar_count(&self) -> usize {
345        N
346    }
347
348    /// Validate that this emulator has the correct number of BARs for the given header type
349    pub fn validate_header_type(&self, expected: HeaderType) -> bool {
350        N == expected.bar_count()
351    }
352
353    /// If the device is multi-function, enable bit 7 in the Header register.
354    pub fn with_multi_function_bit(mut self, bit: bool) -> Self {
355        self.multi_function_bit = bit;
356        self
357    }
358
359    /// If using legacy INT#x interrupts: wire a LineInterrupt to one of the 4
360    /// INT#x pins, returning an object that manages configuration space bits
361    /// when the device sets the interrupt level.
362    pub fn set_interrupt_pin(
363        &mut self,
364        pin: PciInterruptPin,
365        line: LineInterrupt,
366    ) -> Arc<IntxInterrupt> {
367        let intx_interrupt = Arc::new(IntxInterrupt {
368            pin,
369            line,
370            interrupt_disabled: AtomicBool::new(false),
371            interrupt_status: AtomicBool::new(false),
372        });
373        self.intx_interrupt = Some(intx_interrupt.clone());
374        intx_interrupt
375    }
376
377    /// Reset the common header state
378    pub fn reset(&mut self) {
379        tracing::debug!("ConfigSpaceCommonHeaderEmulator: resetting state");
380        self.state = ConfigSpaceCommonHeaderEmulatorState::new();
381
382        tracing::debug!("ConfigSpaceCommonHeaderEmulator: syncing command register after reset");
383        self.sync_command_register(self.state.command);
384
385        tracing::debug!(
386            "ConfigSpaceCommonHeaderEmulator: resetting {} capabilities",
387            self.capabilities.len()
388        );
389        for cap in &mut self.capabilities {
390            cap.reset();
391        }
392
393        tracing::debug!(
394            "ConfigSpaceCommonHeaderEmulator: resetting {} extended capabilities",
395            self.extended_capabilities.len()
396        );
397        for cap in &mut self.extended_capabilities {
398            cap.reset();
399        }
400
401        if let Some(intx) = &mut self.intx_interrupt {
402            tracing::debug!("ConfigSpaceCommonHeaderEmulator: resetting interrupt level");
403            intx.set_level(false);
404        }
405        tracing::debug!("ConfigSpaceCommonHeaderEmulator: reset completed");
406    }
407
408    /// Get hardware IDs
409    pub fn hardware_ids(&self) -> &HardwareIds {
410        &self.hardware_ids
411    }
412
413    /// Get capabilities
414    pub fn capabilities(&self) -> &[Box<dyn PciCapability>] {
415        &self.capabilities
416    }
417
418    /// Get capabilities mutably
419    pub fn capabilities_mut(&mut self) -> &mut [Box<dyn PciCapability>] {
420        &mut self.capabilities
421    }
422
423    /// Get multi-function bit
424    pub fn multi_function_bit(&self) -> bool {
425        self.multi_function_bit
426    }
427
428    /// Get the header type for this emulator
429    pub const fn header_type(&self) -> HeaderType {
430        match N {
431            header_type_consts::TYPE0_BAR_COUNT => HeaderType::Type0,
432            header_type_consts::TYPE1_BAR_COUNT => HeaderType::Type1,
433            _ => panic!("Unsupported BAR count - must be 6 (Type0) or 2 (Type1)"),
434        }
435    }
436
437    /// Get current command register state
438    pub fn command(&self) -> cfg_space::Command {
439        self.state.command
440    }
441
442    /// Get current base addresses
443    pub fn base_addresses(&self) -> &[u32; N] {
444        &self.state.base_addresses
445    }
446
447    /// Get current interrupt line
448    pub fn interrupt_line(&self) -> u8 {
449        self.state.interrupt_line
450    }
451
452    /// Get current interrupt pin (returns the pin number + 1, or 0 if no pin configured)
453    pub fn interrupt_pin(&self) -> u8 {
454        if let Some(intx) = &self.intx_interrupt {
455            (intx.pin as u8) + 1 // PCI spec: 1=INTA, 2=INTB, 3=INTC, 4=INTD, 0=no interrupt
456        } else {
457            0 // No interrupt pin configured
458        }
459    }
460
461    /// Set interrupt line (for save/restore)
462    pub fn set_interrupt_line(&mut self, interrupt_line: u8) {
463        self.state.interrupt_line = interrupt_line;
464    }
465
466    /// Set base addresses (for save/restore)
467    pub fn set_base_addresses(&mut self, base_addresses: &[u32; N]) {
468        self.state.base_addresses = *base_addresses;
469    }
470
471    /// Set command register (for save/restore)
472    pub fn set_command(&mut self, command: cfg_space::Command) {
473        self.state.command = command;
474    }
475
476    /// Sync command register changes by updating both interrupt and MMIO state
477    pub fn sync_command_register(&mut self, command: cfg_space::Command) {
478        tracing::debug!(
479            "ConfigSpaceCommonHeaderEmulator: syncing command register - intx_disable={}, mmio_enabled={}",
480            command.intx_disable(),
481            command.mmio_enabled()
482        );
483        self.update_intx_disable(command.intx_disable());
484        self.update_mmio_enabled(command.mmio_enabled());
485    }
486
487    /// Update interrupt disable setting
488    pub fn update_intx_disable(&mut self, disabled: bool) {
489        tracing::debug!(
490            "ConfigSpaceCommonHeaderEmulator: updating intx_disable={}",
491            disabled
492        );
493        if let Some(intx_interrupt) = &self.intx_interrupt {
494            intx_interrupt.set_disabled(disabled)
495        }
496    }
497
498    /// Update MMIO enabled setting and handle BAR mapping
499    pub fn update_mmio_enabled(&mut self, enabled: bool) {
500        tracing::debug!(
501            "ConfigSpaceCommonHeaderEmulator: updating mmio_enabled={}",
502            enabled
503        );
504        if enabled {
505            // Note that BarMappings expects 6 BARs. Pad with 0 for Type 1 (N=2)
506            // and use directly for Type 0 (N=6).
507            let mut full_base_addresses = [0u32; 6];
508            let mut full_bar_masks = [0u32; 6];
509
510            // Copy our data into the first N positions
511            full_base_addresses[..N].copy_from_slice(&self.state.base_addresses[..N]);
512            full_bar_masks[..N].copy_from_slice(&self.bar_masks[..N]);
513
514            self.active_bars = BarMappings::parse(&full_base_addresses, &full_bar_masks);
515            for (bar, mapping) in self.mapped_memory.iter_mut().enumerate() {
516                if let Some(mapping) = mapping {
517                    let base = self.active_bars.get(bar as u8).expect("bar exists");
518                    match mapping.map_to_guest(base) {
519                        Ok(_) => {}
520                        Err(err) => {
521                            tracelimit::error_ratelimited!(
522                                error = &err as &dyn std::error::Error,
523                                bar,
524                                base,
525                                "failed to map bar",
526                            )
527                        }
528                    }
529                }
530            }
531        } else {
532            self.active_bars = Default::default();
533            for mapping in self.mapped_memory.iter_mut().flatten() {
534                mapping.unmap_from_guest();
535            }
536        }
537    }
538
539    /// Returns the currently captured bus number.
540    pub fn captured_bus_number(&self) -> u8 {
541        self.state.captured_bus_number
542    }
543
544    /// Returns the currently captured devfn (device << 3 | function) number.
545    pub fn captured_devfn(&self) -> u8 {
546        self.state.captured_devfn
547    }
548
549    /// Overwrites the captured bus number.
550    pub fn set_captured_bus_number(&mut self, bus_number: u8) {
551        self.state.captured_bus_number = bus_number;
552    }
553
554    /// Overwrites the captured devfn (device << 3 | fn) number.
555    pub fn set_captured_devfn(&mut self, devfn: u8) {
556        self.state.captured_devfn = devfn;
557    }
558
559    // ===== Configuration Space Read/Write Functions =====
560
561    /// Read from the config space.
562    /// Returns CommonHeaderResult indicating if handled, unhandled, or failed.
563    pub fn read(
564        &self,
565        address: PciConfigAddress,
566        mut value: ByteEnabledDwordRead<'_>,
567    ) -> CommonHeaderResult {
568        use cfg_space::CommonHeader;
569        let offset = address.byte_offset();
570
571        tracing::trace!("ConfigSpaceCommonHeaderEmulator: read offset={:#x}", offset);
572
573        match CommonHeader(offset) {
574            CommonHeader::DEVICE_VENDOR => {
575                value.set_low_high(self.hardware_ids.vendor_id, self.hardware_ids.device_id);
576            }
577            CommonHeader::STATUS_COMMAND => {
578                let mut status =
579                    cfg_space::Status::new().with_capabilities_list(!self.capabilities.is_empty());
580
581                if let Some(intx_interrupt) = &self.intx_interrupt {
582                    if intx_interrupt.interrupt_status.load(Ordering::SeqCst) {
583                        status.set_interrupt_status(true);
584                    }
585                }
586
587                value.set_low_high(self.state.command.into_bits(), status.into_bits());
588            }
589            CommonHeader::CLASS_REVISION => {
590                value.set_bytes(
591                    self.hardware_ids.revision_id,
592                    u8::from(self.hardware_ids.prog_if),
593                    u8::from(self.hardware_ids.sub_class),
594                    u8::from(self.hardware_ids.base_class),
595                );
596            }
597            CommonHeader::RESERVED_CAP_PTR => {
598                value.set(if self.capabilities.is_empty() {
599                    0
600                } else {
601                    COMMON_HEADER_END as u32
602                });
603            }
604            // Capabilities space - handled by common emulator
605            _ if (COMMON_HEADER_END..EXT_CAP_START).contains(&offset) => {
606                return self.read_capabilities(offset, value);
607            }
608            // Extended capabilities space - handled by common emulator
609            _ if (EXT_CAP_START..EXT_CAP_END).contains(&offset) => {
610                return self.read_extended_capabilities(offset, value);
611            }
612            // Check if this is a BAR read
613            _ if self.is_bar_offset(offset) => {
614                return self.read_bar(offset, value);
615            }
616            // Unhandled access - not part of common header, caller should handle
617            _ => {
618                return CommonHeaderResult::Unhandled;
619            }
620        };
621
622        tracing::trace!(
623            ?value,
624            "ConfigSpaceCommonHeaderEmulator: read offset={:#x}",
625            offset,
626        );
627        // Handled access
628        CommonHeaderResult::Handled
629    }
630
631    /// Write to the config space.
632    /// Returns CommonHeaderResult indicating if handled, unhandled, or failed.
633    pub fn write(
634        &mut self,
635        address: PciConfigAddress,
636        val: ByteEnabledDwordWrite,
637    ) -> CommonHeaderResult {
638        use cfg_space::CommonHeader;
639        let offset = address.byte_offset();
640
641        tracing::trace!(
642            ?val,
643            "ConfigSpaceCommonHeaderEmulator: write offset={:#x}",
644            offset,
645        );
646
647        // Capture the bus number as described in section 2.2.6.2.1 of the PCIe spec (Rev 7.0).
648        // The spec recommends that functions only capture these values on successful handling of
649        // the access, but we can't really tell that here from this shared emulation helper so we
650        // instead capture unconditionally.
651        if address.bus != self.state.captured_bus_number
652            || address.devfn != self.state.captured_devfn
653        {
654            tracing::debug!(
655                "ConfigSpaceCommonHeaderEmulator: capturing bdf {:x}:{:x}.{:x}",
656                address.bus,
657                address.device(),
658                address.function(),
659            );
660        }
661        self.state.captured_bus_number = address.bus;
662        self.state.captured_devfn = address.devfn;
663
664        match CommonHeader(offset) {
665            CommonHeader::STATUS_COMMAND => {
666                let mut command =
667                    cfg_space::Command::from_bits(val.merge_low(self.state.command.into_bits()));
668                if command.into_bits() & !SUPPORTED_COMMAND_BITS != 0 {
669                    tracelimit::warn_ratelimited!(offset, ?val, "setting invalid command bits");
670                    // still do our best
671                    command =
672                        cfg_space::Command::from_bits(command.into_bits() & SUPPORTED_COMMAND_BITS);
673                };
674
675                if self.state.command.intx_disable() != command.intx_disable() {
676                    self.update_intx_disable(command.intx_disable())
677                }
678
679                if self.state.command.mmio_enabled() != command.mmio_enabled() {
680                    self.update_mmio_enabled(command.mmio_enabled())
681                }
682
683                self.state.command = command;
684            }
685            // Capabilities space - handled by common emulator
686            _ if (COMMON_HEADER_END..EXT_CAP_START).contains(&offset) => {
687                return self.write_capabilities(offset, val);
688            }
689            // Extended capabilities space - handled by common emulator
690            _ if (EXT_CAP_START..EXT_CAP_END).contains(&offset) => {
691                return self.write_extended_capabilities(offset, val);
692            }
693            // Check if this is a BAR write (Type 0: 0x10-0x27, Type 1: 0x10-0x17)
694            _ if self.is_bar_offset(offset) => {
695                return self.write_bar(offset, val);
696            }
697            // Unhandled access - not part of common header, caller should handle
698            _ => {
699                return CommonHeaderResult::Unhandled;
700            }
701        }
702
703        // Handled access
704        CommonHeaderResult::Handled
705    }
706
707    /// Helper for reading BAR registers
708    fn read_bar(&self, offset: u16, mut value: ByteEnabledDwordRead<'_>) -> CommonHeaderResult {
709        if !self.is_bar_offset(offset) {
710            return CommonHeaderResult::Unhandled;
711        }
712
713        let bar_index = self.get_bar_index(offset);
714        value.set(if bar_index < N {
715            self.state.base_addresses[bar_index]
716        } else {
717            0
718        });
719        CommonHeaderResult::Handled
720    }
721
722    /// Helper for writing BAR registers
723    fn write_bar(&mut self, offset: u16, val: ByteEnabledDwordWrite) -> CommonHeaderResult {
724        if !self.is_bar_offset(offset) {
725            return CommonHeaderResult::Unhandled;
726        }
727
728        // Handle BAR writes - only allow when MMIO is disabled
729        if !self.state.command.mmio_enabled() {
730            let bar_index = self.get_bar_index(offset);
731            if bar_index < N {
732                let val = val.merge(self.state.base_addresses[bar_index]);
733                let mut bar_value = val & self.bar_masks[bar_index];
734
735                // Preserve BAR in-band attribute bits (low nibble) on the
736                // low DWORD of mapped BARs. This applies to both 32-bit BARs
737                // and the low DWORD of 64-bit BARs. Upper DWORDs are not
738                // marked as mapped and therefore skip this path.
739                if self.mapped_memory[bar_index].is_some() {
740                    const BAR_ATTR_MASK: u32 = 0xF;
741                    let attr_bits = self.bar_masks[bar_index] & BAR_ATTR_MASK;
742                    bar_value = (bar_value & !BAR_ATTR_MASK) | attr_bits;
743                }
744
745                self.state.base_addresses[bar_index] = bar_value;
746            }
747        }
748        CommonHeaderResult::Handled
749    }
750
751    /// Read from capabilities space. `offset` must be 32-bit aligned and >= COMMON_HEADER_END.
752    fn read_capabilities(
753        &self,
754        offset: u16,
755        mut value: ByteEnabledDwordRead<'_>,
756    ) -> CommonHeaderResult {
757        if (COMMON_HEADER_END..EXT_CAP_START).contains(&offset) {
758            if let Some((cap_index, cap_offset)) =
759                self.get_capability_index_and_offset(offset - COMMON_HEADER_END)
760            {
761                if cap_offset == 0 {
762                    // Byte 1 of the first DWORD of the capability is the offset of the next
763                    // capability (or 0).
764                    if let Some(mut v) = value.restrict(PciConfigByteEnable::BYTE1) {
765                        let next = if cap_index < self.capabilities.len() - 1 {
766                            offset as u32 + self.capabilities[cap_index].len() as u32
767                        } else {
768                            0
769                        };
770                        v.set(next << 8);
771                    }
772
773                    if let Some(v) = value.exclude(PciConfigByteEnable::BYTE1) {
774                        self.capabilities[cap_index].read(cap_offset, v);
775                    }
776                } else {
777                    self.capabilities[cap_index].read(cap_offset, value);
778                }
779            } else {
780                // Unimplemented registers in a present function read as 0.
781                value.set(0);
782            }
783            CommonHeaderResult::Handled
784        } else {
785            CommonHeaderResult::Failed(IoError::InvalidRegister)
786        }
787    }
788
789    /// Write to capabilities space. `offset` must be 32-bit aligned and >= COMMON_HEADER_END.
790    fn write_capabilities(
791        &mut self,
792        offset: u16,
793        val: ByteEnabledDwordWrite,
794    ) -> CommonHeaderResult {
795        if (COMMON_HEADER_END..EXT_CAP_START).contains(&offset) {
796            if let Some((cap_index, cap_offset)) =
797                self.get_capability_index_and_offset(offset - COMMON_HEADER_END)
798            {
799                self.capabilities[cap_index].write(cap_offset, val);
800                CommonHeaderResult::Handled
801            } else {
802                // Writes to unimplemented registers in a present function are
803                // dropped.
804                CommonHeaderResult::Handled
805            }
806        } else {
807            CommonHeaderResult::Failed(IoError::InvalidRegister)
808        }
809    }
810
811    /// Read from extended capabilities space (EXT_CAP_START-EXT_CAP_END). `offset` must be 32-bit aligned.
812    fn read_extended_capabilities(
813        &self,
814        offset: u16,
815        mut value: ByteEnabledDwordRead<'_>,
816    ) -> CommonHeaderResult {
817        if (EXT_CAP_START..EXT_CAP_END).contains(&offset) {
818            if self.is_pcie_device() {
819                if let Some((cap_index, cap_offset, cap_base)) =
820                    self.get_extended_capability_index_and_offset(offset)
821                {
822                    self.extended_capabilities[cap_index].read(cap_offset, value.reborrow());
823
824                    if cap_offset == 0 {
825                        let next = if cap_index < self.extended_capabilities.len() - 1 {
826                            let cap_size = Self::validated_extended_cap_len_bytes(
827                                self.extended_capabilities[cap_index].as_ref(),
828                            ) as u16;
829                            cap_base + cap_size
830                        } else {
831                            0
832                        };
833
834                        let mut cap_result = value.extract();
835                        if let Some(mut v) = value.restrict(PciConfigByteEnable::HIGH_WORD) {
836                            assert!(cap_result & 0xfff0_0000 == 0);
837                            cap_result |= u32::from(next) << 20;
838                            v.set(cap_result);
839                        }
840                    }
841                } else {
842                    // No more extended capabilities; the terminating header
843                    // reads as 0.
844                    value.set(0);
845                }
846            } else {
847                // A conventional (non-PCIe) function has no extended
848                // configuration space; the region reads as 0.
849                value.set(0);
850            };
851            CommonHeaderResult::Handled
852        } else {
853            CommonHeaderResult::Failed(IoError::InvalidRegister)
854        }
855    }
856
857    /// Write to extended capabilities space (EXT_CAP_START-EXT_CAP_END). `offset` must be 32-bit aligned.
858    fn write_extended_capabilities(
859        &mut self,
860        offset: u16,
861        val: ByteEnabledDwordWrite,
862    ) -> CommonHeaderResult {
863        if (EXT_CAP_START..EXT_CAP_END).contains(&offset) {
864            if self.is_pcie_device() {
865                if let Some((cap_index, cap_offset, _)) =
866                    self.get_extended_capability_index_and_offset(offset)
867                {
868                    self.extended_capabilities[cap_index].write(cap_offset, val);
869                }
870            } else {
871                // No extended configuration space on a conventional function;
872                // writes to the region are dropped.
873            }
874            CommonHeaderResult::Handled
875        } else {
876            CommonHeaderResult::Failed(IoError::InvalidRegister)
877        }
878    }
879
880    // ===== Utility and Query Functions =====
881
882    /// Finds a BAR + offset by address.
883    pub fn find_bar(&self, address: u64) -> Option<(u8, u64)> {
884        self.active_bars.find(address)
885    }
886
887    /// Gets the active base address for a specific BAR index, if mapped.
888    pub fn bar_address(&self, bar: u8) -> Option<u64> {
889        self.active_bars.get(bar)
890    }
891
892    /// Check if this device is a PCIe device by looking for the PCI Express capability.
893    pub fn is_pcie_device(&self) -> bool {
894        self.capabilities
895            .iter()
896            .any(|cap| cap.capability_id() == CapabilityId::PCI_EXPRESS)
897    }
898
899    /// Get extended capability index and offset for a given config offset.
900    fn get_extended_capability_index_and_offset(&self, offset: u16) -> Option<(usize, u16, u16)> {
901        let mut cap_base = EXT_CAP_START;
902        for i in 0..self.extended_capabilities.len() {
903            let cap_size =
904                Self::validated_extended_cap_len_bytes(self.extended_capabilities[i].as_ref())
905                    as u16;
906            if offset < cap_base + cap_size {
907                return Some((i, offset - cap_base, cap_base));
908            }
909            cap_base += cap_size;
910            assert!(
911                cap_base <= EXT_CAP_END,
912                "extended capabilities exceed config space window {:#x}..{:#x} (exclusive end), cap_base={:#x}",
913                EXT_CAP_START,
914                EXT_CAP_END,
915                cap_base
916            );
917        }
918        None
919    }
920
921    /// Get capability index and offset for a given offset
922    fn get_capability_index_and_offset(&self, offset: u16) -> Option<(usize, u16)> {
923        let mut cap_offset = 0;
924        for i in 0..self.capabilities.len() {
925            let cap_size = self.capabilities[i].len() as u16;
926            if offset < cap_offset + cap_size {
927                return Some((i, offset - cap_offset));
928            }
929            cap_offset += cap_size;
930        }
931        None
932    }
933
934    /// Check if an offset corresponds to a BAR register
935    fn is_bar_offset(&self, offset: u16) -> bool {
936        // Type 0: BAR0-BAR5 (0x10-0x27), Type 1: BAR0-BAR1 (0x10-0x17)
937        let bar_start = cfg_space::HeaderType00::BAR0.0;
938        let bar_end = bar_start + (N as u16) * 4;
939        (bar_start..bar_end).contains(&offset) && offset.is_multiple_of(4)
940    }
941
942    /// Get the BAR index for a given offset
943    fn get_bar_index(&self, offset: u16) -> usize {
944        ((offset - cfg_space::HeaderType00::BAR0.0) / 4) as usize
945    }
946
947    /// Get BAR masks (for testing only)
948    #[cfg(test)]
949    pub fn bar_masks(&self) -> &[u32; N] {
950        &self.bar_masks
951    }
952}
953
954#[derive(Debug, Inspect)]
955struct ConfigSpaceType0EmulatorState {
956    /// A read/write register that doesn't matter in virtualized contexts
957    latency_timer: u8,
958}
959
960impl ConfigSpaceType0EmulatorState {
961    fn new() -> Self {
962        Self { latency_timer: 0 }
963    }
964}
965
966/// Emulator for the standard Type 0 PCI configuration space header.
967#[derive(Inspect)]
968pub struct ConfigSpaceType0Emulator {
969    /// The common header emulator that handles shared functionality
970    #[inspect(flatten)]
971    common: ConfigSpaceCommonHeaderEmulatorType0,
972    /// Type 0 specific state
973    state: ConfigSpaceType0EmulatorState,
974}
975
976mod inspect_helpers {
977    use super::*;
978
979    pub(crate) fn bars_generic<const N: usize>(bars: &[u32; N]) -> impl Inspect + '_ {
980        inspect::AsHex(inspect::iter_by_index(bars).prefix("bar"))
981    }
982}
983
984/// Different kinds of memory that a BAR can be backed by
985#[derive(Inspect)]
986#[inspect(tag = "kind")]
987pub enum BarMemoryKind {
988    /// BAR memory is routed to the device's `MmioIntercept` handler
989    Intercept(#[inspect(rename = "handle")] Box<dyn ControlMmioIntercept>),
990    /// BAR memory is routed to a shared memory region
991    SharedMem(#[inspect(skip)] Box<dyn MappableGuestMemory>),
992    /// **TESTING ONLY** BAR memory isn't backed by anything!
993    Dummy,
994}
995
996impl std::fmt::Debug for BarMemoryKind {
997    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
998        match self {
999            Self::Intercept(control) => {
1000                write!(f, "Intercept(region_name: {}, ..)", control.region_name())
1001            }
1002            Self::SharedMem(_) => write!(f, "Mmap(..)"),
1003            Self::Dummy => write!(f, "Dummy"),
1004        }
1005    }
1006}
1007
1008impl BarMemoryKind {
1009    fn map_to_guest(&mut self, gpa: u64) -> std::io::Result<()> {
1010        match self {
1011            BarMemoryKind::Intercept(control) => {
1012                control.map(gpa);
1013                Ok(())
1014            }
1015            BarMemoryKind::SharedMem(control) => control.map_to_guest(gpa, true),
1016            BarMemoryKind::Dummy => Ok(()),
1017        }
1018    }
1019
1020    fn unmap_from_guest(&mut self) {
1021        match self {
1022            BarMemoryKind::Intercept(control) => {
1023                // Some `ControlMmioIntercept` implementations are not idempotent
1024                // and panic if `unmap()` is called while the region is not
1025                // mapped -- which happens when a device is torn down before the
1026                // guest ever enables memory space. Only unmap when mapped.
1027                if control.addr().is_some() {
1028                    control.unmap();
1029                }
1030            }
1031            BarMemoryKind::SharedMem(control) => control.unmap_from_guest(),
1032            BarMemoryKind::Dummy => {}
1033        }
1034    }
1035}
1036
1037/// Container type that describes a device's available BARs
1038// TODO: support more advanced BAR configurations
1039// e.g: mixed 32-bit and 64-bit
1040// e.g: IO space BARs
1041#[derive(Debug)]
1042pub struct DeviceBars {
1043    bars: [Option<(u64, BarMemoryKind)>; 6],
1044}
1045
1046impl DeviceBars {
1047    /// Create a new instance of [`DeviceBars`]
1048    pub fn new() -> DeviceBars {
1049        DeviceBars {
1050            bars: Default::default(),
1051        }
1052    }
1053
1054    /// Set BAR0
1055    pub fn bar0(mut self, len: u64, memory: BarMemoryKind) -> Self {
1056        self.bars[0] = Some((len, memory));
1057        self
1058    }
1059
1060    /// Set BAR2
1061    pub fn bar2(mut self, len: u64, memory: BarMemoryKind) -> Self {
1062        self.bars[2] = Some((len, memory));
1063        self
1064    }
1065
1066    /// Set BAR4
1067    pub fn bar4(mut self, len: u64, memory: BarMemoryKind) -> Self {
1068        self.bars[4] = Some((len, memory));
1069        self
1070    }
1071}
1072
1073impl ConfigSpaceType0Emulator {
1074    /// Create a new [`ConfigSpaceType0Emulator`]
1075    pub fn new(
1076        hardware_ids: HardwareIds,
1077        capabilities: Vec<Box<dyn PciCapability>>,
1078        extended_capabilities: Vec<Box<dyn PciExtendedCapability>>,
1079        bars: DeviceBars,
1080    ) -> Self {
1081        let common = ConfigSpaceCommonHeaderEmulator::new(
1082            hardware_ids,
1083            capabilities,
1084            extended_capabilities,
1085            bars,
1086        );
1087
1088        Self {
1089            common,
1090            state: ConfigSpaceType0EmulatorState::new(),
1091        }
1092    }
1093
1094    /// If the device is multi-function, enable bit 7 in the Header register.
1095    pub fn with_multi_function_bit(mut self, bit: bool) -> Self {
1096        self.common = self.common.with_multi_function_bit(bit);
1097        self
1098    }
1099
1100    /// If using legacy INT#x interrupts: wire a LineInterrupt to one of the 4
1101    /// INT#x pins, returning an object that manages configuration space bits
1102    /// when the device sets the interrupt level.
1103    pub fn set_interrupt_pin(
1104        &mut self,
1105        pin: PciInterruptPin,
1106        line: LineInterrupt,
1107    ) -> Arc<IntxInterrupt> {
1108        self.common.set_interrupt_pin(pin, line)
1109    }
1110
1111    /// Returns the currently captured bus number.
1112    pub fn captured_bus_number(&self) -> u8 {
1113        self.common.captured_bus_number()
1114    }
1115
1116    /// Returns the currently captured devfn (device << 3 | function) number.
1117    pub fn captured_devfn(&self) -> u8 {
1118        self.common.captured_devfn()
1119    }
1120
1121    /// Resets the configuration space state.
1122    pub fn reset(&mut self) {
1123        self.common.reset();
1124        self.state = ConfigSpaceType0EmulatorState::new();
1125    }
1126
1127    /// Read from the config space.
1128    pub fn read(&self, address: PciConfigAddress, mut value: ByteEnabledDwordRead<'_>) -> IoResult {
1129        use cfg_space::HeaderType00;
1130        let offset = address.byte_offset();
1131
1132        // First try to handle with common header emulator
1133        match self.common.read(address, value.reborrow()) {
1134            CommonHeaderResult::Handled => return IoResult::Ok,
1135            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1136            CommonHeaderResult::Unhandled => {
1137                // Continue with Type 0 specific handling
1138            }
1139        }
1140
1141        // Handle Type 0 specific registers
1142        match HeaderType00(offset) {
1143            HeaderType00::BIST_HEADER => {
1144                let mut v = (self.state.latency_timer as u32) << 8;
1145                if self.common.multi_function_bit() {
1146                    // enable top-most bit of the header register
1147                    v |= 0x80 << 16;
1148                }
1149                value.set(v);
1150            }
1151            HeaderType00::CARDBUS_CIS_PTR => value.set(0),
1152            HeaderType00::SUBSYSTEM_ID => {
1153                value.set_low_high(
1154                    self.common.hardware_ids().type0_sub_vendor_id,
1155                    self.common.hardware_ids().type0_sub_system_id,
1156                );
1157            }
1158            HeaderType00::EXPANSION_ROM_BASE => value.set(0),
1159            HeaderType00::RESERVED => value.set(0),
1160            HeaderType00::LATENCY_INTERRUPT => {
1161                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin, Bits 31-16: Latency Timer
1162                value.set(
1163                    (self.state.latency_timer as u32) << 16
1164                        | (self.common.interrupt_pin() as u32) << 8
1165                        | self.common.interrupt_line() as u32,
1166                );
1167            }
1168            _ => {
1169                tracelimit::warn_ratelimited!(offset, "unexpected config space read");
1170                return IoResult::Err(IoError::InvalidRegister);
1171            }
1172        };
1173
1174        IoResult::Ok
1175    }
1176
1177    /// Read a byte-enabled DWORD from the config space. `offset` must be 32-bit aligned.
1178    pub fn read_byte_enabled(&self, offset: u16, value: ByteEnabledDwordRead<'_>) -> IoResult {
1179        if !offset.is_multiple_of(4) {
1180            return IoResult::Err(IoError::UnalignedAccess);
1181        }
1182
1183        let Some(addr) = PciConfigAddress::new(0, 0, offset / 4) else {
1184            return IoResult::Err(IoError::InvalidRegister);
1185        };
1186
1187        self.read(addr, value)
1188    }
1189
1190    /// Write to the config space.
1191    pub fn write(&mut self, address: PciConfigAddress, val: ByteEnabledDwordWrite) -> IoResult {
1192        use cfg_space::HeaderType00;
1193        let offset = address.byte_offset();
1194
1195        // First try to handle with common header emulator
1196        match self.common.write(address, val) {
1197            CommonHeaderResult::Handled => return IoResult::Ok,
1198            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1199            CommonHeaderResult::Unhandled => {
1200                // Continue with Type 0 specific handling
1201            }
1202        }
1203
1204        // Handle Type 0 specific registers
1205        match HeaderType00(offset) {
1206            HeaderType00::BIST_HEADER => {
1207                // BIST_HEADER - Type 0 specific handling
1208                // For now, just ignore these writes (header type is read-only)
1209            }
1210            HeaderType00::LATENCY_INTERRUPT => {
1211                // Bits 7-0: Interrupt Line (read/write)
1212                // Bits 15-8: Interrupt Pin (read-only, ignore writes)
1213                // Bits 31-16: Latency Timer (read/write)
1214                let low = val.merge_low(
1215                    (self.common.interrupt_pin() as u16) << 8 | self.common.interrupt_line() as u16,
1216                );
1217                self.common.set_interrupt_line(low as u8);
1218                self.state.latency_timer = val.merge_high(self.state.latency_timer as u16) as u8;
1219            }
1220            // all other base regs are noops
1221            _ if offset < COMMON_HEADER_END && offset.is_multiple_of(4) => (),
1222            _ => {
1223                tracelimit::warn_ratelimited!(offset, ?val, "unexpected config space write");
1224                return IoResult::Err(IoError::InvalidRegister);
1225            }
1226        }
1227
1228        IoResult::Ok
1229    }
1230
1231    /// Write a byte-enabled DWORD from the config space. `offset` must be 32-bit aligned.
1232    pub fn write_byte_enabled(&mut self, offset: u16, value: ByteEnabledDwordWrite) -> IoResult {
1233        if !offset.is_multiple_of(4) {
1234            return IoResult::Err(IoError::UnalignedAccess);
1235        }
1236
1237        let Some(addr) = PciConfigAddress::new(0, 0, offset / 4) else {
1238            return IoResult::Err(IoError::InvalidRegister);
1239        };
1240
1241        self.write(addr, value)
1242    }
1243
1244    /// Finds a BAR + offset by address.
1245    pub fn find_bar(&self, address: u64) -> Option<(u8, u64)> {
1246        self.common.find_bar(address)
1247    }
1248
1249    /// Gets the active base address for a specific BAR index, if mapped.
1250    pub fn bar_address(&self, bar: u8) -> Option<u64> {
1251        self.common.bar_address(bar)
1252    }
1253
1254    /// Checks if this device is a PCIe device by looking for the PCI Express capability.
1255    pub fn is_pcie_device(&self) -> bool {
1256        self.common.is_pcie_device()
1257    }
1258
1259    /// Set the presence detect state for a hotplug-capable slot.
1260    /// This method finds the PCIe Express capability and calls its set_presence_detect_state method.
1261    /// If the PCIe Express capability is not found, the call is silently ignored.
1262    ///
1263    /// # Arguments
1264    /// * `present` - true if a device is present in the slot, false if the slot is empty
1265    pub fn set_presence_detect_state(&mut self, present: bool) {
1266        for capability in self.common.capabilities_mut() {
1267            if let Some(pcie_cap) = capability.as_pci_express_mut() {
1268                pcie_cap.set_presence_detect_state(present);
1269                return;
1270            }
1271        }
1272
1273        // PCIe Express capability not found - silently ignore
1274    }
1275}
1276
1277#[derive(Debug, Inspect)]
1278struct ConfigSpaceType1EmulatorState {
1279    /// The subordinate bus number register. Software programs
1280    /// this register with the highest bus number below the bridge.
1281    #[inspect(hex)]
1282    subordinate_bus_number: u8,
1283    /// The secondary bus number register. Software programs
1284    /// this register with the bus number assigned to the secondary
1285    /// side of the bridge.
1286    #[inspect(hex)]
1287    secondary_bus_number: u8,
1288    /// The primary bus number register. This is unused for PCI Express but
1289    /// is supposed to be read/write for compability with legacy software.
1290    #[inspect(hex)]
1291    primary_bus_number: u8,
1292    /// The memory base register. Software programs the upper 12 bits of this
1293    /// register with the upper 12 bits of a 32-bit base address of MMIO assigned
1294    /// to the hierarchy under the bridge (the lower 20 bits are assumed to be 0s).
1295    #[inspect(hex)]
1296    memory_base: u16,
1297    /// The memory limit register. Software programs the upper 12 bits of this
1298    /// register with the upper 12 bits of a 32-bit limit address of MMIO assigned
1299    /// to the hierarchy under the bridge (the lower 20 bits are assumed to be 1s).
1300    #[inspect(hex)]
1301    memory_limit: u16,
1302    /// The prefetchable memory base register. Software programs the upper 12 bits of
1303    /// this register with bits 20:31 of the base address of the prefetchable MMIO
1304    /// window assigned to the hierarchy under the bridge. Bits 0:19 are assumed to
1305    /// be 0s.
1306    #[inspect(hex)]
1307    prefetch_base: u16,
1308    /// The prefetchable memory limit register. Software programs the upper 12 bits of
1309    /// this register with bits 20:31 of the limit address of the prefetchable MMIO
1310    /// window assigned to the hierarchy under the bridge. Bits 0:19 are assumed to
1311    /// be 1s.
1312    #[inspect(hex)]
1313    prefetch_limit: u16,
1314    /// The prefetchable memory base upper 32 bits register. When the bridge supports
1315    /// 64-bit addressing for prefetchable memory, software programs this register
1316    /// with the upper 32 bits of the base address of the prefetchable MMIO window
1317    /// assigned to the hierarchy under the bridge.
1318    #[inspect(hex)]
1319    prefetch_base_upper: u32,
1320    /// The prefetchable memory limit upper 32 bits register. When the bridge supports
1321    /// 64-bit addressing for prefetchable memory, software programs this register
1322    /// with the upper 32 bits of the base address of the prefetchable MMIO window
1323    /// assigned to the hierarchy under the bridge.
1324    #[inspect(hex)]
1325    prefetch_limit_upper: u32,
1326    /// The bridge control register. Contains various control bits for bridge behavior
1327    /// such as secondary bus reset, VGA enable, etc.
1328    #[inspect(hex)]
1329    bridge_control: u16,
1330}
1331
1332impl ConfigSpaceType1EmulatorState {
1333    fn new() -> Self {
1334        Self {
1335            subordinate_bus_number: 0,
1336            secondary_bus_number: 0,
1337            primary_bus_number: 0,
1338            memory_base: 0,
1339            memory_limit: 0,
1340            prefetch_base: 0,
1341            prefetch_limit: 0,
1342            prefetch_base_upper: 0,
1343            prefetch_limit_upper: 0,
1344            bridge_control: 0,
1345        }
1346    }
1347}
1348
1349/// Emulator for the standard Type 1 PCI configuration space header.
1350#[derive(Inspect)]
1351pub struct ConfigSpaceType1Emulator {
1352    /// The common header emulator that handles shared functionality
1353    #[inspect(flatten)]
1354    common: ConfigSpaceCommonHeaderEmulatorType1,
1355    /// Type 1 specific state
1356    state: ConfigSpaceType1EmulatorState,
1357    /// Shared bus range, synced automatically on writes, reset, and restore.
1358    #[inspect(skip)]
1359    bus_range: crate::bus_range::AssignedBusRange,
1360}
1361
1362impl ConfigSpaceType1Emulator {
1363    /// Create a new [`ConfigSpaceType1Emulator`]
1364    pub fn new(
1365        hardware_ids: HardwareIds,
1366        capabilities: Vec<Box<dyn PciCapability>>,
1367        extended_capabilities: Vec<Box<dyn PciExtendedCapability>>,
1368    ) -> Self {
1369        Self::new_with_bars(
1370            hardware_ids,
1371            capabilities,
1372            extended_capabilities,
1373            DeviceBars::new(),
1374        )
1375    }
1376
1377    /// Create a new [`ConfigSpaceType1Emulator`] with caller-specified BARs.
1378    pub fn new_with_bars(
1379        hardware_ids: HardwareIds,
1380        capabilities: Vec<Box<dyn PciCapability>>,
1381        extended_capabilities: Vec<Box<dyn PciExtendedCapability>>,
1382        bars: DeviceBars,
1383    ) -> Self {
1384        let common = ConfigSpaceCommonHeaderEmulator::new(
1385            hardware_ids,
1386            capabilities,
1387            extended_capabilities,
1388            bars,
1389        );
1390
1391        Self {
1392            common,
1393            state: ConfigSpaceType1EmulatorState::new(),
1394            bus_range: crate::bus_range::AssignedBusRange::new(),
1395        }
1396    }
1397
1398    /// Returns the currently captured bus number.
1399    pub fn captured_bus_number(&self) -> u8 {
1400        self.common.captured_bus_number()
1401    }
1402
1403    /// Returns the currently captured devfn (device << 3 | function) number.
1404    pub fn captured_devfn(&self) -> u8 {
1405        self.common.captured_devfn()
1406    }
1407
1408    /// Resets the configuration space state.
1409    pub fn reset(&mut self) {
1410        self.common.reset();
1411        self.state = ConfigSpaceType1EmulatorState::new();
1412        self.sync_bus_range();
1413    }
1414
1415    /// Set the multi-function bit for this device.
1416    pub fn with_multi_function_bit(mut self, multi_function: bool) -> Self {
1417        self.common = self.common.with_multi_function_bit(multi_function);
1418        self
1419    }
1420
1421    /// Returns the range of bus numbers the bridge is programmed to decode.
1422    pub fn assigned_bus_range(&self) -> RangeInclusive<u8> {
1423        let secondary = self.state.secondary_bus_number;
1424        let subordinate = self.state.subordinate_bus_number;
1425        if secondary <= subordinate {
1426            secondary..=subordinate
1427        } else {
1428            0..=0
1429        }
1430    }
1431
1432    /// Returns a clone of the shared bus range.
1433    ///
1434    /// The returned handle shares the same underlying atomic — bus number
1435    /// changes from writes, resets, and restores are reflected automatically.
1436    pub fn bus_range(&self) -> crate::bus_range::AssignedBusRange {
1437        self.bus_range.clone()
1438    }
1439
1440    /// Pushes the current secondary/subordinate bus numbers into the shared
1441    /// atomic so that consumers (ITS wrappers, SMMU) see the latest values.
1442    fn sync_bus_range(&self) {
1443        self.bus_range.set_bus_range(
1444            self.state.secondary_bus_number,
1445            self.state.subordinate_bus_number,
1446        );
1447    }
1448
1449    fn decode_memory_range(&self, base_register: u16, limit_register: u16) -> (u32, u32) {
1450        let base_addr = u32::from(base_register) << 16;
1451        let limit_addr = (u32::from(limit_register) << 16) | 0xF_FFFF;
1452        (base_addr, limit_addr)
1453    }
1454
1455    /// If memory decoding is currently enabled, and the memory window assignment is valid,
1456    /// returns the 32-bit memory addresses the bridge is programmed to decode.
1457    pub fn assigned_memory_range(&self) -> Option<RangeInclusive<u32>> {
1458        let (base_addr, limit_addr) =
1459            self.decode_memory_range(self.state.memory_base, self.state.memory_limit);
1460        if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1461            Some(base_addr..=limit_addr)
1462        } else {
1463            None
1464        }
1465    }
1466
1467    /// If memory decoding is currently enabled, and the prefetchable memory window assignment
1468    /// is valid, returns the 64-bit prefetchable memory addresses the bridge is programmed to decode.
1469    pub fn assigned_prefetch_range(&self) -> Option<RangeInclusive<u64>> {
1470        let (base_low, limit_low) =
1471            self.decode_memory_range(self.state.prefetch_base, self.state.prefetch_limit);
1472        let base_addr = (self.state.prefetch_base_upper as u64) << 32 | base_low as u64;
1473        let limit_addr = (self.state.prefetch_limit_upper as u64) << 32 | limit_low as u64;
1474        if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1475            Some(base_addr..=limit_addr)
1476        } else {
1477            None
1478        }
1479    }
1480
1481    /// Read from the config space.
1482    pub fn read(&self, address: PciConfigAddress, mut value: ByteEnabledDwordRead<'_>) -> IoResult {
1483        use cfg_space::HeaderType01;
1484        let offset = address.byte_offset();
1485
1486        // First try to handle with common header emulator
1487        match self.common.read(address, value.reborrow()) {
1488            CommonHeaderResult::Handled => return IoResult::Ok,
1489            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1490            CommonHeaderResult::Unhandled => {
1491                // Continue with Type 1 specific handling
1492            }
1493        }
1494
1495        // Handle Type 1 specific registers
1496        match HeaderType01(offset) {
1497            HeaderType01::BIST_HEADER => {
1498                // Header type 01 with optional multi-function bit
1499                value.set(if self.common.multi_function_bit() {
1500                    0x00810000 // Header type 01 with multi-function bit (bit 23)
1501                } else {
1502                    0x00010000 // Header type 01 without multi-function bit
1503                });
1504            }
1505            HeaderType01::LATENCY_BUS_NUMBERS => {
1506                value.set_bytes(
1507                    self.state.primary_bus_number,
1508                    self.state.secondary_bus_number,
1509                    self.state.subordinate_bus_number,
1510                    0,
1511                );
1512            }
1513            HeaderType01::SEC_STATUS_IO_RANGE => value.set(0),
1514            HeaderType01::MEMORY_RANGE => {
1515                value.set_low_high(self.state.memory_base, self.state.memory_limit)
1516            }
1517            HeaderType01::PREFETCH_RANGE => {
1518                // Set the low bit in both the limit and base registers to indicate
1519                // support for 64-bit addressing.
1520                value.set_low_high(
1521                    self.state.prefetch_base | cfg_space::PREFETCH_MEMORY_BASE_LIMIT_64BIT,
1522                    self.state.prefetch_limit | cfg_space::PREFETCH_MEMORY_BASE_LIMIT_64BIT,
1523                )
1524            }
1525            HeaderType01::PREFETCH_BASE_UPPER => value.set(self.state.prefetch_base_upper),
1526            HeaderType01::PREFETCH_LIMIT_UPPER => value.set(self.state.prefetch_limit_upper),
1527            HeaderType01::IO_RANGE_UPPER => value.set(0),
1528            HeaderType01::EXPANSION_ROM_BASE => value.set(0),
1529            HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1530                // Read interrupt line from common header and bridge control from state
1531                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin (0), Bits 31-16: Bridge Control
1532                value.set_low_high(
1533                    self.common.interrupt_line() as u16,
1534                    self.state.bridge_control,
1535                )
1536            }
1537            _ => {
1538                tracelimit::warn_ratelimited!(offset, "unexpected config space read");
1539                return IoResult::Err(IoError::InvalidRegister);
1540            }
1541        };
1542
1543        IoResult::Ok
1544    }
1545
1546    /// Read a byte-enabled DWORD from the config space. `offset` must be 32-bit aligned.
1547    pub fn read_byte_enabled(&self, offset: u16, value: ByteEnabledDwordRead<'_>) -> IoResult {
1548        if !offset.is_multiple_of(4) {
1549            return IoResult::Err(IoError::UnalignedAccess);
1550        }
1551
1552        let Some(addr) = PciConfigAddress::new(0, 0, offset / 4) else {
1553            return IoResult::Err(IoError::InvalidRegister);
1554        };
1555
1556        self.read(addr, value)
1557    }
1558
1559    /// Write to the config space.
1560    pub fn write(&mut self, address: PciConfigAddress, val: ByteEnabledDwordWrite) -> IoResult {
1561        use cfg_space::HeaderType01;
1562        let offset = address.byte_offset();
1563
1564        // First try to handle with common header emulator
1565        match self.common.write(address, val) {
1566            CommonHeaderResult::Handled => return IoResult::Ok,
1567            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1568            CommonHeaderResult::Unhandled => {
1569                // Continue with Type 1 specific handling
1570            }
1571        }
1572
1573        // Handle Type 1 specific registers
1574        match HeaderType01(offset) {
1575            HeaderType01::BIST_HEADER => {
1576                // BIST_HEADER - Type 1 specific handling
1577                // For now, just ignore these writes (latency timer would go here if supported)
1578            }
1579            HeaderType01::LATENCY_BUS_NUMBERS => {
1580                let current = (self.state.subordinate_bus_number as u32) << 16
1581                    | (self.state.secondary_bus_number as u32) << 8
1582                    | self.state.primary_bus_number as u32;
1583                let val = val.merge(current);
1584                self.state.subordinate_bus_number = (val >> 16) as u8;
1585                self.state.secondary_bus_number = (val >> 8) as u8;
1586                self.state.primary_bus_number = val as u8;
1587                self.sync_bus_range();
1588            }
1589            HeaderType01::MEMORY_RANGE => {
1590                self.state.memory_base = val.merge_low(self.state.memory_base)
1591                    & cfg_space::MEMORY_BASE_LIMIT_ADDRESS_MASK;
1592                self.state.memory_limit = val.merge_high(self.state.memory_limit)
1593                    & cfg_space::MEMORY_BASE_LIMIT_ADDRESS_MASK;
1594            }
1595            HeaderType01::PREFETCH_RANGE => {
1596                self.state.prefetch_base = val.merge_low(self.state.prefetch_base)
1597                    & cfg_space::MEMORY_BASE_LIMIT_ADDRESS_MASK;
1598                self.state.prefetch_limit = val.merge_high(self.state.prefetch_limit)
1599                    & cfg_space::MEMORY_BASE_LIMIT_ADDRESS_MASK;
1600            }
1601            HeaderType01::PREFETCH_BASE_UPPER => {
1602                val.merge_into(&mut self.state.prefetch_base_upper);
1603            }
1604            HeaderType01::PREFETCH_LIMIT_UPPER => {
1605                val.merge_into(&mut self.state.prefetch_limit_upper);
1606            }
1607            HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1608                // Delegate interrupt line writes to common header and store bridge control
1609                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin (ignored), Bits 31-16: Bridge Control
1610                self.common
1611                    .set_interrupt_line(val.merge_low(self.common.interrupt_line() as u16) as u8);
1612                self.state.bridge_control = val.merge_high(self.state.bridge_control);
1613            }
1614            // all other base regs are noops
1615            _ if offset < COMMON_HEADER_END && offset.is_multiple_of(4) => (),
1616            _ => {
1617                tracelimit::warn_ratelimited!(offset, ?val, "unexpected config space write");
1618                return IoResult::Err(IoError::InvalidRegister);
1619            }
1620        }
1621
1622        IoResult::Ok
1623    }
1624
1625    /// Write a byte-enabled DWORD to the config space. `offset` must be 32-bit aligned.
1626    pub fn write_byte_enabled(&mut self, offset: u16, value: ByteEnabledDwordWrite) -> IoResult {
1627        if !offset.is_multiple_of(4) {
1628            return IoResult::Err(IoError::UnalignedAccess);
1629        }
1630
1631        let Some(addr) = PciConfigAddress::new(0, 0, offset / 4) else {
1632            return IoResult::Err(IoError::InvalidRegister);
1633        };
1634
1635        self.write(addr, value)
1636    }
1637
1638    /// Checks if this device is a PCIe device by looking for the PCI Express capability.
1639    pub fn is_pcie_device(&self) -> bool {
1640        self.common.is_pcie_device()
1641    }
1642
1643    /// Set the presence detect state for the slot.
1644    /// This method finds the PCIe Express capability and calls its set_presence_detect_state method.
1645    /// If the PCIe Express capability is not found, the call is silently ignored.
1646    ///
1647    /// # Arguments
1648    /// * `present` - true if a device is present in the slot, false if the slot is empty
1649    pub fn set_presence_detect_state(&mut self, present: bool) {
1650        // Find the PCIe Express capability
1651        for cap in self.common.capabilities_mut() {
1652            if cap.capability_id() == CapabilityId::PCI_EXPRESS {
1653                // Downcast to PciExpressCapability and call set_presence_detect_state
1654                if let Some(pcie_cap) = cap.as_pci_express_mut() {
1655                    pcie_cap.set_presence_detect_state(present);
1656                    return;
1657                }
1658            }
1659        }
1660        // If no PCIe Express capability is found, silently ignore the call
1661    }
1662
1663    /// Get the list of PCI capabilities.
1664    pub fn capabilities(&self) -> &[Box<dyn PciCapability>] {
1665        self.common.capabilities()
1666    }
1667
1668    /// Get the list of PCI capabilities (mutable).
1669    pub fn capabilities_mut(&mut self) -> &mut [Box<dyn PciCapability>] {
1670        self.common.capabilities_mut()
1671    }
1672
1673    /// Finds a BAR + offset by address.
1674    pub fn find_bar(&self, address: u64) -> Option<(u8, u64)> {
1675        self.common.find_bar(address)
1676    }
1677
1678    /// Gets the active base address for a specific BAR index, if mapped.
1679    pub fn bar_address(&self, bar: u8) -> Option<u64> {
1680        self.common.bar_address(bar)
1681    }
1682}
1683
1684mod save_restore {
1685    use super::*;
1686    use thiserror::Error;
1687    use vmcore::save_restore::RestoreError;
1688    use vmcore::save_restore::SaveError;
1689    use vmcore::save_restore::SaveRestore;
1690
1691    mod state {
1692        use mesh::payload::Protobuf;
1693        use vmcore::save_restore::SavedStateBlob;
1694        use vmcore::save_restore::SavedStateRoot;
1695
1696        /// Unified saved state for both Type 0 and Type 1 PCI configuration space emulators.
1697        /// Type 1 specific fields (mesh indices 6-15) will be ignored when restoring Type 0 devices,
1698        /// and will have default values (0) when restoring old save state to Type 1 devices.
1699        #[derive(Protobuf, SavedStateRoot)]
1700        #[mesh(package = "pci.cfg_space_emu")]
1701        pub struct SavedState {
1702            // Common fields (used by both Type 0 and Type 1)
1703            #[mesh(1)]
1704            pub command: u16,
1705            #[mesh(2)]
1706            pub base_addresses: [u32; 6],
1707            #[mesh(3)]
1708            pub interrupt_line: u8,
1709            #[mesh(4)]
1710            pub latency_timer: u8,
1711            #[mesh(5)]
1712            pub capabilities: Vec<(String, SavedStateBlob)>,
1713            #[mesh(16)]
1714            pub extended_capabilities: Vec<(String, SavedStateBlob)>,
1715            #[mesh(17)]
1716            pub captured_bus_number: u8,
1717            #[mesh(18)]
1718            pub captured_devfn: u8,
1719
1720            // Type 1 specific fields (bridge devices)
1721            // These fields default to 0 for backward compatibility with old save state
1722            #[mesh(6)]
1723            pub subordinate_bus_number: u8,
1724            #[mesh(7)]
1725            pub secondary_bus_number: u8,
1726            #[mesh(8)]
1727            pub primary_bus_number: u8,
1728            #[mesh(9)]
1729            pub memory_base: u16,
1730            #[mesh(10)]
1731            pub memory_limit: u16,
1732            #[mesh(11)]
1733            pub prefetch_base: u16,
1734            #[mesh(12)]
1735            pub prefetch_limit: u16,
1736            #[mesh(13)]
1737            pub prefetch_base_upper: u32,
1738            #[mesh(14)]
1739            pub prefetch_limit_upper: u32,
1740            #[mesh(15)]
1741            pub bridge_control: u16,
1742        }
1743    }
1744
1745    #[derive(Debug, Error)]
1746    enum ConfigSpaceRestoreError {
1747        #[error("found invalid config bits in saved state")]
1748        InvalidConfigBits,
1749        #[error("found unexpected capability {0}")]
1750        InvalidCap(String),
1751    }
1752
1753    impl SaveRestore for ConfigSpaceType0Emulator {
1754        type SavedState = state::SavedState;
1755
1756        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1757            let ConfigSpaceType0EmulatorState { latency_timer } = self.state;
1758
1759            let saved_state = state::SavedState {
1760                command: self.common.command().into_bits(),
1761                base_addresses: *self.common.base_addresses(),
1762                interrupt_line: self.common.interrupt_line(),
1763                latency_timer,
1764                capabilities: self
1765                    .common
1766                    .capabilities_mut()
1767                    .iter_mut()
1768                    .map(|cap| {
1769                        let id = cap.label().to_owned();
1770                        Ok((id, cap.save()?))
1771                    })
1772                    .collect::<Result<_, _>>()?,
1773                extended_capabilities: self
1774                    .common
1775                    .extended_capabilities
1776                    .iter_mut()
1777                    .map(|cap| {
1778                        let id = cap.label().to_owned();
1779                        Ok((id, cap.save()?))
1780                    })
1781                    .collect::<Result<_, _>>()?,
1782                captured_bus_number: self.common.captured_bus_number(),
1783                captured_devfn: self.common.captured_devfn(),
1784                // Type 1 specific fields - not used for Type 0
1785                subordinate_bus_number: 0,
1786                secondary_bus_number: 0,
1787                primary_bus_number: 0,
1788                memory_base: 0,
1789                memory_limit: 0,
1790                prefetch_base: 0,
1791                prefetch_limit: 0,
1792                prefetch_base_upper: 0,
1793                prefetch_limit_upper: 0,
1794                bridge_control: 0,
1795            };
1796
1797            Ok(saved_state)
1798        }
1799
1800        fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1801            let state::SavedState {
1802                command,
1803                base_addresses,
1804                interrupt_line,
1805                latency_timer,
1806                capabilities,
1807                extended_capabilities,
1808                captured_bus_number,
1809                captured_devfn,
1810                // Type 1 specific fields - ignored for Type 0
1811                subordinate_bus_number: _,
1812                secondary_bus_number: _,
1813                primary_bus_number: _,
1814                memory_base: _,
1815                memory_limit: _,
1816                prefetch_base: _,
1817                prefetch_limit: _,
1818                prefetch_base_upper: _,
1819                prefetch_limit_upper: _,
1820                bridge_control: _,
1821            } = state;
1822
1823            self.state = ConfigSpaceType0EmulatorState { latency_timer };
1824
1825            self.common.set_base_addresses(&base_addresses);
1826            self.common.set_interrupt_line(interrupt_line);
1827            self.common
1828                .set_command(cfg_space::Command::from_bits(command));
1829
1830            if command & !SUPPORTED_COMMAND_BITS != 0 {
1831                return Err(RestoreError::InvalidSavedState(
1832                    ConfigSpaceRestoreError::InvalidConfigBits.into(),
1833                ));
1834            }
1835
1836            self.common.sync_command_register(self.common.command());
1837
1838            for (id, entry) in capabilities {
1839                tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1840
1841                // yes, yes, this is O(n^2), but devices never have more than a
1842                // handful of caps, so it's totally fine.
1843                let mut restored = false;
1844                for cap in self.common.capabilities_mut() {
1845                    if cap.label() == id {
1846                        cap.restore(entry)?;
1847                        restored = true;
1848                        break;
1849                    }
1850                }
1851
1852                if !restored {
1853                    return Err(RestoreError::InvalidSavedState(
1854                        ConfigSpaceRestoreError::InvalidCap(id).into(),
1855                    ));
1856                }
1857            }
1858
1859            for (id, entry) in extended_capabilities {
1860                tracing::debug!(save_id = id.as_str(), "restoring pci extended capability");
1861
1862                let mut restored = false;
1863                for cap in &mut self.common.extended_capabilities {
1864                    if cap.label() == id {
1865                        cap.restore(entry)?;
1866                        restored = true;
1867                        break;
1868                    }
1869                }
1870
1871                if !restored {
1872                    return Err(RestoreError::InvalidSavedState(
1873                        ConfigSpaceRestoreError::InvalidCap(id).into(),
1874                    ));
1875                }
1876            }
1877
1878            self.common.set_captured_bus_number(captured_bus_number);
1879            self.common.set_captured_devfn(captured_devfn);
1880
1881            Ok(())
1882        }
1883    }
1884
1885    impl SaveRestore for ConfigSpaceType1Emulator {
1886        type SavedState = state::SavedState;
1887
1888        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1889            let ConfigSpaceType1EmulatorState {
1890                subordinate_bus_number,
1891                secondary_bus_number,
1892                primary_bus_number,
1893                memory_base,
1894                memory_limit,
1895                prefetch_base,
1896                prefetch_limit,
1897                prefetch_base_upper,
1898                prefetch_limit_upper,
1899                bridge_control,
1900            } = self.state;
1901
1902            // Pad base_addresses to 6 elements for saved state (Type 1 uses 2 BARs)
1903            let type1_base_addresses = self.common.base_addresses();
1904            let mut saved_base_addresses = [0u32; 6];
1905            saved_base_addresses[0] = type1_base_addresses[0];
1906            saved_base_addresses[1] = type1_base_addresses[1];
1907
1908            let saved_state = state::SavedState {
1909                command: self.common.command().into_bits(),
1910                base_addresses: saved_base_addresses,
1911                interrupt_line: self.common.interrupt_line(),
1912                latency_timer: 0, // Not used for Type 1
1913                capabilities: self
1914                    .common
1915                    .capabilities_mut()
1916                    .iter_mut()
1917                    .map(|cap| {
1918                        let id = cap.label().to_owned();
1919                        Ok((id, cap.save()?))
1920                    })
1921                    .collect::<Result<_, _>>()?,
1922                extended_capabilities: self
1923                    .common
1924                    .extended_capabilities
1925                    .iter_mut()
1926                    .map(|cap| {
1927                        let id = cap.label().to_owned();
1928                        Ok((id, cap.save()?))
1929                    })
1930                    .collect::<Result<_, _>>()?,
1931                captured_bus_number: self.common.captured_bus_number(),
1932                captured_devfn: self.common.captured_devfn(),
1933                // Type 1 specific fields
1934                subordinate_bus_number,
1935                secondary_bus_number,
1936                primary_bus_number,
1937                memory_base,
1938                memory_limit,
1939                prefetch_base,
1940                prefetch_limit,
1941                prefetch_base_upper,
1942                prefetch_limit_upper,
1943                bridge_control,
1944            };
1945
1946            Ok(saved_state)
1947        }
1948
1949        fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1950            let state::SavedState {
1951                command,
1952                base_addresses,
1953                interrupt_line,
1954                latency_timer: _, // Not used for Type 1
1955                capabilities,
1956                extended_capabilities,
1957                captured_bus_number,
1958                captured_devfn,
1959                subordinate_bus_number,
1960                secondary_bus_number,
1961                primary_bus_number,
1962                memory_base,
1963                memory_limit,
1964                prefetch_base,
1965                prefetch_limit,
1966                prefetch_base_upper,
1967                prefetch_limit_upper,
1968                bridge_control,
1969            } = state;
1970
1971            self.state = ConfigSpaceType1EmulatorState {
1972                subordinate_bus_number,
1973                secondary_bus_number,
1974                primary_bus_number,
1975                memory_base: memory_base & cfg_space::MEMORY_BASE_LIMIT_ADDRESS_MASK,
1976                memory_limit: memory_limit & cfg_space::MEMORY_BASE_LIMIT_ADDRESS_MASK,
1977                prefetch_base: prefetch_base & cfg_space::MEMORY_BASE_LIMIT_ADDRESS_MASK,
1978                prefetch_limit: prefetch_limit & cfg_space::MEMORY_BASE_LIMIT_ADDRESS_MASK,
1979                prefetch_base_upper,
1980                prefetch_limit_upper,
1981                bridge_control,
1982            };
1983
1984            self.sync_bus_range();
1985
1986            // Pad base_addresses to 6 elements for common header (Type 1 uses 2 BARs)
1987            let mut full_base_addresses = [0u32; 6];
1988            for (i, &addr) in base_addresses.iter().enumerate().take(2) {
1989                full_base_addresses[i] = addr;
1990            }
1991            self.common
1992                .set_base_addresses(&[full_base_addresses[0], full_base_addresses[1]]);
1993            self.common.set_interrupt_line(interrupt_line);
1994            self.common
1995                .set_command(cfg_space::Command::from_bits(command));
1996
1997            if command & !SUPPORTED_COMMAND_BITS != 0 {
1998                return Err(RestoreError::InvalidSavedState(
1999                    ConfigSpaceRestoreError::InvalidConfigBits.into(),
2000                ));
2001            }
2002
2003            self.common.sync_command_register(self.common.command());
2004
2005            for (id, entry) in capabilities {
2006                tracing::debug!(save_id = id.as_str(), "restoring pci capability");
2007
2008                let mut restored = false;
2009                for cap in self.common.capabilities_mut() {
2010                    if cap.label() == id {
2011                        cap.restore(entry)?;
2012                        restored = true;
2013                        break;
2014                    }
2015                }
2016
2017                if !restored {
2018                    return Err(RestoreError::InvalidSavedState(
2019                        ConfigSpaceRestoreError::InvalidCap(id).into(),
2020                    ));
2021                }
2022            }
2023
2024            for (id, entry) in extended_capabilities {
2025                tracing::debug!(save_id = id.as_str(), "restoring pci extended capability");
2026
2027                let mut restored = false;
2028                for cap in &mut self.common.extended_capabilities {
2029                    if cap.label() == id {
2030                        cap.restore(entry)?;
2031                        restored = true;
2032                        break;
2033                    }
2034                }
2035
2036                if !restored {
2037                    return Err(RestoreError::InvalidSavedState(
2038                        ConfigSpaceRestoreError::InvalidCap(id).into(),
2039                    ));
2040                }
2041            }
2042
2043            self.common.set_captured_bus_number(captured_bus_number);
2044            self.common.set_captured_devfn(captured_devfn);
2045
2046            Ok(())
2047        }
2048    }
2049}
2050
2051#[cfg(test)]
2052mod tests {
2053    use super::*;
2054    use crate::capabilities::extended::acs::AcsExtendedCapability;
2055    use crate::capabilities::pci_express::PciExpressCapability;
2056    use crate::capabilities::read_only::ReadOnlyCapability;
2057    use crate::spec::caps::pci_express::DevicePortType;
2058    use crate::spec::hwid::ClassCode;
2059    use crate::spec::hwid::ProgrammingInterface;
2060    use crate::spec::hwid::Subclass;
2061    use crate::test_helpers::TestCfgAccess;
2062    use chipset_device::pci::ByteEnabledDwordRead;
2063    use chipset_device::pci::ByteEnabledDwordWrite;
2064    use chipset_device::pci::PciConfigByteEnable;
2065    use std::sync::Arc;
2066    use std::sync::atomic::AtomicBool;
2067    use std::sync::atomic::Ordering;
2068    use vmcore::save_restore::SaveRestore;
2069
2070    fn create_type0_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType0Emulator {
2071        ConfigSpaceType0Emulator::new(
2072            HardwareIds {
2073                vendor_id: 0x1111,
2074                device_id: 0x2222,
2075                revision_id: 1,
2076                prog_if: ProgrammingInterface::NONE,
2077                sub_class: Subclass::NONE,
2078                base_class: ClassCode::UNCLASSIFIED,
2079                type0_sub_vendor_id: 0x3333,
2080                type0_sub_system_id: 0x4444,
2081            },
2082            caps,
2083            vec![],
2084            DeviceBars::new(),
2085        )
2086    }
2087
2088    fn create_type1_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType1Emulator {
2089        ConfigSpaceType1Emulator::new(
2090            HardwareIds {
2091                vendor_id: 0x1111,
2092                device_id: 0x2222,
2093                revision_id: 1,
2094                prog_if: ProgrammingInterface::NONE,
2095                sub_class: Subclass::BRIDGE_PCI_TO_PCI,
2096                base_class: ClassCode::BRIDGE,
2097                type0_sub_vendor_id: 0,
2098                type0_sub_system_id: 0,
2099            },
2100            caps,
2101            vec![],
2102        )
2103    }
2104
2105    #[test]
2106    fn test_type1_probe() {
2107        let emu = create_type1_emulator(vec![]);
2108        assert_eq!(emu.read_u32(0), 0x2222_1111);
2109        assert_eq!(emu.read_u32(4) & 0x10_0000, 0); // Capabilities pointer
2110
2111        let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
2112        assert_eq!(emu.read_u32(0), 0x2222_1111);
2113        assert_eq!(emu.read_u32(4) & 0x10_0000, 0x10_0000); // Capabilities pointer
2114    }
2115
2116    #[test]
2117    fn test_type1_bus_number_assignment() {
2118        let mut emu = create_type1_emulator(vec![]);
2119
2120        // The bus number (and latency timer) registers are
2121        // all default 0.
2122        assert_eq!(emu.read_u32(0x18), 0);
2123        assert_eq!(emu.assigned_bus_range(), 0..=0);
2124
2125        // The bus numbers can be programmed one by one,
2126        // and the range may not be valid during the middle
2127        // of allocation.
2128        emu.write_u32(0x18, 0x0000_1000);
2129        assert_eq!(emu.read_u32(0x18), 0x0000_1000);
2130        assert_eq!(emu.assigned_bus_range(), 0..=0);
2131        emu.write_u32(0x18, 0x0012_1000);
2132        assert_eq!(emu.read_u32(0x18), 0x0012_1000);
2133        assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
2134
2135        // The primary bus number register is read/write for compatability
2136        // but unused.
2137        emu.write_u32(0x18, 0x0012_1033);
2138        assert_eq!(emu.read_u32(0x18), 0x0012_1033);
2139        assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
2140
2141        // Software can also just write the entire 4byte value at once
2142        emu.write_u32(0x18, 0x0047_4411);
2143        assert_eq!(emu.read_u32(0x18), 0x0047_4411);
2144        assert_eq!(emu.assigned_bus_range(), 0x44..=0x47);
2145
2146        // The subordinate bus number can equal the secondary bus number...
2147        emu.write_u32(0x18, 0x0088_8800);
2148        assert_eq!(emu.assigned_bus_range(), 0x88..=0x88);
2149
2150        // ... but it cannot be less, that's a confused guest OS.
2151        emu.write_u32(0x18, 0x0087_8800);
2152        assert_eq!(emu.assigned_bus_range(), 0..=0);
2153    }
2154
2155    #[test]
2156    fn test_type1_bus_number_byte_writes() {
2157        let mut emu = create_type1_emulator(vec![]);
2158
2159        emu.write(
2160            PciConfigAddress::new(0, 0, 0x18 / 4).unwrap(),
2161            ByteEnabledDwordWrite::new(
2162                0x0000_0011,
2163                PciConfigByteEnable::from_offset_len(0x18, 1).unwrap(),
2164            ),
2165        )
2166        .unwrap();
2167        assert_eq!(emu.read_u32(0x18), 0x0000_0011);
2168        assert_eq!(emu.assigned_bus_range(), 0..=0);
2169
2170        emu.write(
2171            PciConfigAddress::new(0, 0, 0x18 / 4).unwrap(),
2172            ByteEnabledDwordWrite::new(
2173                0x0000_2200,
2174                PciConfigByteEnable::from_offset_len(0x19, 1).unwrap(),
2175            ),
2176        )
2177        .unwrap();
2178        assert_eq!(emu.read_u32(0x18), 0x0000_2211);
2179        assert_eq!(emu.assigned_bus_range(), 0..=0);
2180
2181        emu.write(
2182            PciConfigAddress::new(0, 0, 0x18 / 4).unwrap(),
2183            ByteEnabledDwordWrite::new(
2184                0x0033_0000,
2185                PciConfigByteEnable::from_offset_len(0x1a, 1).unwrap(),
2186            ),
2187        )
2188        .unwrap();
2189        assert_eq!(emu.read_u32(0x18), 0x0033_2211);
2190        assert_eq!(emu.assigned_bus_range(), 0x22..=0x33);
2191
2192        emu.write(
2193            PciConfigAddress::new(0, 0, 0x18 / 4).unwrap(),
2194            ByteEnabledDwordWrite::new(
2195                0xff00_0000,
2196                PciConfigByteEnable::from_offset_len(0x1b, 1).unwrap(),
2197            ),
2198        )
2199        .unwrap();
2200        assert_eq!(emu.read_u32(0x18), 0x0033_2211);
2201        assert_eq!(emu.assigned_bus_range(), 0x22..=0x33);
2202    }
2203
2204    #[test]
2205    fn test_type1_memory_assignment() {
2206        const MMIO_ENABLED: u32 = 0x0000_0002;
2207        const MMIO_DISABLED: u32 = 0x0000_0000;
2208
2209        let mut emu = create_type1_emulator(vec![]);
2210        assert!(emu.assigned_memory_range().is_none());
2211
2212        // The guest can write whatever it wants while MMIO
2213        // is disabled.
2214        emu.write_u32(0x20, 0xDEAD_BEEF);
2215        assert!(emu.assigned_memory_range().is_none());
2216
2217        // The guest can program a valid resource assignment...
2218        emu.write_u32(0x20, 0xFFF0_FF00);
2219        assert!(emu.assigned_memory_range().is_none());
2220        // ... enable memory decoding...
2221        emu.write_u32(0x4, MMIO_ENABLED);
2222        assert_eq!(emu.assigned_memory_range(), Some(0xFF00_0000..=0xFFFF_FFFF));
2223        // ... then disable memory decoding it.
2224        emu.write_u32(0x4, MMIO_DISABLED);
2225        assert!(emu.assigned_memory_range().is_none());
2226
2227        // Setting memory base equal to memory limit is a valid 1MB range.
2228        emu.write_u32(0x20, 0xBBB0_BBB0);
2229        emu.write_u32(0x4, MMIO_ENABLED);
2230        assert_eq!(emu.assigned_memory_range(), Some(0xBBB0_0000..=0xBBBF_FFFF));
2231        emu.write_u32(0x4, MMIO_DISABLED);
2232        assert!(emu.assigned_memory_range().is_none());
2233
2234        // The guest can try to program an invalid assignment (base > limit), we
2235        // just won't decode it.
2236        emu.write_u32(0x20, 0xAA00_BB00);
2237        assert!(emu.assigned_memory_range().is_none());
2238        emu.write_u32(0x4, MMIO_ENABLED);
2239        assert!(emu.assigned_memory_range().is_none());
2240        emu.write_u32(0x4, MMIO_DISABLED);
2241        assert!(emu.assigned_memory_range().is_none());
2242    }
2243
2244    #[test]
2245    fn test_type1_memory_range_register_masks_reserved_bits() {
2246        const MMIO_ENABLED: u32 = 0x0000_0002;
2247
2248        let mut emu = create_type1_emulator(vec![]);
2249
2250        emu.write_u32(0x20, 0x567f_123f);
2251        assert_eq!(emu.read_u32(0x20), 0x5670_1230);
2252
2253        emu.write_u32(0x4, MMIO_ENABLED);
2254        assert_eq!(emu.assigned_memory_range(), Some(0x1230_0000..=0x567f_ffff));
2255    }
2256
2257    #[test]
2258    fn test_type1_prefetch_assignment() {
2259        const MMIO_ENABLED: u32 = 0x0000_0002;
2260        const MMIO_DISABLED: u32 = 0x0000_0000;
2261
2262        let mut emu = create_type1_emulator(vec![]);
2263        assert!(emu.assigned_prefetch_range().is_none());
2264
2265        // The guest can program a valid prefetch range...
2266        emu.write_u32(0x24, 0xFFF0_FF00); // limit + base
2267        emu.write_u32(0x28, 0x00AA_BBCC); // base upper
2268        emu.write_u32(0x2C, 0x00DD_EEFF); // limit upper
2269        assert!(emu.assigned_prefetch_range().is_none());
2270        // ... enable memory decoding...
2271        emu.write_u32(0x4, MMIO_ENABLED);
2272        assert_eq!(
2273            emu.assigned_prefetch_range(),
2274            Some(0x00AA_BBCC_FF00_0000..=0x00DD_EEFF_FFFF_FFFF)
2275        );
2276        // ... then disable memory decoding it.
2277        emu.write_u32(0x4, MMIO_DISABLED);
2278        assert!(emu.assigned_prefetch_range().is_none());
2279
2280        // The validity of the assignment is determined using the combined 64-bit
2281        // address, not the lower bits or the upper bits in isolation.
2282
2283        // Lower bits of the limit are greater than the lower bits of the
2284        // base, but the upper bits make that valid.
2285        emu.write_u32(0x24, 0xFF00_FFF0); // limit + base
2286        emu.write_u32(0x28, 0x00AA_BBCC); // base upper
2287        emu.write_u32(0x2C, 0x00DD_EEFF); // limit upper
2288        assert!(emu.assigned_prefetch_range().is_none());
2289        emu.write_u32(0x4, MMIO_ENABLED);
2290        assert_eq!(
2291            emu.assigned_prefetch_range(),
2292            Some(0x00AA_BBCC_FFF0_0000..=0x00DD_EEFF_FF0F_FFFF)
2293        );
2294        emu.write_u32(0x4, MMIO_DISABLED);
2295        assert!(emu.assigned_prefetch_range().is_none());
2296
2297        // The base can equal the limit, which is a valid 1MB range.
2298        emu.write_u32(0x24, 0xDD00_DD00); // limit + base
2299        emu.write_u32(0x28, 0x00AA_BBCC); // base upper
2300        emu.write_u32(0x2C, 0x00AA_BBCC); // limit upper
2301        assert!(emu.assigned_prefetch_range().is_none());
2302        emu.write_u32(0x4, MMIO_ENABLED);
2303        assert_eq!(
2304            emu.assigned_prefetch_range(),
2305            Some(0x00AA_BBCC_DD00_0000..=0x00AA_BBCC_DD0F_FFFF)
2306        );
2307        emu.write_u32(0x4, MMIO_DISABLED);
2308        assert!(emu.assigned_prefetch_range().is_none());
2309    }
2310
2311    #[test]
2312    fn test_type1_prefetch_range_register_masks_reserved_bits_and_reports_64_bit() {
2313        const MMIO_ENABLED: u32 = 0x0000_0002;
2314
2315        let mut emu = create_type1_emulator(vec![]);
2316
2317        emu.write_u32(0x24, 0x567e_123e);
2318        assert_eq!(emu.read_u32(0x24), 0x5671_1231);
2319
2320        emu.write_u32(0x4, MMIO_ENABLED);
2321        assert_eq!(
2322            emu.assigned_prefetch_range(),
2323            Some(0x1230_0000..=0x567f_ffff)
2324        );
2325    }
2326
2327    #[test]
2328    fn test_type1_restore_masks_bridge_memory_range_reserved_bits() {
2329        const MMIO_ENABLED: u32 = 0x0000_0002;
2330
2331        let mut source = create_type1_emulator(vec![]);
2332        source.write_u32(0x4, MMIO_ENABLED);
2333        source.state.memory_base = 0x123f;
2334        source.state.memory_limit = 0x567f;
2335        source.state.prefetch_base = 0x234e;
2336        source.state.prefetch_limit = 0x678e;
2337
2338        let saved_state = source.save().expect("save should succeed");
2339
2340        let mut emu = create_type1_emulator(vec![]);
2341        emu.restore(saved_state).expect("restore should succeed");
2342
2343        assert_eq!(emu.read_u32(0x20), 0x5670_1230);
2344        assert_eq!(emu.read_u32(0x24), 0x6781_2341);
2345        assert_eq!(emu.assigned_memory_range(), Some(0x1230_0000..=0x567f_ffff));
2346        assert_eq!(
2347            emu.assigned_prefetch_range(),
2348            Some(0x2340_0000..=0x678f_ffff)
2349        );
2350    }
2351
2352    #[test]
2353    fn test_type1_is_pcie_device() {
2354        // Test Type 1 device without PCIe capability
2355        let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
2356        assert!(!emu.is_pcie_device());
2357
2358        // Test Type 1 device with PCIe capability
2359        let emu = create_type1_emulator(vec![Box::new(PciExpressCapability::new(
2360            DevicePortType::RootPort,
2361            None,
2362        ))]);
2363        assert!(emu.is_pcie_device());
2364
2365        // Test Type 1 device with multiple capabilities including PCIe
2366        let emu = create_type1_emulator(vec![
2367            Box::new(ReadOnlyCapability::new("foo", 0)),
2368            Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
2369            Box::new(ReadOnlyCapability::new("bar", 0)),
2370        ]);
2371        assert!(emu.is_pcie_device());
2372    }
2373
2374    #[test]
2375    fn test_type0_is_pcie_device() {
2376        // Test Type 0 device without PCIe capability
2377        let emu = ConfigSpaceType0Emulator::new(
2378            HardwareIds {
2379                vendor_id: 0x1111,
2380                device_id: 0x2222,
2381                revision_id: 1,
2382                prog_if: ProgrammingInterface::NONE,
2383                sub_class: Subclass::NONE,
2384                base_class: ClassCode::UNCLASSIFIED,
2385                type0_sub_vendor_id: 0,
2386                type0_sub_system_id: 0,
2387            },
2388            vec![Box::new(ReadOnlyCapability::new("foo", 0))],
2389            vec![],
2390            DeviceBars::new(),
2391        );
2392        assert!(!emu.is_pcie_device());
2393
2394        // Test Type 0 device with PCIe capability
2395        let emu = ConfigSpaceType0Emulator::new(
2396            HardwareIds {
2397                vendor_id: 0x1111,
2398                device_id: 0x2222,
2399                revision_id: 1,
2400                prog_if: ProgrammingInterface::NONE,
2401                sub_class: Subclass::NONE,
2402                base_class: ClassCode::UNCLASSIFIED,
2403                type0_sub_vendor_id: 0,
2404                type0_sub_system_id: 0,
2405            },
2406            vec![Box::new(PciExpressCapability::new(
2407                DevicePortType::Endpoint,
2408                None,
2409            ))],
2410            vec![],
2411            DeviceBars::new(),
2412        );
2413        assert!(emu.is_pcie_device());
2414
2415        // Test Type 0 device with multiple capabilities including PCIe
2416        let emu = ConfigSpaceType0Emulator::new(
2417            HardwareIds {
2418                vendor_id: 0x1111,
2419                device_id: 0x2222,
2420                revision_id: 1,
2421                prog_if: ProgrammingInterface::NONE,
2422                sub_class: Subclass::NONE,
2423                base_class: ClassCode::UNCLASSIFIED,
2424                type0_sub_vendor_id: 0,
2425                type0_sub_system_id: 0,
2426            },
2427            vec![
2428                Box::new(ReadOnlyCapability::new("foo", 0)),
2429                Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
2430                Box::new(ReadOnlyCapability::new("bar", 0)),
2431            ],
2432            vec![],
2433            DeviceBars::new(),
2434        );
2435        assert!(emu.is_pcie_device());
2436
2437        // Test Type 0 device with no capabilities
2438        let emu = ConfigSpaceType0Emulator::new(
2439            HardwareIds {
2440                vendor_id: 0x1111,
2441                device_id: 0x2222,
2442                revision_id: 1,
2443                prog_if: ProgrammingInterface::NONE,
2444                sub_class: Subclass::NONE,
2445                base_class: ClassCode::UNCLASSIFIED,
2446                type0_sub_vendor_id: 0,
2447                type0_sub_system_id: 0,
2448            },
2449            vec![],
2450            vec![],
2451            DeviceBars::new(),
2452        );
2453        assert!(!emu.is_pcie_device());
2454    }
2455
2456    #[test]
2457    fn test_capability_ids() {
2458        // Test that capabilities return the correct capability IDs
2459        let pcie_cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
2460        assert_eq!(pcie_cap.capability_id(), CapabilityId::PCI_EXPRESS);
2461
2462        let read_only_cap = ReadOnlyCapability::new("test", 0u32);
2463        assert_eq!(read_only_cap.capability_id(), CapabilityId::VENDOR_SPECIFIC);
2464    }
2465
2466    #[test]
2467    fn test_common_header_emulator_type0() {
2468        // Test the common header emulator with Type 0 configuration (6 BARs)
2469        let hardware_ids = HardwareIds {
2470            vendor_id: 0x1111,
2471            device_id: 0x2222,
2472            revision_id: 1,
2473            prog_if: ProgrammingInterface::NONE,
2474            sub_class: Subclass::NONE,
2475            base_class: ClassCode::UNCLASSIFIED,
2476            type0_sub_vendor_id: 0,
2477            type0_sub_system_id: 0,
2478        };
2479
2480        let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
2481
2482        let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
2483            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], vec![], bars);
2484
2485        assert_eq!(common_emu.hardware_ids().vendor_id, 0x1111);
2486        assert_eq!(common_emu.hardware_ids().device_id, 0x2222);
2487        assert!(!common_emu.multi_function_bit());
2488        assert!(!common_emu.is_pcie_device());
2489        assert_ne!(common_emu.bar_masks()[0], 0); // Should have a mask for BAR0
2490    }
2491
2492    #[test]
2493    fn test_common_header_emulator_type1() {
2494        // Test the common header emulator with Type 1 configuration (2 BARs)
2495        let hardware_ids = HardwareIds {
2496            vendor_id: 0x3333,
2497            device_id: 0x4444,
2498            revision_id: 1,
2499            prog_if: ProgrammingInterface::NONE,
2500            sub_class: Subclass::BRIDGE_PCI_TO_PCI,
2501            base_class: ClassCode::BRIDGE,
2502            type0_sub_vendor_id: 0,
2503            type0_sub_system_id: 0,
2504        };
2505
2506        let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
2507
2508        let mut common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
2509            ConfigSpaceCommonHeaderEmulator::new(
2510                hardware_ids,
2511                vec![Box::new(PciExpressCapability::new(
2512                    DevicePortType::RootPort,
2513                    None,
2514                ))],
2515                vec![],
2516                bars,
2517            )
2518            .with_multi_function_bit(true);
2519
2520        assert_eq!(common_emu.hardware_ids().vendor_id, 0x3333);
2521        assert_eq!(common_emu.hardware_ids().device_id, 0x4444);
2522        assert!(common_emu.multi_function_bit());
2523        assert!(common_emu.is_pcie_device());
2524        assert_ne!(common_emu.bar_masks()[0], 0); // Should have a mask for BAR0
2525        assert_eq!(common_emu.bar_masks().len(), 2);
2526
2527        // Test reset functionality
2528        common_emu.reset();
2529        assert_eq!(common_emu.capabilities().len(), 1); // capabilities should still be there
2530    }
2531
2532    #[test]
2533    fn test_common_header_emulator_no_bars() {
2534        // Test the common header emulator with no BARs configured
2535        let hardware_ids = HardwareIds {
2536            vendor_id: 0x5555,
2537            device_id: 0x6666,
2538            revision_id: 1,
2539            prog_if: ProgrammingInterface::NONE,
2540            sub_class: Subclass::NONE,
2541            base_class: ClassCode::UNCLASSIFIED,
2542            type0_sub_vendor_id: 0,
2543            type0_sub_system_id: 0,
2544        };
2545
2546        // Create bars with no BARs configured
2547        let bars = DeviceBars::new();
2548
2549        let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
2550            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], vec![], bars);
2551
2552        assert_eq!(common_emu.hardware_ids().vendor_id, 0x5555);
2553        assert_eq!(common_emu.hardware_ids().device_id, 0x6666);
2554
2555        // All BAR masks should be 0 when no BARs are configured
2556        for &mask in common_emu.bar_masks() {
2557            assert_eq!(mask, 0);
2558        }
2559    }
2560
2561    #[test]
2562    fn test_common_header_emulator_type1_ignores_extra_bars() {
2563        // Test that Type 1 emulator ignores BARs beyond index 1 (only supports 2 BARs)
2564        let hardware_ids = HardwareIds {
2565            vendor_id: 0x7777,
2566            device_id: 0x8888,
2567            revision_id: 1,
2568            prog_if: ProgrammingInterface::NONE,
2569            sub_class: Subclass::BRIDGE_PCI_TO_PCI,
2570            base_class: ClassCode::BRIDGE,
2571            type0_sub_vendor_id: 0,
2572            type0_sub_system_id: 0,
2573        };
2574
2575        // Configure BARs 0, 2, and 4 - Type 1 should only use BAR0 (and BAR1 as upper 32 bits)
2576        let bars = DeviceBars::new()
2577            .bar0(4096, BarMemoryKind::Dummy)
2578            .bar2(8192, BarMemoryKind::Dummy)
2579            .bar4(16384, BarMemoryKind::Dummy);
2580
2581        let common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
2582            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], vec![], bars);
2583
2584        assert_eq!(common_emu.hardware_ids().vendor_id, 0x7777);
2585        assert_eq!(common_emu.hardware_ids().device_id, 0x8888);
2586
2587        // Should have a mask for BAR0, and BAR1 should be the upper 32 bits (64-bit BAR)
2588        assert_ne!(common_emu.bar_masks()[0], 0); // BAR0 should be configured
2589        assert_ne!(common_emu.bar_masks()[1], 0); // BAR1 should be upper 32 bits of BAR0
2590        assert_eq!(common_emu.bar_masks().len(), 2); // Type 1 only has 2 BARs
2591
2592        // BAR2 and higher should be ignored (not accessible in Type 1 with N=2)
2593        // This demonstrates that extra BARs in DeviceBars are properly ignored
2594    }
2595
2596    #[test]
2597    fn test_common_header_extended_capabilities() {
2598        // Test common header emulator extended capabilities
2599        let mut common_emu_no_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2600            HardwareIds {
2601                vendor_id: 0x1111,
2602                device_id: 0x2222,
2603                revision_id: 1,
2604                prog_if: ProgrammingInterface::NONE,
2605                sub_class: Subclass::NONE,
2606                base_class: ClassCode::UNCLASSIFIED,
2607                type0_sub_vendor_id: 0,
2608                type0_sub_system_id: 0,
2609            },
2610            vec![Box::new(ReadOnlyCapability::new("foo", 0))],
2611            vec![],
2612            DeviceBars::new(),
2613        );
2614        assert!(!common_emu_no_pcie.is_pcie_device());
2615
2616        let mut common_emu_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2617            HardwareIds {
2618                vendor_id: 0x1111,
2619                device_id: 0x2222,
2620                revision_id: 1,
2621                prog_if: ProgrammingInterface::NONE,
2622                sub_class: Subclass::NONE,
2623                base_class: ClassCode::UNCLASSIFIED,
2624                type0_sub_vendor_id: 0,
2625                type0_sub_system_id: 0,
2626            },
2627            vec![Box::new(PciExpressCapability::new(
2628                DevicePortType::Endpoint,
2629                None,
2630            ))],
2631            vec![],
2632            DeviceBars::new(),
2633        );
2634        assert!(common_emu_pcie.is_pcie_device());
2635
2636        // A non-PCIe device has no extended configuration space, but the
2637        // function is present: in-range reads return 0 (no extended caps),
2638        // not all-ones.
2639        let mut value = 0xdead_beef;
2640        assert!(matches!(
2641            common_emu_no_pcie.read_extended_capabilities(
2642                EXT_CAP_START,
2643                ByteEnabledDwordRead::with_all_bytes_enabled(&mut value)
2644            ),
2645            CommonHeaderResult::Handled
2646        ));
2647        assert_eq!(value, 0);
2648
2649        // A PCIe device with no extended capabilities returns an all-zero
2650        // header, terminating the list.
2651        let mut value = 0xdead_beef;
2652        assert!(matches!(
2653            common_emu_pcie.read_extended_capabilities(
2654                EXT_CAP_START,
2655                ByteEnabledDwordRead::with_all_bytes_enabled(&mut value)
2656            ),
2657            CommonHeaderResult::Handled
2658        ));
2659        assert_eq!(value, 0);
2660
2661        // Writes to the (unimplemented) extended region on a non-PCIe device
2662        // are dropped silently rather than faulting.
2663        assert!(matches!(
2664            common_emu_no_pcie.write_extended_capabilities(
2665                EXT_CAP_START,
2666                ByteEnabledDwordWrite::with_all_bytes_enabled(0x1234)
2667            ),
2668            CommonHeaderResult::Handled
2669        ));
2670
2671        // Test writing extended capabilities - PCIe device should accept writes
2672        assert!(matches!(
2673            common_emu_pcie.write_extended_capabilities(
2674                EXT_CAP_START,
2675                ByteEnabledDwordWrite::with_all_bytes_enabled(0x1234)
2676            ),
2677            CommonHeaderResult::Handled
2678        ));
2679
2680        // Test invalid offset ranges
2681        let mut value = 0;
2682        assert!(matches!(
2683            common_emu_pcie.read_extended_capabilities(
2684                0x99,
2685                ByteEnabledDwordRead::with_all_bytes_enabled(&mut value)
2686            ),
2687            CommonHeaderResult::Failed(IoError::InvalidRegister)
2688        ));
2689        assert!(matches!(
2690            common_emu_pcie.read_extended_capabilities(
2691                EXT_CAP_END,
2692                ByteEnabledDwordRead::with_all_bytes_enabled(&mut value)
2693            ),
2694            CommonHeaderResult::Failed(IoError::InvalidRegister)
2695        ));
2696    }
2697
2698    #[test]
2699    fn test_unimplemented_capability_region_reads_zero() {
2700        // Unimplemented registers in the standard capability region of a
2701        // present function read as 0.
2702        let mut common_emu = ConfigSpaceCommonHeaderEmulatorType0::new(
2703            HardwareIds {
2704                vendor_id: 0x1111,
2705                device_id: 0x2222,
2706                revision_id: 1,
2707                prog_if: ProgrammingInterface::NONE,
2708                sub_class: Subclass::NONE,
2709                base_class: ClassCode::UNCLASSIFIED,
2710                type0_sub_vendor_id: 0,
2711                type0_sub_system_id: 0,
2712            },
2713            // A single small capability at the start of the region; everything
2714            // past it is unimplemented.
2715            vec![Box::new(ReadOnlyCapability::new("foo", 0))],
2716            vec![],
2717            DeviceBars::new(),
2718        );
2719
2720        // An offset well past the implemented capability reads as 0.
2721        let mut value = 0xdead_beef;
2722        assert!(matches!(
2723            common_emu.read_capabilities(
2724                0x90,
2725                ByteEnabledDwordRead::with_all_bytes_enabled(&mut value)
2726            ),
2727            CommonHeaderResult::Handled
2728        ));
2729        assert_eq!(value, 0);
2730
2731        // Writes to the unimplemented region are dropped silently.
2732        assert!(matches!(
2733            common_emu
2734                .write_capabilities(0x90, ByteEnabledDwordWrite::with_all_bytes_enabled(0x1234)),
2735            CommonHeaderResult::Handled
2736        ));
2737    }
2738
2739    #[test]
2740    fn test_type1_acs_extended_capability() {
2741        let mut common_emu_pcie = ConfigSpaceCommonHeaderEmulatorType1::new(
2742            HardwareIds {
2743                vendor_id: 0x1111,
2744                device_id: 0x2222,
2745                revision_id: 1,
2746                prog_if: ProgrammingInterface::NONE,
2747                sub_class: Subclass::BRIDGE_PCI_TO_PCI,
2748                base_class: ClassCode::BRIDGE,
2749                type0_sub_vendor_id: 0,
2750                type0_sub_system_id: 0,
2751            },
2752            vec![Box::new(PciExpressCapability::new(
2753                DevicePortType::RootPort,
2754                None,
2755            ))],
2756            vec![Box::new(AcsExtendedCapability::new())],
2757            DeviceBars::new(),
2758        );
2759
2760        let mut value = 0;
2761        assert!(matches!(
2762            common_emu_pcie.read_extended_capabilities(
2763                EXT_CAP_START,
2764                ByteEnabledDwordRead::with_all_bytes_enabled(&mut value)
2765            ),
2766            CommonHeaderResult::Handled
2767        ));
2768        assert_eq!(value, 0x0001_000d);
2769
2770        assert!(matches!(
2771            common_emu_pcie.read_extended_capabilities(
2772                0x104,
2773                ByteEnabledDwordRead::with_all_bytes_enabled(&mut value)
2774            ),
2775            CommonHeaderResult::Handled
2776        ));
2777        assert_eq!(value as u16, 0x005f);
2778        assert_eq!((value >> 16) as u16, 0x0000);
2779
2780        assert!(matches!(
2781            common_emu_pcie.write_extended_capabilities(
2782                0x104,
2783                ByteEnabledDwordWrite::with_all_bytes_enabled(0xffff_0000),
2784            ),
2785            CommonHeaderResult::Handled
2786        ));
2787        assert!(matches!(
2788            common_emu_pcie.read_extended_capabilities(
2789                0x104,
2790                ByteEnabledDwordRead::with_all_bytes_enabled(&mut value)
2791            ),
2792            CommonHeaderResult::Handled
2793        ));
2794        assert_eq!((value >> 16) as u16, 0x005f);
2795    }
2796
2797    #[test]
2798    fn test_type0_emulator_save_restore() {
2799        // Test Type 0 emulator save/restore
2800        let mut emu = create_type0_emulator(vec![]);
2801
2802        // Modify some state by writing to command register
2803        emu.write_u32(0x04, 0x0007); // Enable some command bits
2804
2805        // Read back and verify
2806        assert_eq!(emu.read_u32(0x04) & 0x0007, 0x0007);
2807
2808        // Write to latency timer / interrupt register
2809        emu.write_u32(0x3C, 0x0040_0000); // Set latency_timer
2810
2811        // Save the state
2812        let saved_state = emu.save().expect("save should succeed");
2813
2814        // Reset the emulator
2815        emu.reset();
2816
2817        // Verify state is reset
2818        assert_eq!(emu.read_u32(0x04) & 0x0007, 0x0000); // Should be reset
2819
2820        // Restore the state
2821        emu.restore(saved_state).expect("restore should succeed");
2822
2823        // Verify state is restored
2824        assert_eq!(emu.read_u32(0x04) & 0x0007, 0x0007); // Should be restored
2825    }
2826
2827    #[test]
2828    fn test_type1_emulator_save_restore() {
2829        // Test Type 1 emulator save/restore
2830        let mut emu = create_type1_emulator(vec![]);
2831
2832        // Modify some state
2833        emu.write_u32(0x04, 0x0003); // Enable command bits
2834        emu.write_u32(0x18, 0x0012_1000); // Set bus numbers
2835        emu.write_u32(0x20, 0xFFF0_FF00); // Set memory range
2836        emu.write_u32(0x24, 0xFFF0_FF00); // Set prefetch range
2837        emu.write_u32(0x28, 0x00AA_BBCC); // Set prefetch base upper
2838        emu.write_u32(0x2C, 0x00DD_EEFF); // Set prefetch limit upper
2839        emu.write_u32(0x3C, 0x0001_0000); // Set bridge control
2840
2841        // Verify values
2842        assert_eq!(emu.read_u32(0x04) & 0x0003, 0x0003);
2843        assert_eq!(emu.read_u32(0x18), 0x0012_1000);
2844        assert_eq!(emu.read_u32(0x20), 0xFFF0_FF00);
2845        assert_eq!(emu.read_u32(0x28), 0x00AA_BBCC);
2846        assert_eq!(emu.read_u32(0x2C), 0x00DD_EEFF);
2847        assert_eq!(emu.read_u32(0x3C) >> 16, 0x0001); // bridge_control
2848
2849        // Save the state
2850        let saved_state = emu.save().expect("save should succeed");
2851
2852        // Reset the emulator
2853        emu.reset();
2854
2855        // Verify state is reset
2856        let test_val = emu.read_u32(0x04);
2857        assert_eq!(test_val & 0x0003, 0x0000);
2858        let test_val = emu.read_u32(0x18);
2859        assert_eq!(test_val, 0x0000_0000);
2860
2861        // Restore the state
2862        emu.restore(saved_state).expect("restore should succeed");
2863
2864        // Verify state is restored
2865        assert_eq!(emu.read_u32(0x04) & 0x0003, 0x0003);
2866        assert_eq!(emu.read_u32(0x18), 0x0012_1000);
2867        assert_eq!(emu.read_u32(0x20), 0xFFF0_FF00);
2868        assert_eq!(emu.read_u32(0x28), 0x00AA_BBCC);
2869        assert_eq!(emu.read_u32(0x2C), 0x00DD_EEFF);
2870        assert_eq!(emu.read_u32(0x3C) >> 16, 0x0001); // bridge_control
2871    }
2872
2873    #[test]
2874    fn test_type1_emulator_save_restore_with_extended_capabilities() {
2875        let mut emu = ConfigSpaceType1Emulator::new(
2876            HardwareIds {
2877                vendor_id: 0x1111,
2878                device_id: 0x2222,
2879                revision_id: 1,
2880                prog_if: ProgrammingInterface::NONE,
2881                sub_class: Subclass::BRIDGE_PCI_TO_PCI,
2882                base_class: ClassCode::BRIDGE,
2883                type0_sub_vendor_id: 0,
2884                type0_sub_system_id: 0,
2885            },
2886            vec![Box::new(PciExpressCapability::new(
2887                DevicePortType::RootPort,
2888                None,
2889            ))],
2890            vec![Box::new(AcsExtendedCapability::new())],
2891        );
2892
2893        // Enable all supported ACS control bits.
2894        emu.write_u32(0x104, 0xffff_0000);
2895
2896        assert_eq!((emu.read_u32(0x104) >> 16) as u16, 0x005f);
2897
2898        let saved_state = emu.save().expect("save should succeed");
2899
2900        emu.reset();
2901        assert_eq!((emu.read_u32(0x104) >> 16) as u16, 0);
2902
2903        emu.restore(saved_state).expect("restore should succeed");
2904        assert_eq!((emu.read_u32(0x104) >> 16) as u16, 0x005f);
2905    }
2906
2907    #[test]
2908    fn test_config_space_type1_set_presence_detect_state() {
2909        // Test that ConfigSpaceType1Emulator can set presence detect state
2910        // when it has a PCIe Express capability with hotplug support
2911
2912        // Create a PCIe Express capability with hotplug support
2913        let pcie_cap =
2914            PciExpressCapability::new(DevicePortType::RootPort, None).with_hotplug_support(1);
2915
2916        let mut emulator = create_type1_emulator(vec![Box::new(pcie_cap)]);
2917
2918        // Initially, presence detect state should be 0
2919        let slot_status_val = emulator.read_u32(COMMON_HEADER_END + 0x18); // COMMON_HEADER_END (cap start) + 0x18 (slot control/status)
2920        let initial_presence_detect = (slot_status_val >> 22) & 0x1; // presence_detect_state is bit 6 of slot status
2921        assert_eq!(
2922            initial_presence_detect, 0,
2923            "Initial presence detect state should be 0"
2924        );
2925
2926        // Set device as present
2927        emulator.set_presence_detect_state(true);
2928        let slot_status_val = emulator.read_u32(0x58);
2929        let present_presence_detect = (slot_status_val >> 22) & 0x1;
2930        assert_eq!(
2931            present_presence_detect, 1,
2932            "Presence detect state should be 1 when device is present"
2933        );
2934
2935        // Set device as not present
2936        emulator.set_presence_detect_state(false);
2937        let slot_status_val = emulator.read_u32(0x58);
2938        let absent_presence_detect = (slot_status_val >> 22) & 0x1;
2939        assert_eq!(
2940            absent_presence_detect, 0,
2941            "Presence detect state should be 0 when device is not present"
2942        );
2943    }
2944
2945    #[test]
2946    fn test_config_space_type1_set_presence_detect_state_without_pcie() {
2947        // Test that ConfigSpaceType1Emulator silently ignores set_presence_detect_state
2948        // when there is no PCIe Express capability
2949
2950        let mut emulator = create_type1_emulator(vec![]); // No capabilities
2951
2952        // Should not panic and should be silently ignored
2953        emulator.set_presence_detect_state(true);
2954        emulator.set_presence_detect_state(false);
2955    }
2956
2957    #[test]
2958    fn test_interrupt_pin_register() {
2959        use vmcore::line_interrupt::LineInterrupt;
2960
2961        // Test Type 0 device with interrupt pin configured
2962        let mut emu = ConfigSpaceType0Emulator::new(
2963            HardwareIds {
2964                vendor_id: 0x1111,
2965                device_id: 0x2222,
2966                revision_id: 1,
2967                prog_if: ProgrammingInterface::NONE,
2968                sub_class: Subclass::NONE,
2969                base_class: ClassCode::UNCLASSIFIED,
2970                type0_sub_vendor_id: 0,
2971                type0_sub_system_id: 0,
2972            },
2973            vec![],
2974            vec![],
2975            DeviceBars::new(),
2976        );
2977
2978        // Initially, no interrupt pin should be configured
2979        assert_eq!(emu.read_u32(0x3C) & 0xFF00, 0); // Interrupt pin should be 0
2980
2981        // Configure interrupt pin A
2982        let line_interrupt = LineInterrupt::detached();
2983        emu.set_interrupt_pin(PciInterruptPin::IntA, line_interrupt);
2984
2985        // Read the register again
2986        assert_eq!((emu.read_u32(0x3C) >> 8) & 0xFF, 1); // Interrupt pin should be 1 (INTA)
2987
2988        // Set interrupt line to 0x42 and verify both pin and line are correct
2989        emu.write_u32(0x3C, 0x00110042); // Latency=0x11, pin=ignored, line=0x42
2990        let val = emu.read_u32(0x3C);
2991        assert_eq!(val & 0xFF, 0x42); // Interrupt line should be 0x42
2992        assert_eq!((val >> 8) & 0xFF, 1); // Interrupt pin should still be 1 (writes ignored)
2993        assert_eq!((val >> 16) & 0xFF, 0x11); // Latency timer should be 0x11
2994
2995        // Test with interrupt pin D
2996        let mut emu_d = ConfigSpaceType0Emulator::new(
2997            HardwareIds {
2998                vendor_id: 0x1111,
2999                device_id: 0x2222,
3000                revision_id: 1,
3001                prog_if: ProgrammingInterface::NONE,
3002                sub_class: Subclass::NONE,
3003                base_class: ClassCode::UNCLASSIFIED,
3004                type0_sub_vendor_id: 0,
3005                type0_sub_system_id: 0,
3006            },
3007            vec![],
3008            vec![],
3009            DeviceBars::new(),
3010        );
3011
3012        let line_interrupt_d = LineInterrupt::detached();
3013        emu_d.set_interrupt_pin(PciInterruptPin::IntD, line_interrupt_d);
3014
3015        assert_eq!((emu_d.read_u32(0x3C) >> 8) & 0xFF, 4); // Interrupt pin should be 4 (INTD)
3016    }
3017
3018    #[test]
3019    fn test_header_type_functionality() {
3020        // Test HeaderType enum values
3021        assert_eq!(HeaderType::Type0.bar_count(), 6);
3022        assert_eq!(HeaderType::Type1.bar_count(), 2);
3023        assert_eq!(usize::from(HeaderType::Type0), 6);
3024        assert_eq!(usize::from(HeaderType::Type1), 2);
3025
3026        // Test constant values
3027        assert_eq!(header_type_consts::TYPE0_BAR_COUNT, 6);
3028        assert_eq!(header_type_consts::TYPE1_BAR_COUNT, 2);
3029
3030        // Test Type 0 emulator
3031        let emu_type0 = create_type0_emulator(vec![]);
3032        assert_eq!(emu_type0.common.bar_count(), 6);
3033        assert_eq!(emu_type0.common.header_type(), HeaderType::Type0);
3034        assert!(emu_type0.common.validate_header_type(HeaderType::Type0));
3035        assert!(!emu_type0.common.validate_header_type(HeaderType::Type1));
3036
3037        // Test Type 1 emulator
3038        let emu_type1 = create_type1_emulator(vec![]);
3039        assert_eq!(emu_type1.common.bar_count(), 2);
3040        assert_eq!(emu_type1.common.header_type(), HeaderType::Type1);
3041        assert!(emu_type1.common.validate_header_type(HeaderType::Type1));
3042        assert!(!emu_type1.common.validate_header_type(HeaderType::Type0));
3043    }
3044
3045    /// Ensure that `find_bar` correctly returns a full `u64` offset for BARs
3046    /// larger than 64KiB, guarding against truncation back to `u16`.
3047    #[test]
3048    fn find_bar_returns_full_u64_offset_for_large_bar() {
3049        use crate::bar_mapping::BarMappings;
3050
3051        // Set up a 64-bit BAR0 at base address 0x1_0000_0000 with size
3052        // 0x2_0000 (128KiB). The mask encodes the size via the complement:
3053        //   mask = !(size - 1) = !(0x1_FFFF) = 0xFFFF_FFFE_0000
3054        // Split across two 32-bit BAR registers (BAR0 low + BAR1 high).
3055        let bar_base: u64 = 0x1_0000_0000;
3056        let bar_size: u64 = 0x2_0000; // 128KiB — larger than u16::MAX
3057        let mask64 = !(bar_size - 1); // 0xFFFF_FFFE_0000
3058
3059        let mut base_addresses = [0u32; 6];
3060        let mut bar_masks = [0u32; 6];
3061
3062        // BAR0 low: set the 64-bit type bit in the mask and the base address.
3063        bar_masks[0] = cfg_space::BarEncodingBits::from_bits(mask64 as u32)
3064            .with_type_64_bit(true)
3065            .into_bits();
3066        bar_masks[1] = (mask64 >> 32) as u32;
3067        base_addresses[0] = bar_base as u32;
3068        base_addresses[1] = (bar_base >> 32) as u32;
3069
3070        let bar_mappings = BarMappings::parse(&base_addresses, &bar_masks);
3071
3072        // Query an address whose offset within BAR0 exceeds 0xFFFF.
3073        let expected_offset: u64 = 0x1_2345;
3074        let address: u64 = bar_base + expected_offset;
3075
3076        let (found_bar, offset) = bar_mappings
3077            .find(address)
3078            .expect("address should resolve to BAR 0");
3079        assert_eq!(found_bar, 0);
3080        assert_eq!(offset, expected_offset);
3081    }
3082
3083    #[test]
3084    fn test_odd_index_64bit_bar_preserves_attrs_only_on_lower_dword() {
3085        let mut bars = DeviceBars::new();
3086        bars.bars[1] = Some((4096, BarMemoryKind::Dummy));
3087
3088        let mut common_emu = ConfigSpaceCommonHeaderEmulatorType0::new(
3089            HardwareIds {
3090                vendor_id: 0x1111,
3091                device_id: 0x2222,
3092                revision_id: 1,
3093                prog_if: ProgrammingInterface::NONE,
3094                sub_class: Subclass::NONE,
3095                base_class: ClassCode::UNCLASSIFIED,
3096                type0_sub_vendor_id: 0,
3097                type0_sub_system_id: 0,
3098            },
3099            vec![],
3100            vec![],
3101            bars,
3102        );
3103
3104        // BAR1 is the lower dword of a 64-bit BAR and should preserve
3105        // encoding bits (type + prefetchable).
3106        assert!(matches!(
3107            common_emu.write(
3108                PciConfigAddress::new(0, 0, 0x14 / 4).unwrap(),
3109                ByteEnabledDwordWrite::with_all_bytes_enabled(0x1234_5000),
3110            ),
3111            CommonHeaderResult::Handled
3112        ));
3113        assert_eq!(common_emu.base_addresses()[1] & 0xF, 0xC);
3114
3115        // BAR2 is the upper dword and must not be treated as encoding bits.
3116        assert!(matches!(
3117            common_emu.write(
3118                PciConfigAddress::new(0, 0, 0x18 / 4).unwrap(),
3119                ByteEnabledDwordWrite::with_all_bytes_enabled(0x89ab_cde5),
3120            ),
3121            CommonHeaderResult::Handled
3122        ));
3123        assert_eq!(common_emu.base_addresses()[2] & 0xF, 0x5);
3124    }
3125
3126    #[test]
3127    fn test_32bit_bar_preserves_attr_bits_without_clobbering_address_bits() {
3128        let mut common_emu = ConfigSpaceCommonHeaderEmulatorType0::new(
3129            HardwareIds {
3130                vendor_id: 0x1111,
3131                device_id: 0x2222,
3132                revision_id: 1,
3133                prog_if: ProgrammingInterface::NONE,
3134                sub_class: Subclass::NONE,
3135                base_class: ClassCode::UNCLASSIFIED,
3136                type0_sub_vendor_id: 0,
3137                type0_sub_system_id: 0,
3138            },
3139            vec![],
3140            vec![],
3141            DeviceBars::new(),
3142        );
3143
3144        // Force BAR0 to behave like a 32-bit mapped BAR with the prefetchable
3145        // bit set. This validates low-nibble preservation independent of
3146        // current DeviceBars construction defaults.
3147        common_emu.bar_masks[0] = 0xffff_fff0 | 0x8;
3148        common_emu.mapped_memory[0] = Some(BarMemoryKind::Dummy);
3149
3150        assert!(matches!(
3151            common_emu.write(
3152                PciConfigAddress::new(0, 0, 0x10 / 4).unwrap(),
3153                ByteEnabledDwordWrite::with_all_bytes_enabled(0x1234_5670),
3154            ),
3155            CommonHeaderResult::Handled
3156        ));
3157
3158        // Low nibble should retain BAR attribute bits from the mask while
3159        // higher address bits should come from the guest write and BAR mask.
3160        assert_eq!(common_emu.base_addresses()[0], 0x1234_5678);
3161    }
3162
3163    // A `ControlMmioIntercept` test double that records map/unmap. Like some
3164    // real intercept implementations (e.g. the PCIe test intercept), its
3165    // `unmap()` panics if called while not mapped -- so these tests also verify
3166    // that teardown never unmaps a BAR that was never mapped.
3167    struct TrackingBar {
3168        len: u64,
3169        addr: Option<u64>,
3170        mapped: Arc<AtomicBool>,
3171    }
3172
3173    impl ControlMmioIntercept for TrackingBar {
3174        fn region_name(&self) -> &str {
3175            "bar0"
3176        }
3177        fn map(&mut self, addr: u64) {
3178            self.addr = Some(addr);
3179            self.mapped.store(true, Ordering::SeqCst);
3180        }
3181        fn unmap(&mut self) {
3182            assert!(self.addr.is_some(), "unmap called while not mapped");
3183            self.addr = None;
3184            self.mapped.store(false, Ordering::SeqCst);
3185        }
3186        fn addr(&self) -> Option<u64> {
3187            self.addr
3188        }
3189        fn len(&self) -> u64 {
3190            self.len
3191        }
3192        fn offset_of(&self, addr: u64) -> Option<u64> {
3193            let base = self.addr?;
3194            (base..base + self.len).contains(&addr).then(|| addr - base)
3195        }
3196    }
3197
3198    fn config_space_with_intercept_bar(
3199        mapped: Arc<AtomicBool>,
3200    ) -> ConfigSpaceCommonHeaderEmulatorType0 {
3201        let bars = DeviceBars::new().bar0(
3202            0x1000,
3203            BarMemoryKind::Intercept(Box::new(TrackingBar {
3204                len: 0x1000,
3205                addr: None,
3206                mapped,
3207            })),
3208        );
3209        ConfigSpaceCommonHeaderEmulatorType0::new(
3210            HardwareIds {
3211                vendor_id: 0x1111,
3212                device_id: 0x2222,
3213                revision_id: 1,
3214                prog_if: ProgrammingInterface::NONE,
3215                sub_class: Subclass::NONE,
3216                base_class: ClassCode::UNCLASSIFIED,
3217                type0_sub_vendor_id: 0,
3218                type0_sub_system_id: 0,
3219            },
3220            vec![],
3221            vec![],
3222            bars,
3223        )
3224    }
3225
3226    // Regression test for a PCIe hot-add-after-remove failure: when a device's
3227    // config space is dropped (e.g. a hot-removed controller being torn down),
3228    // its BAR intercept registrations must be released. Otherwise the stale
3229    // range stays in the chipset's shared range map and a subsequent device
3230    // that reuses the same GPA fails to install its intercept, leaving its BAR
3231    // undispatched (guest reads all-1s -> stornvme FindAdapter reads CAP=~0).
3232    #[test]
3233    fn dropping_config_space_unmaps_bar_intercepts() {
3234        let mapped = Arc::new(AtomicBool::new(false));
3235        let mut common_emu = config_space_with_intercept_bar(mapped.clone());
3236
3237        // Program BAR0's base address and enable memory space so the BAR
3238        // intercept is mapped into the chipset's range map.
3239        common_emu.set_base_addresses(&[0x2000_0000, 0, 0, 0, 0, 0]);
3240        common_emu.update_mmio_enabled(true);
3241        assert!(
3242            mapped.load(Ordering::SeqCst),
3243            "BAR intercept should be mapped once memory space is enabled"
3244        );
3245
3246        // Dropping the config space (device teardown / hot-remove) must unmap
3247        // the BAR intercept so its range is released.
3248        drop(common_emu);
3249        assert!(
3250            !mapped.load(Ordering::SeqCst),
3251            "dropping config space must unmap its BAR intercepts"
3252        );
3253    }
3254
3255    // A device can be torn down before the guest ever enables memory space (so
3256    // the BAR was never mapped). Dropping its config space must not attempt to
3257    // unmap the never-mapped intercept -- which would panic for intercept impls
3258    // whose `unmap()` is not idempotent (as `TrackingBar::unmap` asserts here).
3259    #[test]
3260    fn dropping_config_space_without_mmio_enabled_does_not_unmap() {
3261        let mapped = Arc::new(AtomicBool::new(false));
3262        let common_emu = config_space_with_intercept_bar(mapped.clone());
3263
3264        // Never enabled memory space -> BAR never mapped. Dropping must be a
3265        // no-op for the intercept and must not panic.
3266        drop(common_emu);
3267        assert!(!mapped.load(Ordering::SeqCst));
3268    }
3269
3270    #[test]
3271    fn test_type1_bdf_capturing() {
3272        // Test that the type1 config space emulator captures
3273        // the BDF of accesses it receives.
3274        let mut type1_emulator = create_type1_emulator(vec![]);
3275
3276        // Initially, the captured BDF should be 0.
3277        assert_eq!(type1_emulator.captured_bus_number(), 0);
3278        assert_eq!(type1_emulator.captured_devfn(), 0);
3279
3280        // Reads do not capture the BDF.
3281        let mut read_value = 0;
3282        let _ = type1_emulator.read(
3283            PciConfigAddress::new(1, 1, 0).unwrap(),
3284            ByteEnabledDwordRead::with_all_bytes_enabled(&mut read_value),
3285        );
3286        assert_eq!(type1_emulator.captured_bus_number(), 0);
3287        assert_eq!(type1_emulator.captured_devfn(), 0);
3288
3289        // Writes capture the BDF.
3290        let _ = type1_emulator.write(
3291            PciConfigAddress::new(1, 1, 0).unwrap(),
3292            ByteEnabledDwordWrite::with_all_bytes_enabled(0xdead_beef),
3293        );
3294        assert_eq!(type1_emulator.captured_bus_number(), 1);
3295        assert_eq!(type1_emulator.captured_devfn(), 1);
3296
3297        // And writing a new BDF overwrites the old.
3298        let _ = type1_emulator.write(
3299            PciConfigAddress::new(4, 1, 0).unwrap(),
3300            ByteEnabledDwordWrite::with_all_bytes_enabled(0xdead_beef),
3301        );
3302        assert_eq!(type1_emulator.captured_bus_number(), 4);
3303        assert_eq!(type1_emulator.captured_devfn(), 1);
3304
3305        // Save state with BDF captured.
3306        let saved_state = type1_emulator.save().expect("save should succeed");
3307
3308        // Captured BDF should be cleared on reset.
3309        type1_emulator.reset();
3310        assert_eq!(type1_emulator.captured_bus_number(), 0);
3311        assert_eq!(type1_emulator.captured_devfn(), 0);
3312
3313        // Restore the state, captured BDF should be restored.
3314        type1_emulator
3315            .restore(saved_state)
3316            .expect("restore should succeed");
3317        assert_eq!(type1_emulator.captured_bus_number(), 4);
3318        assert_eq!(type1_emulator.captured_devfn(), 1);
3319    }
3320
3321    #[test]
3322    fn test_type0_bdf_capturing() {
3323        // Test that the type0 config space emulator captures
3324        // the BDF of accesses it receives.
3325        let mut type0_emulator = create_type0_emulator(vec![]);
3326
3327        // Initially, the captured BDF should be 0.
3328        assert_eq!(type0_emulator.captured_bus_number(), 0);
3329        assert_eq!(type0_emulator.captured_devfn(), 0);
3330
3331        // Reads do not capture the BDF.
3332        let mut read_value = 0;
3333        let _ = type0_emulator.read(
3334            PciConfigAddress::new(1, 1, 0).unwrap(),
3335            ByteEnabledDwordRead::with_all_bytes_enabled(&mut read_value),
3336        );
3337        assert_eq!(type0_emulator.captured_bus_number(), 0);
3338        assert_eq!(type0_emulator.captured_devfn(), 0);
3339
3340        // Writes capture the BDF.
3341        let _ = type0_emulator.write(
3342            PciConfigAddress::new(1, 1, 0).unwrap(),
3343            ByteEnabledDwordWrite::with_all_bytes_enabled(0xdead_beef),
3344        );
3345        assert_eq!(type0_emulator.captured_bus_number(), 1);
3346        assert_eq!(type0_emulator.captured_devfn(), 1);
3347
3348        // And writing a new BDF overwrites the old.
3349        let _ = type0_emulator.write(
3350            PciConfigAddress::new(4, 1, 0).unwrap(),
3351            ByteEnabledDwordWrite::with_all_bytes_enabled(0xdead_beef),
3352        );
3353        assert_eq!(type0_emulator.captured_bus_number(), 4);
3354        assert_eq!(type0_emulator.captured_devfn(), 1);
3355
3356        // Save state with BDF captured.
3357        let saved_state = type0_emulator.save().expect("save should succeed");
3358
3359        // Captured BDF should be cleared on reset.
3360        type0_emulator.reset();
3361        assert_eq!(type0_emulator.captured_bus_number(), 0);
3362        assert_eq!(type0_emulator.captured_devfn(), 0);
3363
3364        // Restore the state, captured BDF should be restored.
3365        type0_emulator
3366            .restore(saved_state)
3367            .expect("restore should succeed");
3368        assert_eq!(type0_emulator.captured_bus_number(), 4);
3369        assert_eq!(type0_emulator.captured_devfn(), 1);
3370    }
3371}