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::spec::caps::CapabilityId;
13use crate::spec::cfg_space;
14use crate::spec::hwid::HardwareIds;
15use chipset_device::io::IoError;
16use chipset_device::io::IoResult;
17use chipset_device::mmio::ControlMmioIntercept;
18use guestmem::MappableGuestMemory;
19use inspect::Inspect;
20use std::ops::RangeInclusive;
21use std::sync::Arc;
22use std::sync::atomic::AtomicBool;
23use std::sync::atomic::Ordering;
24use vmcore::line_interrupt::LineInterrupt;
25
26/// PCI configuration space header type with corresponding BAR count
27///
28/// This enum provides a type-safe way to work with PCI configuration space header types
29/// and their corresponding BAR counts. It improves readability over raw constants.
30///
31/// # Examples
32///
33/// ```rust
34/// # use pci_core::cfg_space_emu::HeaderType;
35/// // Get BAR count for different header types
36/// assert_eq!(HeaderType::Type0.bar_count(), 6);
37/// assert_eq!(HeaderType::Type1.bar_count(), 2);
38///
39/// // Convert to usize for use in generic contexts
40/// let bar_count: usize = HeaderType::Type0.into();
41/// assert_eq!(bar_count, 6);
42/// ```
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum HeaderType {
45    /// Type 0 header with 6 BARs (endpoint devices)
46    Type0,
47    /// Type 1 header with 2 BARs (bridge devices)
48    Type1,
49}
50
51impl HeaderType {
52    /// Get the number of BARs for this header type
53    pub const fn bar_count(self) -> usize {
54        match self {
55            HeaderType::Type0 => 6,
56            HeaderType::Type1 => 2,
57        }
58    }
59}
60
61impl From<HeaderType> for usize {
62    fn from(header_type: HeaderType) -> usize {
63        header_type.bar_count()
64    }
65}
66
67/// Constants for header type BAR counts
68pub mod header_type_consts {
69    use super::HeaderType;
70
71    /// Number of BARs for Type 0 headers
72    pub const TYPE0_BAR_COUNT: usize = HeaderType::Type0.bar_count();
73
74    /// Number of BARs for Type 1 headers
75    pub const TYPE1_BAR_COUNT: usize = HeaderType::Type1.bar_count();
76}
77
78/// Result type for common header emulator operations
79#[derive(Debug)]
80pub enum CommonHeaderResult {
81    /// The access was handled by the common header emulator
82    Handled,
83    /// The access is not handled by common header, caller should handle it
84    Unhandled,
85    /// The access failed with an error
86    Failed(IoError),
87}
88
89impl PartialEq for CommonHeaderResult {
90    fn eq(&self, other: &Self) -> bool {
91        match (self, other) {
92            (Self::Handled, Self::Handled) => true,
93            (Self::Unhandled, Self::Unhandled) => true,
94            (Self::Failed(_), Self::Failed(_)) => true, // Consider all failures equal for testing
95            _ => false,
96        }
97    }
98}
99
100const SUPPORTED_COMMAND_BITS: u16 = cfg_space::Command::new()
101    .with_pio_enabled(true)
102    .with_mmio_enabled(true)
103    .with_bus_master(true)
104    .with_special_cycles(true)
105    .with_enable_memory_write_invalidate(true)
106    .with_vga_palette_snoop(true)
107    .with_parity_error_response(true)
108    .with_enable_serr(true)
109    .with_enable_fast_b2b(true)
110    .with_intx_disable(true)
111    .into_bits();
112
113/// A wrapper around a [`LineInterrupt`] that considers PCI configuration space
114/// interrupt control bits.
115#[derive(Debug, Inspect)]
116pub struct IntxInterrupt {
117    pin: PciInterruptPin,
118    line: LineInterrupt,
119    interrupt_disabled: AtomicBool,
120    interrupt_status: AtomicBool,
121}
122
123impl IntxInterrupt {
124    /// Sets the line level high or low.
125    ///
126    /// NOTE: whether or not this will actually trigger an interrupt will depend
127    /// the status of the Interrupt Disabled bit in the PCI configuration space.
128    pub fn set_level(&self, high: bool) {
129        tracing::debug!(
130            disabled = ?self.interrupt_disabled,
131            status = ?self.interrupt_status,
132            ?high,
133            %self.line,
134            "set_level"
135        );
136
137        // the actual config space bit is set unconditionally
138        self.interrupt_status.store(high, Ordering::SeqCst);
139
140        // ...but whether it also fires an interrupt is a different story
141        if self.interrupt_disabled.load(Ordering::SeqCst) {
142            self.line.set_level(false);
143        } else {
144            self.line.set_level(high);
145        }
146    }
147
148    fn set_disabled(&self, disabled: bool) {
149        tracing::debug!(
150            disabled = ?self.interrupt_disabled,
151            status = ?self.interrupt_status,
152            ?disabled,
153            %self.line,
154            "set_disabled"
155        );
156
157        self.interrupt_disabled.store(disabled, Ordering::SeqCst);
158        if disabled {
159            self.line.set_level(false)
160        } else {
161            if self.interrupt_status.load(Ordering::SeqCst) {
162                self.line.set_level(true)
163            }
164        }
165    }
166}
167
168#[derive(Debug, Inspect)]
169struct ConfigSpaceCommonHeaderEmulatorState<const N: usize> {
170    /// The command register
171    command: cfg_space::Command,
172    /// OS-configured BARs
173    #[inspect(with = "inspect_helpers::bars_generic")]
174    base_addresses: [u32; N],
175    /// The PCI device doesn't actually care about what value is stored here -
176    /// this register is just a bit of standardized "scratch space", ostensibly
177    /// for firmware to communicate IRQ assignments to the OS, but it can really
178    /// be used for just about anything.
179    interrupt_line: u8,
180}
181
182impl<const N: usize> ConfigSpaceCommonHeaderEmulatorState<N> {
183    fn new() -> Self {
184        Self {
185            command: cfg_space::Command::new(),
186            base_addresses: {
187                const ZERO: u32 = 0;
188                [ZERO; N]
189            },
190            interrupt_line: 0,
191        }
192    }
193}
194
195/// Common emulator for shared PCI configuration space functionality.
196/// Generic over the number of BARs (6 for Type 0, 2 for Type 1).
197#[derive(Inspect)]
198pub struct ConfigSpaceCommonHeaderEmulator<const N: usize> {
199    // Fixed configuration
200    #[inspect(with = "inspect_helpers::bars_generic")]
201    bar_masks: [u32; N],
202    hardware_ids: HardwareIds,
203    multi_function_bit: bool,
204
205    // Runtime glue
206    #[inspect(with = r#"|x| inspect::iter_by_index(x).prefix("bar")"#)]
207    mapped_memory: [Option<BarMemoryKind>; N],
208    #[inspect(with = "|x| inspect::iter_by_key(x.iter().map(|cap| (cap.label(), cap)))")]
209    capabilities: Vec<Box<dyn PciCapability>>,
210    intx_interrupt: Option<Arc<IntxInterrupt>>,
211
212    // Runtime book-keeping
213    active_bars: BarMappings,
214
215    // Volatile state
216    state: ConfigSpaceCommonHeaderEmulatorState<N>,
217}
218
219/// Type alias for Type 0 common header emulator (6 BARs)
220pub type ConfigSpaceCommonHeaderEmulatorType0 =
221    ConfigSpaceCommonHeaderEmulator<{ header_type_consts::TYPE0_BAR_COUNT }>;
222
223/// Type alias for Type 1 common header emulator (2 BARs)
224pub type ConfigSpaceCommonHeaderEmulatorType1 =
225    ConfigSpaceCommonHeaderEmulator<{ header_type_consts::TYPE1_BAR_COUNT }>;
226
227impl<const N: usize> ConfigSpaceCommonHeaderEmulator<N> {
228    /// Create a new common header emulator
229    pub fn new(
230        hardware_ids: HardwareIds,
231        capabilities: Vec<Box<dyn PciCapability>>,
232        bars: DeviceBars,
233    ) -> Self {
234        let mut bar_masks = {
235            const ZERO: u32 = 0;
236            [ZERO; N]
237        };
238        let mut mapped_memory = {
239            const NONE: Option<BarMemoryKind> = None;
240            [NONE; N]
241        };
242
243        // Only process BARs that fit within our supported range (N)
244        for (bar_index, bar) in bars.bars.into_iter().enumerate().take(N) {
245            let (len, mapped) = match bar {
246                Some(bar) => bar,
247                None => continue,
248            };
249            // use 64-bit aware BARs
250            assert!(bar_index < N.saturating_sub(1));
251            // Round up regions to a power of 2, as required by PCI (and
252            // inherently required by the BAR representation). Round up to at
253            // least one page to avoid various problems in guest OSes.
254            const MIN_BAR_SIZE: u64 = 4096;
255            let len = std::cmp::max(len.next_power_of_two(), MIN_BAR_SIZE);
256            let mask64 = !(len - 1);
257            bar_masks[bar_index] = cfg_space::BarEncodingBits::from_bits(mask64 as u32)
258                .with_type_64_bit(true)
259                .into_bits();
260            if bar_index + 1 < N {
261                bar_masks[bar_index + 1] = (mask64 >> 32) as u32;
262            }
263            mapped_memory[bar_index] = Some(mapped);
264        }
265
266        Self {
267            hardware_ids,
268            capabilities,
269            bar_masks,
270            mapped_memory,
271            multi_function_bit: false,
272            intx_interrupt: None,
273            active_bars: Default::default(),
274            state: ConfigSpaceCommonHeaderEmulatorState::new(),
275        }
276    }
277
278    /// Get the number of BARs supported by this emulator
279    pub const fn bar_count(&self) -> usize {
280        N
281    }
282
283    /// Validate that this emulator has the correct number of BARs for the given header type
284    pub fn validate_header_type(&self, expected: HeaderType) -> bool {
285        N == expected.bar_count()
286    }
287
288    /// If the device is multi-function, enable bit 7 in the Header register.
289    pub fn with_multi_function_bit(mut self, bit: bool) -> Self {
290        self.multi_function_bit = bit;
291        self
292    }
293
294    /// If using legacy INT#x interrupts: wire a LineInterrupt to one of the 4
295    /// INT#x pins, returning an object that manages configuration space bits
296    /// when the device sets the interrupt level.
297    pub fn set_interrupt_pin(
298        &mut self,
299        pin: PciInterruptPin,
300        line: LineInterrupt,
301    ) -> Arc<IntxInterrupt> {
302        let intx_interrupt = Arc::new(IntxInterrupt {
303            pin,
304            line,
305            interrupt_disabled: AtomicBool::new(false),
306            interrupt_status: AtomicBool::new(false),
307        });
308        self.intx_interrupt = Some(intx_interrupt.clone());
309        intx_interrupt
310    }
311
312    /// Reset the common header state
313    pub fn reset(&mut self) {
314        tracing::info!("ConfigSpaceCommonHeaderEmulator: resetting state");
315        self.state = ConfigSpaceCommonHeaderEmulatorState::new();
316
317        tracing::info!("ConfigSpaceCommonHeaderEmulator: syncing command register after reset");
318        self.sync_command_register(self.state.command);
319
320        tracing::info!(
321            "ConfigSpaceCommonHeaderEmulator: resetting {} capabilities",
322            self.capabilities.len()
323        );
324        for cap in &mut self.capabilities {
325            cap.reset();
326        }
327
328        if let Some(intx) = &mut self.intx_interrupt {
329            tracing::info!("ConfigSpaceCommonHeaderEmulator: resetting interrupt level");
330            intx.set_level(false);
331        }
332        tracing::info!("ConfigSpaceCommonHeaderEmulator: reset completed");
333    }
334
335    /// Get hardware IDs
336    pub fn hardware_ids(&self) -> &HardwareIds {
337        &self.hardware_ids
338    }
339
340    /// Get capabilities
341    pub fn capabilities(&self) -> &[Box<dyn PciCapability>] {
342        &self.capabilities
343    }
344
345    /// Get capabilities mutably
346    pub fn capabilities_mut(&mut self) -> &mut [Box<dyn PciCapability>] {
347        &mut self.capabilities
348    }
349
350    /// Get multi-function bit
351    pub fn multi_function_bit(&self) -> bool {
352        self.multi_function_bit
353    }
354
355    /// Get the header type for this emulator
356    pub const fn header_type(&self) -> HeaderType {
357        match N {
358            header_type_consts::TYPE0_BAR_COUNT => HeaderType::Type0,
359            header_type_consts::TYPE1_BAR_COUNT => HeaderType::Type1,
360            _ => panic!("Unsupported BAR count - must be 6 (Type0) or 2 (Type1)"),
361        }
362    }
363
364    /// Get current command register state
365    pub fn command(&self) -> cfg_space::Command {
366        self.state.command
367    }
368
369    /// Get current base addresses
370    pub fn base_addresses(&self) -> &[u32; N] {
371        &self.state.base_addresses
372    }
373
374    /// Get current interrupt line
375    pub fn interrupt_line(&self) -> u8 {
376        self.state.interrupt_line
377    }
378
379    /// Get current interrupt pin (returns the pin number + 1, or 0 if no pin configured)
380    pub fn interrupt_pin(&self) -> u8 {
381        if let Some(intx) = &self.intx_interrupt {
382            (intx.pin as u8) + 1 // PCI spec: 1=INTA, 2=INTB, 3=INTC, 4=INTD, 0=no interrupt
383        } else {
384            0 // No interrupt pin configured
385        }
386    }
387
388    /// Set interrupt line (for save/restore)
389    pub fn set_interrupt_line(&mut self, interrupt_line: u8) {
390        self.state.interrupt_line = interrupt_line;
391    }
392
393    /// Set base addresses (for save/restore)
394    pub fn set_base_addresses(&mut self, base_addresses: &[u32; N]) {
395        self.state.base_addresses = *base_addresses;
396    }
397
398    /// Set command register (for save/restore)
399    pub fn set_command(&mut self, command: cfg_space::Command) {
400        self.state.command = command;
401    }
402
403    /// Sync command register changes by updating both interrupt and MMIO state
404    pub fn sync_command_register(&mut self, command: cfg_space::Command) {
405        tracing::info!(
406            "ConfigSpaceCommonHeaderEmulator: syncing command register - intx_disable={}, mmio_enabled={}",
407            command.intx_disable(),
408            command.mmio_enabled()
409        );
410        self.update_intx_disable(command.intx_disable());
411        self.update_mmio_enabled(command.mmio_enabled());
412    }
413
414    /// Update interrupt disable setting
415    pub fn update_intx_disable(&mut self, disabled: bool) {
416        tracing::info!(
417            "ConfigSpaceCommonHeaderEmulator: updating intx_disable={}",
418            disabled
419        );
420        if let Some(intx_interrupt) = &self.intx_interrupt {
421            intx_interrupt.set_disabled(disabled)
422        }
423    }
424
425    /// Update MMIO enabled setting and handle BAR mapping
426    pub fn update_mmio_enabled(&mut self, enabled: bool) {
427        tracing::info!(
428            "ConfigSpaceCommonHeaderEmulator: updating mmio_enabled={}",
429            enabled
430        );
431        if enabled {
432            // Note that BarMappings expects 6 BARs. Pad with 0 for Type 1 (N=2)
433            // and use directly for Type 0 (N=6).
434            let mut full_base_addresses = [0u32; 6];
435            let mut full_bar_masks = [0u32; 6];
436
437            // Copy our data into the first N positions
438            full_base_addresses[..N].copy_from_slice(&self.state.base_addresses[..N]);
439            full_bar_masks[..N].copy_from_slice(&self.bar_masks[..N]);
440
441            self.active_bars = BarMappings::parse(&full_base_addresses, &full_bar_masks);
442            for (bar, mapping) in self.mapped_memory.iter_mut().enumerate() {
443                if let Some(mapping) = mapping {
444                    let base = self.active_bars.get(bar as u8).expect("bar exists");
445                    match mapping.map_to_guest(base) {
446                        Ok(_) => {}
447                        Err(err) => {
448                            tracelimit::error_ratelimited!(
449                                error = &err as &dyn std::error::Error,
450                                bar,
451                                base,
452                                "failed to map bar",
453                            )
454                        }
455                    }
456                }
457            }
458        } else {
459            self.active_bars = Default::default();
460            for mapping in self.mapped_memory.iter_mut().flatten() {
461                mapping.unmap_from_guest();
462            }
463        }
464    }
465
466    // ===== Configuration Space Read/Write Functions =====
467
468    /// Read from the config space. `offset` must be 32-bit aligned.
469    /// Returns CommonHeaderResult indicating if handled, unhandled, or failed.
470    pub fn read_u32(&self, offset: u16, value: &mut u32) -> CommonHeaderResult {
471        use cfg_space::CommonHeader;
472
473        tracing::trace!(
474            "ConfigSpaceCommonHeaderEmulator: read_u32 offset={:#x}",
475            offset
476        );
477
478        *value = match CommonHeader(offset) {
479            CommonHeader::DEVICE_VENDOR => {
480                (self.hardware_ids.device_id as u32) << 16 | self.hardware_ids.vendor_id as u32
481            }
482            CommonHeader::STATUS_COMMAND => {
483                let mut status =
484                    cfg_space::Status::new().with_capabilities_list(!self.capabilities.is_empty());
485
486                if let Some(intx_interrupt) = &self.intx_interrupt {
487                    if intx_interrupt.interrupt_status.load(Ordering::SeqCst) {
488                        status.set_interrupt_status(true);
489                    }
490                }
491
492                (status.into_bits() as u32) << 16 | self.state.command.into_bits() as u32
493            }
494            CommonHeader::CLASS_REVISION => {
495                (u8::from(self.hardware_ids.base_class) as u32) << 24
496                    | (u8::from(self.hardware_ids.sub_class) as u32) << 16
497                    | (u8::from(self.hardware_ids.prog_if) as u32) << 8
498                    | self.hardware_ids.revision_id as u32
499            }
500            CommonHeader::RESERVED_CAP_PTR => {
501                if self.capabilities.is_empty() {
502                    0
503                } else {
504                    0x40
505                }
506            }
507            // Capabilities space - handled by common emulator
508            _ if (0x40..0x100).contains(&offset) => {
509                return self.read_capabilities(offset, value);
510            }
511            // Extended capabilities space - handled by common emulator
512            _ if (0x100..0x1000).contains(&offset) => {
513                return self.read_extended_capabilities(offset, value);
514            }
515            // Check if this is a BAR read
516            _ if self.is_bar_offset(offset) => {
517                return self.read_bar(offset, value);
518            }
519            // Unhandled access - not part of common header, caller should handle
520            _ => {
521                return CommonHeaderResult::Unhandled;
522            }
523        };
524
525        tracing::trace!(
526            "ConfigSpaceCommonHeaderEmulator: read_u32 offset={:#x} -> value={:#x}",
527            offset,
528            *value
529        );
530        // Handled access
531        CommonHeaderResult::Handled
532    }
533
534    /// Write to the config space. `offset` must be 32-bit aligned.
535    /// Returns CommonHeaderResult indicating if handled, unhandled, or failed.
536    pub fn write_u32(&mut self, offset: u16, val: u32) -> CommonHeaderResult {
537        use cfg_space::CommonHeader;
538
539        tracing::trace!(
540            "ConfigSpaceCommonHeaderEmulator: write_u32 offset={:#x} val={:#x}",
541            offset,
542            val
543        );
544
545        match CommonHeader(offset) {
546            CommonHeader::STATUS_COMMAND => {
547                let mut command = cfg_space::Command::from_bits(val as u16);
548                if command.into_bits() & !SUPPORTED_COMMAND_BITS != 0 {
549                    tracelimit::warn_ratelimited!(offset, val, "setting invalid command bits");
550                    // still do our best
551                    command =
552                        cfg_space::Command::from_bits(command.into_bits() & SUPPORTED_COMMAND_BITS);
553                };
554
555                if self.state.command.intx_disable() != command.intx_disable() {
556                    self.update_intx_disable(command.intx_disable())
557                }
558
559                if self.state.command.mmio_enabled() != command.mmio_enabled() {
560                    self.update_mmio_enabled(command.mmio_enabled())
561                }
562
563                self.state.command = command;
564            }
565            // Capabilities space - handled by common emulator
566            _ if (0x40..0x100).contains(&offset) => {
567                return self.write_capabilities(offset, val);
568            }
569            // Extended capabilities space - handled by common emulator
570            _ if (0x100..0x1000).contains(&offset) => {
571                return self.write_extended_capabilities(offset, val);
572            }
573            // Check if this is a BAR write (Type 0: 0x10-0x27, Type 1: 0x10-0x17)
574            _ if self.is_bar_offset(offset) => {
575                return self.write_bar(offset, val);
576            }
577            // Unhandled access - not part of common header, caller should handle
578            _ => {
579                return CommonHeaderResult::Unhandled;
580            }
581        }
582
583        // Handled access
584        CommonHeaderResult::Handled
585    }
586
587    /// Helper for reading BAR registers
588    fn read_bar(&self, offset: u16, value: &mut u32) -> CommonHeaderResult {
589        if !self.is_bar_offset(offset) {
590            return CommonHeaderResult::Unhandled;
591        }
592
593        let bar_index = self.get_bar_index(offset);
594        if bar_index < N {
595            *value = self.state.base_addresses[bar_index];
596        } else {
597            *value = 0;
598        }
599        CommonHeaderResult::Handled
600    }
601
602    /// Helper for writing BAR registers
603    fn write_bar(&mut self, offset: u16, val: u32) -> CommonHeaderResult {
604        if !self.is_bar_offset(offset) {
605            return CommonHeaderResult::Unhandled;
606        }
607
608        // Handle BAR writes - only allow when MMIO is disabled
609        if !self.state.command.mmio_enabled() {
610            let bar_index = self.get_bar_index(offset);
611            if bar_index < N {
612                let mut bar_value = val & self.bar_masks[bar_index];
613
614                // For even-indexed BARs, set the 64-bit type bit if the BAR is configured
615                if bar_index & 1 == 0 && self.bar_masks[bar_index] != 0 {
616                    bar_value = cfg_space::BarEncodingBits::from_bits(bar_value)
617                        .with_type_64_bit(true)
618                        .into_bits();
619                }
620
621                self.state.base_addresses[bar_index] = bar_value;
622            }
623        }
624        CommonHeaderResult::Handled
625    }
626
627    /// Read from capabilities space. `offset` must be 32-bit aligned and >= 0x40.
628    fn read_capabilities(&self, offset: u16, value: &mut u32) -> CommonHeaderResult {
629        if (0x40..0x100).contains(&offset) {
630            if let Some((cap_index, cap_offset)) =
631                self.get_capability_index_and_offset(offset - 0x40)
632            {
633                *value = self.capabilities[cap_index].read_u32(cap_offset);
634                if cap_offset == 0 {
635                    let next = if cap_index < self.capabilities.len() - 1 {
636                        offset as u32 + self.capabilities[cap_index].len() as u32
637                    } else {
638                        0
639                    };
640                    assert!(*value & 0xff00 == 0);
641                    *value |= next << 8;
642                }
643                CommonHeaderResult::Handled
644            } else {
645                tracelimit::warn_ratelimited!(offset, "unhandled config space read");
646                CommonHeaderResult::Failed(IoError::InvalidRegister)
647            }
648        } else {
649            CommonHeaderResult::Failed(IoError::InvalidRegister)
650        }
651    }
652
653    /// Write to capabilities space. `offset` must be 32-bit aligned and >= 0x40.
654    fn write_capabilities(&mut self, offset: u16, val: u32) -> CommonHeaderResult {
655        if (0x40..0x100).contains(&offset) {
656            if let Some((cap_index, cap_offset)) =
657                self.get_capability_index_and_offset(offset - 0x40)
658            {
659                self.capabilities[cap_index].write_u32(cap_offset, val);
660                CommonHeaderResult::Handled
661            } else {
662                tracelimit::warn_ratelimited!(offset, value = val, "unhandled config space write");
663                CommonHeaderResult::Failed(IoError::InvalidRegister)
664            }
665        } else {
666            CommonHeaderResult::Failed(IoError::InvalidRegister)
667        }
668    }
669
670    /// Read from extended capabilities space (0x100-0x1000). `offset` must be 32-bit aligned.
671    fn read_extended_capabilities(&self, offset: u16, value: &mut u32) -> CommonHeaderResult {
672        if (0x100..0x1000).contains(&offset) {
673            if self.is_pcie_device() {
674                *value = 0xffffffff;
675                CommonHeaderResult::Handled
676            } else {
677                tracelimit::warn_ratelimited!(offset, "unhandled extended config space read");
678                CommonHeaderResult::Failed(IoError::InvalidRegister)
679            }
680        } else {
681            CommonHeaderResult::Failed(IoError::InvalidRegister)
682        }
683    }
684
685    /// Write to extended capabilities space (0x100-0x1000). `offset` must be 32-bit aligned.
686    fn write_extended_capabilities(&mut self, offset: u16, val: u32) -> CommonHeaderResult {
687        if (0x100..0x1000).contains(&offset) {
688            if self.is_pcie_device() {
689                // For now, just ignore writes to extended config space
690                CommonHeaderResult::Handled
691            } else {
692                tracelimit::warn_ratelimited!(
693                    offset,
694                    value = val,
695                    "unhandled extended config space write"
696                );
697                CommonHeaderResult::Failed(IoError::InvalidRegister)
698            }
699        } else {
700            CommonHeaderResult::Failed(IoError::InvalidRegister)
701        }
702    }
703
704    // ===== Utility and Query Functions =====
705
706    /// Finds a BAR + offset by address.
707    pub fn find_bar(&self, address: u64) -> Option<(u8, u16)> {
708        self.active_bars.find(address)
709    }
710
711    /// Check if this device is a PCIe device by looking for the PCI Express capability.
712    pub fn is_pcie_device(&self) -> bool {
713        self.capabilities
714            .iter()
715            .any(|cap| cap.capability_id() == CapabilityId::PCI_EXPRESS)
716    }
717
718    /// Get capability index and offset for a given offset
719    fn get_capability_index_and_offset(&self, offset: u16) -> Option<(usize, u16)> {
720        let mut cap_offset = 0;
721        for i in 0..self.capabilities.len() {
722            let cap_size = self.capabilities[i].len() as u16;
723            if offset < cap_offset + cap_size {
724                return Some((i, offset - cap_offset));
725            }
726            cap_offset += cap_size;
727        }
728        None
729    }
730
731    /// Check if an offset corresponds to a BAR register
732    fn is_bar_offset(&self, offset: u16) -> bool {
733        // Type 0: BAR0-BAR5 (0x10-0x27), Type 1: BAR0-BAR1 (0x10-0x17)
734        let bar_start = cfg_space::HeaderType00::BAR0.0;
735        let bar_end = bar_start + (N as u16) * 4;
736        (bar_start..bar_end).contains(&offset) && offset.is_multiple_of(4)
737    }
738
739    /// Get the BAR index for a given offset
740    fn get_bar_index(&self, offset: u16) -> usize {
741        ((offset - cfg_space::HeaderType00::BAR0.0) / 4) as usize
742    }
743
744    /// Get BAR masks (for testing only)
745    #[cfg(test)]
746    pub fn bar_masks(&self) -> &[u32; N] {
747        &self.bar_masks
748    }
749}
750
751#[derive(Debug, Inspect)]
752struct ConfigSpaceType0EmulatorState {
753    /// A read/write register that doesn't matter in virtualized contexts
754    latency_timer: u8,
755}
756
757impl ConfigSpaceType0EmulatorState {
758    fn new() -> Self {
759        Self { latency_timer: 0 }
760    }
761}
762
763/// Emulator for the standard Type 0 PCI configuration space header.
764#[derive(Inspect)]
765pub struct ConfigSpaceType0Emulator {
766    /// The common header emulator that handles shared functionality
767    #[inspect(flatten)]
768    common: ConfigSpaceCommonHeaderEmulatorType0,
769    /// Type 0 specific state
770    state: ConfigSpaceType0EmulatorState,
771}
772
773mod inspect_helpers {
774    use super::*;
775
776    pub(crate) fn bars_generic<const N: usize>(bars: &[u32; N]) -> impl Inspect + '_ {
777        inspect::AsHex(inspect::iter_by_index(bars).prefix("bar"))
778    }
779}
780
781/// Different kinds of memory that a BAR can be backed by
782#[derive(Inspect)]
783#[inspect(tag = "kind")]
784pub enum BarMemoryKind {
785    /// BAR memory is routed to the device's `MmioIntercept` handler
786    Intercept(#[inspect(rename = "handle")] Box<dyn ControlMmioIntercept>),
787    /// BAR memory is routed to a shared memory region
788    SharedMem(#[inspect(skip)] Box<dyn MappableGuestMemory>),
789    /// **TESTING ONLY** BAR memory isn't backed by anything!
790    Dummy,
791}
792
793impl std::fmt::Debug for BarMemoryKind {
794    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
795        match self {
796            Self::Intercept(control) => {
797                write!(f, "Intercept(region_name: {}, ..)", control.region_name())
798            }
799            Self::SharedMem(_) => write!(f, "Mmap(..)"),
800            Self::Dummy => write!(f, "Dummy"),
801        }
802    }
803}
804
805impl BarMemoryKind {
806    fn map_to_guest(&mut self, gpa: u64) -> std::io::Result<()> {
807        match self {
808            BarMemoryKind::Intercept(control) => {
809                control.map(gpa);
810                Ok(())
811            }
812            BarMemoryKind::SharedMem(control) => control.map_to_guest(gpa, true),
813            BarMemoryKind::Dummy => Ok(()),
814        }
815    }
816
817    fn unmap_from_guest(&mut self) {
818        match self {
819            BarMemoryKind::Intercept(control) => control.unmap(),
820            BarMemoryKind::SharedMem(control) => control.unmap_from_guest(),
821            BarMemoryKind::Dummy => {}
822        }
823    }
824}
825
826/// Container type that describes a device's available BARs
827// TODO: support more advanced BAR configurations
828// e.g: mixed 32-bit and 64-bit
829// e.g: IO space BARs
830#[derive(Debug)]
831pub struct DeviceBars {
832    bars: [Option<(u64, BarMemoryKind)>; 6],
833}
834
835impl DeviceBars {
836    /// Create a new instance of [`DeviceBars`]
837    pub fn new() -> DeviceBars {
838        DeviceBars {
839            bars: Default::default(),
840        }
841    }
842
843    /// Set BAR0
844    pub fn bar0(mut self, len: u64, memory: BarMemoryKind) -> Self {
845        self.bars[0] = Some((len, memory));
846        self
847    }
848
849    /// Set BAR2
850    pub fn bar2(mut self, len: u64, memory: BarMemoryKind) -> Self {
851        self.bars[2] = Some((len, memory));
852        self
853    }
854
855    /// Set BAR4
856    pub fn bar4(mut self, len: u64, memory: BarMemoryKind) -> Self {
857        self.bars[4] = Some((len, memory));
858        self
859    }
860}
861
862impl ConfigSpaceType0Emulator {
863    /// Create a new [`ConfigSpaceType0Emulator`]
864    pub fn new(
865        hardware_ids: HardwareIds,
866        capabilities: Vec<Box<dyn PciCapability>>,
867        bars: DeviceBars,
868    ) -> Self {
869        let common = ConfigSpaceCommonHeaderEmulator::new(hardware_ids, capabilities, bars);
870
871        Self {
872            common,
873            state: ConfigSpaceType0EmulatorState::new(),
874        }
875    }
876
877    /// If the device is multi-function, enable bit 7 in the Header register.
878    pub fn with_multi_function_bit(mut self, bit: bool) -> Self {
879        self.common = self.common.with_multi_function_bit(bit);
880        self
881    }
882
883    /// If using legacy INT#x interrupts: wire a LineInterrupt to one of the 4
884    /// INT#x pins, returning an object that manages configuration space bits
885    /// when the device sets the interrupt level.
886    pub fn set_interrupt_pin(
887        &mut self,
888        pin: PciInterruptPin,
889        line: LineInterrupt,
890    ) -> Arc<IntxInterrupt> {
891        self.common.set_interrupt_pin(pin, line)
892    }
893
894    /// Resets the configuration space state.
895    pub fn reset(&mut self) {
896        self.common.reset();
897        self.state = ConfigSpaceType0EmulatorState::new();
898    }
899
900    /// Read from the config space. `offset` must be 32-bit aligned.
901    pub fn read_u32(&self, offset: u16, value: &mut u32) -> IoResult {
902        use cfg_space::HeaderType00;
903
904        // First try to handle with common header emulator
905        match self.common.read_u32(offset, value) {
906            CommonHeaderResult::Handled => return IoResult::Ok,
907            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
908            CommonHeaderResult::Unhandled => {
909                // Continue with Type 0 specific handling
910            }
911        }
912
913        // Handle Type 0 specific registers
914        *value = match HeaderType00(offset) {
915            HeaderType00::BIST_HEADER => {
916                let mut v = (self.state.latency_timer as u32) << 8;
917                if self.common.multi_function_bit() {
918                    // enable top-most bit of the header register
919                    v |= 0x80 << 16;
920                }
921                v
922            }
923            HeaderType00::CARDBUS_CIS_PTR => 0,
924            HeaderType00::SUBSYSTEM_ID => {
925                (self.common.hardware_ids().type0_sub_system_id as u32) << 16
926                    | self.common.hardware_ids().type0_sub_vendor_id as u32
927            }
928            HeaderType00::EXPANSION_ROM_BASE => 0,
929            HeaderType00::RESERVED => 0,
930            HeaderType00::LATENCY_INTERRUPT => {
931                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin, Bits 31-16: Latency Timer
932                (self.state.latency_timer as u32) << 16
933                    | (self.common.interrupt_pin() as u32) << 8
934                    | self.common.interrupt_line() as u32
935            }
936            _ => {
937                tracelimit::warn_ratelimited!(offset, "unexpected config space read");
938                return IoResult::Err(IoError::InvalidRegister);
939            }
940        };
941
942        IoResult::Ok
943    }
944
945    /// Write to the config space. `offset` must be 32-bit aligned.
946    pub fn write_u32(&mut self, offset: u16, val: u32) -> IoResult {
947        use cfg_space::HeaderType00;
948
949        // First try to handle with common header emulator
950        match self.common.write_u32(offset, val) {
951            CommonHeaderResult::Handled => return IoResult::Ok,
952            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
953            CommonHeaderResult::Unhandled => {
954                // Continue with Type 0 specific handling
955            }
956        }
957
958        // Handle Type 0 specific registers
959        match HeaderType00(offset) {
960            HeaderType00::BIST_HEADER => {
961                // BIST_HEADER - Type 0 specific handling
962                // For now, just ignore these writes (header type is read-only)
963            }
964            HeaderType00::LATENCY_INTERRUPT => {
965                // Bits 7-0: Interrupt Line (read/write)
966                // Bits 15-8: Interrupt Pin (read-only, ignore writes)
967                // Bits 31-16: Latency Timer (read/write)
968                self.common.set_interrupt_line((val & 0xff) as u8);
969                self.state.latency_timer = (val >> 16) as u8;
970            }
971            // all other base regs are noops
972            _ if offset < 0x40 && offset.is_multiple_of(4) => (),
973            _ => {
974                tracelimit::warn_ratelimited!(offset, value = val, "unexpected config space write");
975                return IoResult::Err(IoError::InvalidRegister);
976            }
977        }
978
979        IoResult::Ok
980    }
981
982    /// Finds a BAR + offset by address.
983    pub fn find_bar(&self, address: u64) -> Option<(u8, u16)> {
984        self.common.find_bar(address)
985    }
986
987    /// Checks if this device is a PCIe device by looking for the PCI Express capability.
988    pub fn is_pcie_device(&self) -> bool {
989        self.common.is_pcie_device()
990    }
991
992    /// Set the presence detect state for a hotplug-capable slot.
993    /// This method finds the PCIe Express capability and calls its set_presence_detect_state method.
994    /// If the PCIe Express capability is not found, the call is silently ignored.
995    ///
996    /// # Arguments
997    /// * `present` - true if a device is present in the slot, false if the slot is empty
998    pub fn set_presence_detect_state(&mut self, present: bool) {
999        for capability in self.common.capabilities_mut() {
1000            if let Some(pcie_cap) = capability.as_pci_express_mut() {
1001                pcie_cap.set_presence_detect_state(present);
1002                return;
1003            }
1004        }
1005
1006        // PCIe Express capability not found - silently ignore
1007    }
1008}
1009
1010#[derive(Debug, Inspect)]
1011struct ConfigSpaceType1EmulatorState {
1012    /// The subordinate bus number register. Software programs
1013    /// this register with the highest bus number below the bridge.
1014    #[inspect(hex)]
1015    subordinate_bus_number: u8,
1016    /// The secondary bus number register. Software programs
1017    /// this register with the bus number assigned to the secondary
1018    /// side of the bridge.
1019    #[inspect(hex)]
1020    secondary_bus_number: u8,
1021    /// The primary bus number register. This is unused for PCI Express but
1022    /// is supposed to be read/write for compability with legacy software.
1023    #[inspect(hex)]
1024    primary_bus_number: u8,
1025    /// The memory base register. Software programs the upper 12 bits of this
1026    /// register with the upper 12 bits of a 32-bit base address of MMIO assigned
1027    /// to the hierarchy under the bridge (the lower 20 bits are assumed to be 0s).
1028    #[inspect(hex)]
1029    memory_base: u16,
1030    /// The memory limit register. Software programs the upper 12 bits of this
1031    /// register with the upper 12 bits of a 32-bit limit address of MMIO assigned
1032    /// to the hierarchy under the bridge (the lower 20 bits are assumed to be 1s).
1033    #[inspect(hex)]
1034    memory_limit: u16,
1035    /// The prefetchable memory base register. Software programs the upper 12 bits of
1036    /// this register with bits 20:31 of the base address of the prefetchable MMIO
1037    /// window assigned to the hierarchy under the bridge. Bits 0:19 are assumed to
1038    /// be 0s.
1039    #[inspect(hex)]
1040    prefetch_base: u16,
1041    /// The prefetchable memory limit register. Software programs the upper 12 bits of
1042    /// this register with bits 20:31 of the limit address of the prefetchable MMIO
1043    /// window assigned to the hierarchy under the bridge. Bits 0:19 are assumed to
1044    /// be 1s.
1045    #[inspect(hex)]
1046    prefetch_limit: u16,
1047    /// The prefetchable memory base upper 32 bits register. When the bridge supports
1048    /// 64-bit addressing for prefetchable memory, software programs this register
1049    /// with the upper 32 bits of the base address of the prefetchable MMIO window
1050    /// assigned to the hierarchy under the bridge.
1051    #[inspect(hex)]
1052    prefetch_base_upper: u32,
1053    /// The prefetchable memory limit upper 32 bits register. When the bridge supports
1054    /// 64-bit addressing for prefetchable memory, software programs this register
1055    /// with the upper 32 bits of the base address of the prefetchable MMIO window
1056    /// assigned to the hierarchy under the bridge.
1057    #[inspect(hex)]
1058    prefetch_limit_upper: u32,
1059    /// The bridge control register. Contains various control bits for bridge behavior
1060    /// such as secondary bus reset, VGA enable, etc.
1061    #[inspect(hex)]
1062    bridge_control: u16,
1063}
1064
1065impl ConfigSpaceType1EmulatorState {
1066    fn new() -> Self {
1067        Self {
1068            subordinate_bus_number: 0,
1069            secondary_bus_number: 0,
1070            primary_bus_number: 0,
1071            memory_base: 0,
1072            memory_limit: 0,
1073            prefetch_base: 0,
1074            prefetch_limit: 0,
1075            prefetch_base_upper: 0,
1076            prefetch_limit_upper: 0,
1077            bridge_control: 0,
1078        }
1079    }
1080}
1081
1082/// Emulator for the standard Type 1 PCI configuration space header.
1083#[derive(Inspect)]
1084pub struct ConfigSpaceType1Emulator {
1085    /// The common header emulator that handles shared functionality
1086    #[inspect(flatten)]
1087    common: ConfigSpaceCommonHeaderEmulatorType1,
1088    /// Type 1 specific state
1089    state: ConfigSpaceType1EmulatorState,
1090}
1091
1092impl ConfigSpaceType1Emulator {
1093    /// Create a new [`ConfigSpaceType1Emulator`]
1094    pub fn new(hardware_ids: HardwareIds, capabilities: Vec<Box<dyn PciCapability>>) -> Self {
1095        let common =
1096            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, capabilities, DeviceBars::new());
1097
1098        Self {
1099            common,
1100            state: ConfigSpaceType1EmulatorState::new(),
1101        }
1102    }
1103
1104    /// Resets the configuration space state.
1105    pub fn reset(&mut self) {
1106        self.common.reset();
1107        self.state = ConfigSpaceType1EmulatorState::new();
1108    }
1109
1110    /// Set the multi-function bit for this device.
1111    pub fn with_multi_function_bit(mut self, multi_function: bool) -> Self {
1112        self.common = self.common.with_multi_function_bit(multi_function);
1113        self
1114    }
1115
1116    /// Returns the range of bus numbers the bridge is programmed to decode.
1117    pub fn assigned_bus_range(&self) -> RangeInclusive<u8> {
1118        let secondary = self.state.secondary_bus_number;
1119        let subordinate = self.state.subordinate_bus_number;
1120        if secondary <= subordinate {
1121            secondary..=subordinate
1122        } else {
1123            0..=0
1124        }
1125    }
1126
1127    fn decode_memory_range(&self, base_register: u16, limit_register: u16) -> (u32, u32) {
1128        let base_addr = ((base_register & !0b1111) as u32) << 16;
1129        let limit_addr = ((limit_register & !0b1111) as u32) << 16 | 0xF_FFFF;
1130        (base_addr, limit_addr)
1131    }
1132
1133    /// If memory decoding is currently enabled, and the memory window assignment is valid,
1134    /// returns the 32-bit memory addresses the bridge is programmed to decode.
1135    pub fn assigned_memory_range(&self) -> Option<RangeInclusive<u32>> {
1136        let (base_addr, limit_addr) =
1137            self.decode_memory_range(self.state.memory_base, self.state.memory_limit);
1138        if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1139            Some(base_addr..=limit_addr)
1140        } else {
1141            None
1142        }
1143    }
1144
1145    /// If memory decoding is currently enabled, and the prefetchable memory window assignment
1146    /// is valid, returns the 64-bit prefetchable memory addresses the bridge is programmed to decode.
1147    pub fn assigned_prefetch_range(&self) -> Option<RangeInclusive<u64>> {
1148        let (base_low, limit_low) =
1149            self.decode_memory_range(self.state.prefetch_base, self.state.prefetch_limit);
1150        let base_addr = (self.state.prefetch_base_upper as u64) << 32 | base_low as u64;
1151        let limit_addr = (self.state.prefetch_limit_upper as u64) << 32 | limit_low as u64;
1152        if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1153            Some(base_addr..=limit_addr)
1154        } else {
1155            None
1156        }
1157    }
1158
1159    /// Read from the config space. `offset` must be 32-bit aligned.
1160    pub fn read_u32(&self, offset: u16, value: &mut u32) -> IoResult {
1161        use cfg_space::HeaderType01;
1162
1163        // First try to handle with common header emulator
1164        match self.common.read_u32(offset, value) {
1165            CommonHeaderResult::Handled => return IoResult::Ok,
1166            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1167            CommonHeaderResult::Unhandled => {
1168                // Continue with Type 1 specific handling
1169            }
1170        }
1171
1172        // Handle Type 1 specific registers
1173        *value = match HeaderType01(offset) {
1174            HeaderType01::BIST_HEADER => {
1175                // Header type 01 with optional multi-function bit
1176                if self.common.multi_function_bit() {
1177                    0x00810000 // Header type 01 with multi-function bit (bit 23)
1178                } else {
1179                    0x00010000 // Header type 01 without multi-function bit
1180                }
1181            }
1182            HeaderType01::LATENCY_BUS_NUMBERS => {
1183                (self.state.subordinate_bus_number as u32) << 16
1184                    | (self.state.secondary_bus_number as u32) << 8
1185                    | self.state.primary_bus_number as u32
1186            }
1187            HeaderType01::SEC_STATUS_IO_RANGE => 0,
1188            HeaderType01::MEMORY_RANGE => {
1189                (self.state.memory_limit as u32) << 16 | self.state.memory_base as u32
1190            }
1191            HeaderType01::PREFETCH_RANGE => {
1192                // Set the low bit in both the limit and base registers to indicate
1193                // support for 64-bit addressing.
1194                ((self.state.prefetch_limit | 0b0001) as u32) << 16
1195                    | (self.state.prefetch_base | 0b0001) as u32
1196            }
1197            HeaderType01::PREFETCH_BASE_UPPER => self.state.prefetch_base_upper,
1198            HeaderType01::PREFETCH_LIMIT_UPPER => self.state.prefetch_limit_upper,
1199            HeaderType01::IO_RANGE_UPPER => 0,
1200            HeaderType01::EXPANSION_ROM_BASE => 0,
1201            HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1202                // Read interrupt line from common header and bridge control from state
1203                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin (0), Bits 31-16: Bridge Control
1204                (self.state.bridge_control as u32) << 16 | self.common.interrupt_line() as u32
1205            }
1206            _ => {
1207                tracelimit::warn_ratelimited!(offset, "unexpected config space read");
1208                return IoResult::Err(IoError::InvalidRegister);
1209            }
1210        };
1211
1212        IoResult::Ok
1213    }
1214
1215    /// Write to the config space. `offset` must be 32-bit aligned.
1216    pub fn write_u32(&mut self, offset: u16, val: u32) -> IoResult {
1217        use cfg_space::HeaderType01;
1218
1219        // First try to handle with common header emulator
1220        match self.common.write_u32(offset, val) {
1221            CommonHeaderResult::Handled => return IoResult::Ok,
1222            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1223            CommonHeaderResult::Unhandled => {
1224                // Continue with Type 1 specific handling
1225            }
1226        }
1227
1228        // Handle Type 1 specific registers
1229        match HeaderType01(offset) {
1230            HeaderType01::BIST_HEADER => {
1231                // BIST_HEADER - Type 1 specific handling
1232                // For now, just ignore these writes (latency timer would go here if supported)
1233            }
1234            HeaderType01::LATENCY_BUS_NUMBERS => {
1235                self.state.subordinate_bus_number = (val >> 16) as u8;
1236                self.state.secondary_bus_number = (val >> 8) as u8;
1237                self.state.primary_bus_number = val as u8;
1238            }
1239            HeaderType01::MEMORY_RANGE => {
1240                self.state.memory_base = val as u16;
1241                self.state.memory_limit = (val >> 16) as u16;
1242            }
1243            HeaderType01::PREFETCH_RANGE => {
1244                self.state.prefetch_base = val as u16;
1245                self.state.prefetch_limit = (val >> 16) as u16;
1246            }
1247            HeaderType01::PREFETCH_BASE_UPPER => {
1248                self.state.prefetch_base_upper = val;
1249            }
1250            HeaderType01::PREFETCH_LIMIT_UPPER => {
1251                self.state.prefetch_limit_upper = val;
1252            }
1253            HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1254                // Delegate interrupt line writes to common header and store bridge control
1255                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin (ignored), Bits 31-16: Bridge Control
1256                self.common.set_interrupt_line((val & 0xff) as u8);
1257                self.state.bridge_control = (val >> 16) as u16;
1258            }
1259            // all other base regs are noops
1260            _ if offset < 0x40 && offset.is_multiple_of(4) => (),
1261            _ => {
1262                tracelimit::warn_ratelimited!(offset, value = val, "unexpected config space write");
1263                return IoResult::Err(IoError::InvalidRegister);
1264            }
1265        }
1266
1267        IoResult::Ok
1268    }
1269
1270    /// Checks if this device is a PCIe device by looking for the PCI Express capability.
1271    pub fn is_pcie_device(&self) -> bool {
1272        self.common.is_pcie_device()
1273    }
1274
1275    /// Set the presence detect state for the slot.
1276    /// This method finds the PCIe Express capability and calls its set_presence_detect_state method.
1277    /// If the PCIe Express capability is not found, the call is silently ignored.
1278    ///
1279    /// # Arguments
1280    /// * `present` - true if a device is present in the slot, false if the slot is empty
1281    pub fn set_presence_detect_state(&mut self, present: bool) {
1282        // Find the PCIe Express capability
1283        for cap in self.common.capabilities_mut() {
1284            if cap.capability_id() == CapabilityId::PCI_EXPRESS {
1285                // Downcast to PciExpressCapability and call set_presence_detect_state
1286                if let Some(pcie_cap) = cap.as_pci_express_mut() {
1287                    pcie_cap.set_presence_detect_state(present);
1288                    return;
1289                }
1290            }
1291        }
1292        // If no PCIe Express capability is found, silently ignore the call
1293    }
1294}
1295
1296mod save_restore {
1297    use super::*;
1298    use thiserror::Error;
1299    use vmcore::save_restore::RestoreError;
1300    use vmcore::save_restore::SaveError;
1301    use vmcore::save_restore::SaveRestore;
1302
1303    mod state {
1304        use mesh::payload::Protobuf;
1305        use vmcore::save_restore::SavedStateBlob;
1306        use vmcore::save_restore::SavedStateRoot;
1307
1308        /// Unified saved state for both Type 0 and Type 1 PCI configuration space emulators.
1309        /// Type 1 specific fields (mesh indices 6-15) will be ignored when restoring Type 0 devices,
1310        /// and will have default values (0) when restoring old save state to Type 1 devices.
1311        #[derive(Protobuf, SavedStateRoot)]
1312        #[mesh(package = "pci.cfg_space_emu")]
1313        pub struct SavedState {
1314            // Common fields (used by both Type 0 and Type 1)
1315            #[mesh(1)]
1316            pub command: u16,
1317            #[mesh(2)]
1318            pub base_addresses: [u32; 6],
1319            #[mesh(3)]
1320            pub interrupt_line: u8,
1321            #[mesh(4)]
1322            pub latency_timer: u8,
1323            #[mesh(5)]
1324            pub capabilities: Vec<(String, SavedStateBlob)>,
1325
1326            // Type 1 specific fields (bridge devices)
1327            // These fields default to 0 for backward compatibility with old save state
1328            #[mesh(6)]
1329            pub subordinate_bus_number: u8,
1330            #[mesh(7)]
1331            pub secondary_bus_number: u8,
1332            #[mesh(8)]
1333            pub primary_bus_number: u8,
1334            #[mesh(9)]
1335            pub memory_base: u16,
1336            #[mesh(10)]
1337            pub memory_limit: u16,
1338            #[mesh(11)]
1339            pub prefetch_base: u16,
1340            #[mesh(12)]
1341            pub prefetch_limit: u16,
1342            #[mesh(13)]
1343            pub prefetch_base_upper: u32,
1344            #[mesh(14)]
1345            pub prefetch_limit_upper: u32,
1346            #[mesh(15)]
1347            pub bridge_control: u16,
1348        }
1349    }
1350
1351    #[derive(Debug, Error)]
1352    enum ConfigSpaceRestoreError {
1353        #[error("found invalid config bits in saved state")]
1354        InvalidConfigBits,
1355        #[error("found unexpected capability {0}")]
1356        InvalidCap(String),
1357    }
1358
1359    impl SaveRestore for ConfigSpaceType0Emulator {
1360        type SavedState = state::SavedState;
1361
1362        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1363            let ConfigSpaceType0EmulatorState { latency_timer } = self.state;
1364
1365            let saved_state = state::SavedState {
1366                command: self.common.command().into_bits(),
1367                base_addresses: *self.common.base_addresses(),
1368                interrupt_line: self.common.interrupt_line(),
1369                latency_timer,
1370                capabilities: self
1371                    .common
1372                    .capabilities_mut()
1373                    .iter_mut()
1374                    .map(|cap| {
1375                        let id = cap.label().to_owned();
1376                        Ok((id, cap.save()?))
1377                    })
1378                    .collect::<Result<_, _>>()?,
1379                // Type 1 specific fields - not used for Type 0
1380                subordinate_bus_number: 0,
1381                secondary_bus_number: 0,
1382                primary_bus_number: 0,
1383                memory_base: 0,
1384                memory_limit: 0,
1385                prefetch_base: 0,
1386                prefetch_limit: 0,
1387                prefetch_base_upper: 0,
1388                prefetch_limit_upper: 0,
1389                bridge_control: 0,
1390            };
1391
1392            Ok(saved_state)
1393        }
1394
1395        fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1396            let state::SavedState {
1397                command,
1398                base_addresses,
1399                interrupt_line,
1400                latency_timer,
1401                capabilities,
1402                // Type 1 specific fields - ignored for Type 0
1403                subordinate_bus_number: _,
1404                secondary_bus_number: _,
1405                primary_bus_number: _,
1406                memory_base: _,
1407                memory_limit: _,
1408                prefetch_base: _,
1409                prefetch_limit: _,
1410                prefetch_base_upper: _,
1411                prefetch_limit_upper: _,
1412                bridge_control: _,
1413            } = state;
1414
1415            self.state = ConfigSpaceType0EmulatorState { latency_timer };
1416
1417            self.common.set_base_addresses(&base_addresses);
1418            self.common.set_interrupt_line(interrupt_line);
1419            self.common
1420                .set_command(cfg_space::Command::from_bits(command));
1421
1422            if command & !SUPPORTED_COMMAND_BITS != 0 {
1423                return Err(RestoreError::InvalidSavedState(
1424                    ConfigSpaceRestoreError::InvalidConfigBits.into(),
1425                ));
1426            }
1427
1428            self.common.sync_command_register(self.common.command());
1429
1430            for (id, entry) in capabilities {
1431                tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1432
1433                // yes, yes, this is O(n^2), but devices never have more than a
1434                // handful of caps, so it's totally fine.
1435                let mut restored = false;
1436                for cap in self.common.capabilities_mut() {
1437                    if cap.label() == id {
1438                        cap.restore(entry)?;
1439                        restored = true;
1440                        break;
1441                    }
1442                }
1443
1444                if !restored {
1445                    return Err(RestoreError::InvalidSavedState(
1446                        ConfigSpaceRestoreError::InvalidCap(id).into(),
1447                    ));
1448                }
1449            }
1450
1451            Ok(())
1452        }
1453    }
1454
1455    impl SaveRestore for ConfigSpaceType1Emulator {
1456        type SavedState = state::SavedState;
1457
1458        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1459            let ConfigSpaceType1EmulatorState {
1460                subordinate_bus_number,
1461                secondary_bus_number,
1462                primary_bus_number,
1463                memory_base,
1464                memory_limit,
1465                prefetch_base,
1466                prefetch_limit,
1467                prefetch_base_upper,
1468                prefetch_limit_upper,
1469                bridge_control,
1470            } = self.state;
1471
1472            // Pad base_addresses to 6 elements for saved state (Type 1 uses 2 BARs)
1473            let type1_base_addresses = self.common.base_addresses();
1474            let mut saved_base_addresses = [0u32; 6];
1475            saved_base_addresses[0] = type1_base_addresses[0];
1476            saved_base_addresses[1] = type1_base_addresses[1];
1477
1478            let saved_state = state::SavedState {
1479                command: self.common.command().into_bits(),
1480                base_addresses: saved_base_addresses,
1481                interrupt_line: self.common.interrupt_line(),
1482                latency_timer: 0, // Not used for Type 1
1483                capabilities: self
1484                    .common
1485                    .capabilities_mut()
1486                    .iter_mut()
1487                    .map(|cap| {
1488                        let id = cap.label().to_owned();
1489                        Ok((id, cap.save()?))
1490                    })
1491                    .collect::<Result<_, _>>()?,
1492                // Type 1 specific fields
1493                subordinate_bus_number,
1494                secondary_bus_number,
1495                primary_bus_number,
1496                memory_base,
1497                memory_limit,
1498                prefetch_base,
1499                prefetch_limit,
1500                prefetch_base_upper,
1501                prefetch_limit_upper,
1502                bridge_control,
1503            };
1504
1505            Ok(saved_state)
1506        }
1507
1508        fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1509            let state::SavedState {
1510                command,
1511                base_addresses,
1512                interrupt_line,
1513                latency_timer: _, // Not used for Type 1
1514                capabilities,
1515                subordinate_bus_number,
1516                secondary_bus_number,
1517                primary_bus_number,
1518                memory_base,
1519                memory_limit,
1520                prefetch_base,
1521                prefetch_limit,
1522                prefetch_base_upper,
1523                prefetch_limit_upper,
1524                bridge_control,
1525            } = state;
1526
1527            self.state = ConfigSpaceType1EmulatorState {
1528                subordinate_bus_number,
1529                secondary_bus_number,
1530                primary_bus_number,
1531                memory_base,
1532                memory_limit,
1533                prefetch_base,
1534                prefetch_limit,
1535                prefetch_base_upper,
1536                prefetch_limit_upper,
1537                bridge_control,
1538            };
1539
1540            // Pad base_addresses to 6 elements for common header (Type 1 uses 2 BARs)
1541            let mut full_base_addresses = [0u32; 6];
1542            for (i, &addr) in base_addresses.iter().enumerate().take(2) {
1543                full_base_addresses[i] = addr;
1544            }
1545            self.common
1546                .set_base_addresses(&[full_base_addresses[0], full_base_addresses[1]]);
1547            self.common.set_interrupt_line(interrupt_line);
1548            self.common
1549                .set_command(cfg_space::Command::from_bits(command));
1550
1551            if command & !SUPPORTED_COMMAND_BITS != 0 {
1552                return Err(RestoreError::InvalidSavedState(
1553                    ConfigSpaceRestoreError::InvalidConfigBits.into(),
1554                ));
1555            }
1556
1557            self.common.sync_command_register(self.common.command());
1558
1559            for (id, entry) in capabilities {
1560                tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1561
1562                let mut restored = false;
1563                for cap in self.common.capabilities_mut() {
1564                    if cap.label() == id {
1565                        cap.restore(entry)?;
1566                        restored = true;
1567                        break;
1568                    }
1569                }
1570
1571                if !restored {
1572                    return Err(RestoreError::InvalidSavedState(
1573                        ConfigSpaceRestoreError::InvalidCap(id).into(),
1574                    ));
1575                }
1576            }
1577
1578            Ok(())
1579        }
1580    }
1581}
1582
1583#[cfg(test)]
1584mod tests {
1585    use super::*;
1586    use crate::capabilities::pci_express::PciExpressCapability;
1587    use crate::capabilities::read_only::ReadOnlyCapability;
1588    use crate::spec::caps::pci_express::DevicePortType;
1589    use crate::spec::hwid::ClassCode;
1590    use crate::spec::hwid::ProgrammingInterface;
1591    use crate::spec::hwid::Subclass;
1592
1593    fn create_type0_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType0Emulator {
1594        ConfigSpaceType0Emulator::new(
1595            HardwareIds {
1596                vendor_id: 0x1111,
1597                device_id: 0x2222,
1598                revision_id: 1,
1599                prog_if: ProgrammingInterface::NONE,
1600                sub_class: Subclass::NONE,
1601                base_class: ClassCode::UNCLASSIFIED,
1602                type0_sub_vendor_id: 0x3333,
1603                type0_sub_system_id: 0x4444,
1604            },
1605            caps,
1606            DeviceBars::new(),
1607        )
1608    }
1609
1610    fn create_type1_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType1Emulator {
1611        ConfigSpaceType1Emulator::new(
1612            HardwareIds {
1613                vendor_id: 0x1111,
1614                device_id: 0x2222,
1615                revision_id: 1,
1616                prog_if: ProgrammingInterface::NONE,
1617                sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1618                base_class: ClassCode::BRIDGE,
1619                type0_sub_vendor_id: 0,
1620                type0_sub_system_id: 0,
1621            },
1622            caps,
1623        )
1624    }
1625
1626    fn read_cfg(emulator: &ConfigSpaceType1Emulator, offset: u16) -> u32 {
1627        let mut val = 0;
1628        emulator.read_u32(offset, &mut val).unwrap();
1629        val
1630    }
1631
1632    #[test]
1633    fn test_type1_probe() {
1634        let emu = create_type1_emulator(vec![]);
1635        assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1636        assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0); // Capabilities pointer
1637
1638        let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1639        assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1640        assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0x10_0000); // Capabilities pointer
1641    }
1642
1643    #[test]
1644    fn test_type1_bus_number_assignment() {
1645        let mut emu = create_type1_emulator(vec![]);
1646
1647        // The bus number (and latency timer) registers are
1648        // all default 0.
1649        assert_eq!(read_cfg(&emu, 0x18), 0);
1650        assert_eq!(emu.assigned_bus_range(), 0..=0);
1651
1652        // The bus numbers can be programmed one by one,
1653        // and the range may not be valid during the middle
1654        // of allocation.
1655        emu.write_u32(0x18, 0x0000_1000).unwrap();
1656        assert_eq!(read_cfg(&emu, 0x18), 0x0000_1000);
1657        assert_eq!(emu.assigned_bus_range(), 0..=0);
1658        emu.write_u32(0x18, 0x0012_1000).unwrap();
1659        assert_eq!(read_cfg(&emu, 0x18), 0x0012_1000);
1660        assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1661
1662        // The primary bus number register is read/write for compatability
1663        // but unused.
1664        emu.write_u32(0x18, 0x0012_1033).unwrap();
1665        assert_eq!(read_cfg(&emu, 0x18), 0x0012_1033);
1666        assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1667
1668        // Software can also just write the entire 4byte value at once
1669        emu.write_u32(0x18, 0x0047_4411).unwrap();
1670        assert_eq!(read_cfg(&emu, 0x18), 0x0047_4411);
1671        assert_eq!(emu.assigned_bus_range(), 0x44..=0x47);
1672
1673        // The subordinate bus number can equal the secondary bus number...
1674        emu.write_u32(0x18, 0x0088_8800).unwrap();
1675        assert_eq!(emu.assigned_bus_range(), 0x88..=0x88);
1676
1677        // ... but it cannot be less, that's a confused guest OS.
1678        emu.write_u32(0x18, 0x0087_8800).unwrap();
1679        assert_eq!(emu.assigned_bus_range(), 0..=0);
1680    }
1681
1682    #[test]
1683    fn test_type1_memory_assignment() {
1684        const MMIO_ENABLED: u32 = 0x0000_0002;
1685        const MMIO_DISABLED: u32 = 0x0000_0000;
1686
1687        let mut emu = create_type1_emulator(vec![]);
1688        assert!(emu.assigned_memory_range().is_none());
1689
1690        // The guest can write whatever it wants while MMIO
1691        // is disabled.
1692        emu.write_u32(0x20, 0xDEAD_BEEF).unwrap();
1693        assert!(emu.assigned_memory_range().is_none());
1694
1695        // The guest can program a valid resource assignment...
1696        emu.write_u32(0x20, 0xFFF0_FF00).unwrap();
1697        assert!(emu.assigned_memory_range().is_none());
1698        // ... enable memory decoding...
1699        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1700        assert_eq!(emu.assigned_memory_range(), Some(0xFF00_0000..=0xFFFF_FFFF));
1701        // ... then disable memory decoding it.
1702        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1703        assert!(emu.assigned_memory_range().is_none());
1704
1705        // Setting memory base equal to memory limit is a valid 1MB range.
1706        emu.write_u32(0x20, 0xBBB0_BBB0).unwrap();
1707        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1708        assert_eq!(emu.assigned_memory_range(), Some(0xBBB0_0000..=0xBBBF_FFFF));
1709        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1710        assert!(emu.assigned_memory_range().is_none());
1711
1712        // The guest can try to program an invalid assignment (base > limit), we
1713        // just won't decode it.
1714        emu.write_u32(0x20, 0xAA00_BB00).unwrap();
1715        assert!(emu.assigned_memory_range().is_none());
1716        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1717        assert!(emu.assigned_memory_range().is_none());
1718        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1719        assert!(emu.assigned_memory_range().is_none());
1720    }
1721
1722    #[test]
1723    fn test_type1_prefetch_assignment() {
1724        const MMIO_ENABLED: u32 = 0x0000_0002;
1725        const MMIO_DISABLED: u32 = 0x0000_0000;
1726
1727        let mut emu = create_type1_emulator(vec![]);
1728        assert!(emu.assigned_prefetch_range().is_none());
1729
1730        // The guest can program a valid prefetch range...
1731        emu.write_u32(0x24, 0xFFF0_FF00).unwrap(); // limit + base
1732        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // base upper
1733        emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); // limit upper
1734        assert!(emu.assigned_prefetch_range().is_none());
1735        // ... enable memory decoding...
1736        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1737        assert_eq!(
1738            emu.assigned_prefetch_range(),
1739            Some(0x00AA_BBCC_FF00_0000..=0x00DD_EEFF_FFFF_FFFF)
1740        );
1741        // ... then disable memory decoding it.
1742        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1743        assert!(emu.assigned_prefetch_range().is_none());
1744
1745        // The validity of the assignment is determined using the combined 64-bit
1746        // address, not the lower bits or the upper bits in isolation.
1747
1748        // Lower bits of the limit are greater than the lower bits of the
1749        // base, but the upper bits make that valid.
1750        emu.write_u32(0x24, 0xFF00_FFF0).unwrap(); // limit + base
1751        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // base upper
1752        emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); // limit upper
1753        assert!(emu.assigned_prefetch_range().is_none());
1754        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1755        assert_eq!(
1756            emu.assigned_prefetch_range(),
1757            Some(0x00AA_BBCC_FFF0_0000..=0x00DD_EEFF_FF0F_FFFF)
1758        );
1759        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1760        assert!(emu.assigned_prefetch_range().is_none());
1761
1762        // The base can equal the limit, which is a valid 1MB range.
1763        emu.write_u32(0x24, 0xDD00_DD00).unwrap(); // limit + base
1764        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // base upper
1765        emu.write_u32(0x2C, 0x00AA_BBCC).unwrap(); // limit upper
1766        assert!(emu.assigned_prefetch_range().is_none());
1767        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1768        assert_eq!(
1769            emu.assigned_prefetch_range(),
1770            Some(0x00AA_BBCC_DD00_0000..=0x00AA_BBCC_DD0F_FFFF)
1771        );
1772        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1773        assert!(emu.assigned_prefetch_range().is_none());
1774    }
1775
1776    #[test]
1777    fn test_type1_is_pcie_device() {
1778        // Test Type 1 device without PCIe capability
1779        let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1780        assert!(!emu.is_pcie_device());
1781
1782        // Test Type 1 device with PCIe capability
1783        let emu = create_type1_emulator(vec![Box::new(PciExpressCapability::new(
1784            DevicePortType::RootPort,
1785            None,
1786        ))]);
1787        assert!(emu.is_pcie_device());
1788
1789        // Test Type 1 device with multiple capabilities including PCIe
1790        let emu = create_type1_emulator(vec![
1791            Box::new(ReadOnlyCapability::new("foo", 0)),
1792            Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1793            Box::new(ReadOnlyCapability::new("bar", 0)),
1794        ]);
1795        assert!(emu.is_pcie_device());
1796    }
1797
1798    #[test]
1799    fn test_type0_is_pcie_device() {
1800        // Test Type 0 device without PCIe capability
1801        let emu = ConfigSpaceType0Emulator::new(
1802            HardwareIds {
1803                vendor_id: 0x1111,
1804                device_id: 0x2222,
1805                revision_id: 1,
1806                prog_if: ProgrammingInterface::NONE,
1807                sub_class: Subclass::NONE,
1808                base_class: ClassCode::UNCLASSIFIED,
1809                type0_sub_vendor_id: 0,
1810                type0_sub_system_id: 0,
1811            },
1812            vec![Box::new(ReadOnlyCapability::new("foo", 0))],
1813            DeviceBars::new(),
1814        );
1815        assert!(!emu.is_pcie_device());
1816
1817        // Test Type 0 device with PCIe capability
1818        let emu = ConfigSpaceType0Emulator::new(
1819            HardwareIds {
1820                vendor_id: 0x1111,
1821                device_id: 0x2222,
1822                revision_id: 1,
1823                prog_if: ProgrammingInterface::NONE,
1824                sub_class: Subclass::NONE,
1825                base_class: ClassCode::UNCLASSIFIED,
1826                type0_sub_vendor_id: 0,
1827                type0_sub_system_id: 0,
1828            },
1829            vec![Box::new(PciExpressCapability::new(
1830                DevicePortType::Endpoint,
1831                None,
1832            ))],
1833            DeviceBars::new(),
1834        );
1835        assert!(emu.is_pcie_device());
1836
1837        // Test Type 0 device with multiple capabilities including PCIe
1838        let emu = ConfigSpaceType0Emulator::new(
1839            HardwareIds {
1840                vendor_id: 0x1111,
1841                device_id: 0x2222,
1842                revision_id: 1,
1843                prog_if: ProgrammingInterface::NONE,
1844                sub_class: Subclass::NONE,
1845                base_class: ClassCode::UNCLASSIFIED,
1846                type0_sub_vendor_id: 0,
1847                type0_sub_system_id: 0,
1848            },
1849            vec![
1850                Box::new(ReadOnlyCapability::new("foo", 0)),
1851                Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1852                Box::new(ReadOnlyCapability::new("bar", 0)),
1853            ],
1854            DeviceBars::new(),
1855        );
1856        assert!(emu.is_pcie_device());
1857
1858        // Test Type 0 device with no capabilities
1859        let emu = ConfigSpaceType0Emulator::new(
1860            HardwareIds {
1861                vendor_id: 0x1111,
1862                device_id: 0x2222,
1863                revision_id: 1,
1864                prog_if: ProgrammingInterface::NONE,
1865                sub_class: Subclass::NONE,
1866                base_class: ClassCode::UNCLASSIFIED,
1867                type0_sub_vendor_id: 0,
1868                type0_sub_system_id: 0,
1869            },
1870            vec![],
1871            DeviceBars::new(),
1872        );
1873        assert!(!emu.is_pcie_device());
1874    }
1875
1876    #[test]
1877    fn test_capability_ids() {
1878        // Test that capabilities return the correct capability IDs
1879        let pcie_cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
1880        assert_eq!(pcie_cap.capability_id(), CapabilityId::PCI_EXPRESS);
1881
1882        let read_only_cap = ReadOnlyCapability::new("test", 0u32);
1883        assert_eq!(read_only_cap.capability_id(), CapabilityId::VENDOR_SPECIFIC);
1884    }
1885
1886    #[test]
1887    fn test_common_header_emulator_type0() {
1888        // Test the common header emulator with Type 0 configuration (6 BARs)
1889        let hardware_ids = HardwareIds {
1890            vendor_id: 0x1111,
1891            device_id: 0x2222,
1892            revision_id: 1,
1893            prog_if: ProgrammingInterface::NONE,
1894            sub_class: Subclass::NONE,
1895            base_class: ClassCode::UNCLASSIFIED,
1896            type0_sub_vendor_id: 0,
1897            type0_sub_system_id: 0,
1898        };
1899
1900        let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1901
1902        let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1903            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1904
1905        assert_eq!(common_emu.hardware_ids().vendor_id, 0x1111);
1906        assert_eq!(common_emu.hardware_ids().device_id, 0x2222);
1907        assert!(!common_emu.multi_function_bit());
1908        assert!(!common_emu.is_pcie_device());
1909        assert_ne!(common_emu.bar_masks()[0], 0); // Should have a mask for BAR0
1910    }
1911
1912    #[test]
1913    fn test_common_header_emulator_type1() {
1914        // Test the common header emulator with Type 1 configuration (2 BARs)
1915        let hardware_ids = HardwareIds {
1916            vendor_id: 0x3333,
1917            device_id: 0x4444,
1918            revision_id: 1,
1919            prog_if: ProgrammingInterface::NONE,
1920            sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1921            base_class: ClassCode::BRIDGE,
1922            type0_sub_vendor_id: 0,
1923            type0_sub_system_id: 0,
1924        };
1925
1926        let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1927
1928        let mut common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
1929            ConfigSpaceCommonHeaderEmulator::new(
1930                hardware_ids,
1931                vec![Box::new(PciExpressCapability::new(
1932                    DevicePortType::RootPort,
1933                    None,
1934                ))],
1935                bars,
1936            )
1937            .with_multi_function_bit(true);
1938
1939        assert_eq!(common_emu.hardware_ids().vendor_id, 0x3333);
1940        assert_eq!(common_emu.hardware_ids().device_id, 0x4444);
1941        assert!(common_emu.multi_function_bit());
1942        assert!(common_emu.is_pcie_device());
1943        assert_ne!(common_emu.bar_masks()[0], 0); // Should have a mask for BAR0
1944        assert_eq!(common_emu.bar_masks().len(), 2);
1945
1946        // Test reset functionality
1947        common_emu.reset();
1948        assert_eq!(common_emu.capabilities().len(), 1); // capabilities should still be there
1949    }
1950
1951    #[test]
1952    fn test_common_header_emulator_no_bars() {
1953        // Test the common header emulator with no BARs configured
1954        let hardware_ids = HardwareIds {
1955            vendor_id: 0x5555,
1956            device_id: 0x6666,
1957            revision_id: 1,
1958            prog_if: ProgrammingInterface::NONE,
1959            sub_class: Subclass::NONE,
1960            base_class: ClassCode::UNCLASSIFIED,
1961            type0_sub_vendor_id: 0,
1962            type0_sub_system_id: 0,
1963        };
1964
1965        // Create bars with no BARs configured
1966        let bars = DeviceBars::new();
1967
1968        let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1969            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1970
1971        assert_eq!(common_emu.hardware_ids().vendor_id, 0x5555);
1972        assert_eq!(common_emu.hardware_ids().device_id, 0x6666);
1973
1974        // All BAR masks should be 0 when no BARs are configured
1975        for &mask in common_emu.bar_masks() {
1976            assert_eq!(mask, 0);
1977        }
1978    }
1979
1980    #[test]
1981    fn test_common_header_emulator_type1_ignores_extra_bars() {
1982        // Test that Type 1 emulator ignores BARs beyond index 1 (only supports 2 BARs)
1983        let hardware_ids = HardwareIds {
1984            vendor_id: 0x7777,
1985            device_id: 0x8888,
1986            revision_id: 1,
1987            prog_if: ProgrammingInterface::NONE,
1988            sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1989            base_class: ClassCode::BRIDGE,
1990            type0_sub_vendor_id: 0,
1991            type0_sub_system_id: 0,
1992        };
1993
1994        // Configure BARs 0, 2, and 4 - Type 1 should only use BAR0 (and BAR1 as upper 32 bits)
1995        let bars = DeviceBars::new()
1996            .bar0(4096, BarMemoryKind::Dummy)
1997            .bar2(8192, BarMemoryKind::Dummy)
1998            .bar4(16384, BarMemoryKind::Dummy);
1999
2000        let common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
2001            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
2002
2003        assert_eq!(common_emu.hardware_ids().vendor_id, 0x7777);
2004        assert_eq!(common_emu.hardware_ids().device_id, 0x8888);
2005
2006        // Should have a mask for BAR0, and BAR1 should be the upper 32 bits (64-bit BAR)
2007        assert_ne!(common_emu.bar_masks()[0], 0); // BAR0 should be configured
2008        assert_ne!(common_emu.bar_masks()[1], 0); // BAR1 should be upper 32 bits of BAR0
2009        assert_eq!(common_emu.bar_masks().len(), 2); // Type 1 only has 2 BARs
2010
2011        // BAR2 and higher should be ignored (not accessible in Type 1 with N=2)
2012        // This demonstrates that extra BARs in DeviceBars are properly ignored
2013    }
2014
2015    #[test]
2016    fn test_common_header_extended_capabilities() {
2017        // Test common header emulator extended capabilities
2018        let mut common_emu_no_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2019            HardwareIds {
2020                vendor_id: 0x1111,
2021                device_id: 0x2222,
2022                revision_id: 1,
2023                prog_if: ProgrammingInterface::NONE,
2024                sub_class: Subclass::NONE,
2025                base_class: ClassCode::UNCLASSIFIED,
2026                type0_sub_vendor_id: 0,
2027                type0_sub_system_id: 0,
2028            },
2029            vec![Box::new(ReadOnlyCapability::new("foo", 0))],
2030            DeviceBars::new(),
2031        );
2032        assert!(!common_emu_no_pcie.is_pcie_device());
2033
2034        let mut common_emu_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2035            HardwareIds {
2036                vendor_id: 0x1111,
2037                device_id: 0x2222,
2038                revision_id: 1,
2039                prog_if: ProgrammingInterface::NONE,
2040                sub_class: Subclass::NONE,
2041                base_class: ClassCode::UNCLASSIFIED,
2042                type0_sub_vendor_id: 0,
2043                type0_sub_system_id: 0,
2044            },
2045            vec![Box::new(PciExpressCapability::new(
2046                DevicePortType::Endpoint,
2047                None,
2048            ))],
2049            DeviceBars::new(),
2050        );
2051        assert!(common_emu_pcie.is_pcie_device());
2052
2053        // Test reading extended capabilities - non-PCIe device should return error
2054        let mut value = 0;
2055        assert!(matches!(
2056            common_emu_no_pcie.read_extended_capabilities(0x100, &mut value),
2057            CommonHeaderResult::Failed(IoError::InvalidRegister)
2058        ));
2059
2060        // Test reading extended capabilities - PCIe device should return 0xffffffff
2061        let mut value = 0;
2062        assert!(matches!(
2063            common_emu_pcie.read_extended_capabilities(0x100, &mut value),
2064            CommonHeaderResult::Handled
2065        ));
2066        assert_eq!(value, 0xffffffff);
2067
2068        // Test writing extended capabilities - non-PCIe device should return error
2069        assert!(matches!(
2070            common_emu_no_pcie.write_extended_capabilities(0x100, 0x1234),
2071            CommonHeaderResult::Failed(IoError::InvalidRegister)
2072        ));
2073
2074        // Test writing extended capabilities - PCIe device should accept writes
2075        assert!(matches!(
2076            common_emu_pcie.write_extended_capabilities(0x100, 0x1234),
2077            CommonHeaderResult::Handled
2078        ));
2079
2080        // Test invalid offset ranges
2081        let mut value = 0;
2082        assert!(matches!(
2083            common_emu_pcie.read_extended_capabilities(0x99, &mut value),
2084            CommonHeaderResult::Failed(IoError::InvalidRegister)
2085        ));
2086        assert!(matches!(
2087            common_emu_pcie.read_extended_capabilities(0x1000, &mut value),
2088            CommonHeaderResult::Failed(IoError::InvalidRegister)
2089        ));
2090    }
2091
2092    #[test]
2093    fn test_type0_emulator_save_restore() {
2094        use vmcore::save_restore::SaveRestore;
2095
2096        // Test Type 0 emulator save/restore
2097        let mut emu = create_type0_emulator(vec![]);
2098
2099        // Modify some state by writing to command register
2100        emu.write_u32(0x04, 0x0007).unwrap(); // Enable some command bits
2101
2102        // Read back and verify
2103        let mut test_val = 0u32;
2104        emu.read_u32(0x04, &mut test_val).unwrap();
2105        assert_eq!(test_val & 0x0007, 0x0007);
2106
2107        // Write to latency timer / interrupt register
2108        emu.write_u32(0x3C, 0x0040_0000).unwrap(); // Set latency_timer
2109
2110        // Save the state
2111        let saved_state = emu.save().expect("save should succeed");
2112
2113        // Reset the emulator
2114        emu.reset();
2115
2116        // Verify state is reset
2117        emu.read_u32(0x04, &mut test_val).unwrap();
2118        assert_eq!(test_val & 0x0007, 0x0000); // Should be reset
2119
2120        // Restore the state
2121        emu.restore(saved_state).expect("restore should succeed");
2122
2123        // Verify state is restored
2124        emu.read_u32(0x04, &mut test_val).unwrap();
2125        assert_eq!(test_val & 0x0007, 0x0007); // Should be restored
2126    }
2127
2128    #[test]
2129    fn test_type1_emulator_save_restore() {
2130        use vmcore::save_restore::SaveRestore;
2131
2132        // Test Type 1 emulator save/restore
2133        let mut emu = create_type1_emulator(vec![]);
2134
2135        // Modify some state
2136        emu.write_u32(0x04, 0x0003).unwrap(); // Enable command bits
2137        emu.write_u32(0x18, 0x0012_1000).unwrap(); // Set bus numbers
2138        emu.write_u32(0x20, 0xFFF0_FF00).unwrap(); // Set memory range
2139        emu.write_u32(0x24, 0xFFF0_FF00).unwrap(); // Set prefetch range
2140        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // Set prefetch base upper
2141        emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); // Set prefetch limit upper
2142        emu.write_u32(0x3C, 0x0001_0000).unwrap(); // Set bridge control
2143
2144        // Verify values
2145        let mut test_val = 0u32;
2146        emu.read_u32(0x04, &mut test_val).unwrap();
2147        assert_eq!(test_val & 0x0003, 0x0003);
2148        emu.read_u32(0x18, &mut test_val).unwrap();
2149        assert_eq!(test_val, 0x0012_1000);
2150        emu.read_u32(0x20, &mut test_val).unwrap();
2151        assert_eq!(test_val, 0xFFF0_FF00);
2152        emu.read_u32(0x28, &mut test_val).unwrap();
2153        assert_eq!(test_val, 0x00AA_BBCC);
2154        emu.read_u32(0x2C, &mut test_val).unwrap();
2155        assert_eq!(test_val, 0x00DD_EEFF);
2156        emu.read_u32(0x3C, &mut test_val).unwrap();
2157        assert_eq!(test_val >> 16, 0x0001); // bridge_control
2158
2159        // Save the state
2160        let saved_state = emu.save().expect("save should succeed");
2161
2162        // Reset the emulator
2163        emu.reset();
2164
2165        // Verify state is reset
2166        emu.read_u32(0x04, &mut test_val).unwrap();
2167        assert_eq!(test_val & 0x0003, 0x0000);
2168        emu.read_u32(0x18, &mut test_val).unwrap();
2169        assert_eq!(test_val, 0x0000_0000);
2170
2171        // Restore the state
2172        emu.restore(saved_state).expect("restore should succeed");
2173
2174        // Verify state is restored
2175        emu.read_u32(0x04, &mut test_val).unwrap();
2176        assert_eq!(test_val & 0x0003, 0x0003);
2177        emu.read_u32(0x18, &mut test_val).unwrap();
2178        assert_eq!(test_val, 0x0012_1000);
2179        emu.read_u32(0x20, &mut test_val).unwrap();
2180        assert_eq!(test_val, 0xFFF0_FF00);
2181        emu.read_u32(0x28, &mut test_val).unwrap();
2182        assert_eq!(test_val, 0x00AA_BBCC);
2183        emu.read_u32(0x2C, &mut test_val).unwrap();
2184        assert_eq!(test_val, 0x00DD_EEFF);
2185        emu.read_u32(0x3C, &mut test_val).unwrap();
2186        assert_eq!(test_val >> 16, 0x0001); // bridge_control
2187    }
2188
2189    #[test]
2190    fn test_config_space_type1_set_presence_detect_state() {
2191        // Test that ConfigSpaceType1Emulator can set presence detect state
2192        // when it has a PCIe Express capability with hotplug support
2193
2194        // Create a PCIe Express capability with hotplug support
2195        let pcie_cap =
2196            PciExpressCapability::new(DevicePortType::RootPort, None).with_hotplug_support(1);
2197
2198        let mut emulator = create_type1_emulator(vec![Box::new(pcie_cap)]);
2199
2200        // Initially, presence detect state should be 0
2201        let mut slot_status_val = 0u32;
2202        let result = emulator.read_u32(0x58, &mut slot_status_val); // 0x40 (cap start) + 0x18 (slot control/status)
2203        assert!(matches!(result, IoResult::Ok));
2204        let initial_presence_detect = (slot_status_val >> 22) & 0x1; // presence_detect_state is bit 6 of slot status
2205        assert_eq!(
2206            initial_presence_detect, 0,
2207            "Initial presence detect state should be 0"
2208        );
2209
2210        // Set device as present
2211        emulator.set_presence_detect_state(true);
2212        let result = emulator.read_u32(0x58, &mut slot_status_val);
2213        assert!(matches!(result, IoResult::Ok));
2214        let present_presence_detect = (slot_status_val >> 22) & 0x1;
2215        assert_eq!(
2216            present_presence_detect, 1,
2217            "Presence detect state should be 1 when device is present"
2218        );
2219
2220        // Set device as not present
2221        emulator.set_presence_detect_state(false);
2222        let result = emulator.read_u32(0x58, &mut slot_status_val);
2223        assert!(matches!(result, IoResult::Ok));
2224        let absent_presence_detect = (slot_status_val >> 22) & 0x1;
2225        assert_eq!(
2226            absent_presence_detect, 0,
2227            "Presence detect state should be 0 when device is not present"
2228        );
2229    }
2230
2231    #[test]
2232    fn test_config_space_type1_set_presence_detect_state_without_pcie() {
2233        // Test that ConfigSpaceType1Emulator silently ignores set_presence_detect_state
2234        // when there is no PCIe Express capability
2235
2236        let mut emulator = create_type1_emulator(vec![]); // No capabilities
2237
2238        // Should not panic and should be silently ignored
2239        emulator.set_presence_detect_state(true);
2240        emulator.set_presence_detect_state(false);
2241    }
2242
2243    #[test]
2244    fn test_interrupt_pin_register() {
2245        use vmcore::line_interrupt::LineInterrupt;
2246
2247        // Test Type 0 device with interrupt pin configured
2248        let mut emu = ConfigSpaceType0Emulator::new(
2249            HardwareIds {
2250                vendor_id: 0x1111,
2251                device_id: 0x2222,
2252                revision_id: 1,
2253                prog_if: ProgrammingInterface::NONE,
2254                sub_class: Subclass::NONE,
2255                base_class: ClassCode::UNCLASSIFIED,
2256                type0_sub_vendor_id: 0,
2257                type0_sub_system_id: 0,
2258            },
2259            vec![],
2260            DeviceBars::new(),
2261        );
2262
2263        // Initially, no interrupt pin should be configured
2264        let mut val = 0u32;
2265        emu.read_u32(0x3C, &mut val).unwrap(); // LATENCY_INTERRUPT register
2266        assert_eq!(val & 0xFF00, 0); // Interrupt pin should be 0
2267
2268        // Configure interrupt pin A
2269        let line_interrupt = LineInterrupt::detached();
2270        emu.set_interrupt_pin(PciInterruptPin::IntA, line_interrupt);
2271
2272        // Read the register again
2273        emu.read_u32(0x3C, &mut val).unwrap();
2274        assert_eq!((val >> 8) & 0xFF, 1); // Interrupt pin should be 1 (INTA)
2275
2276        // Set interrupt line to 0x42 and verify both pin and line are correct
2277        emu.write_u32(0x3C, 0x00110042).unwrap(); // Latency=0x11, pin=ignored, line=0x42
2278        emu.read_u32(0x3C, &mut val).unwrap();
2279        assert_eq!(val & 0xFF, 0x42); // Interrupt line should be 0x42
2280        assert_eq!((val >> 8) & 0xFF, 1); // Interrupt pin should still be 1 (writes ignored)
2281        assert_eq!((val >> 16) & 0xFF, 0x11); // Latency timer should be 0x11
2282
2283        // Test with interrupt pin D
2284        let mut emu_d = ConfigSpaceType0Emulator::new(
2285            HardwareIds {
2286                vendor_id: 0x1111,
2287                device_id: 0x2222,
2288                revision_id: 1,
2289                prog_if: ProgrammingInterface::NONE,
2290                sub_class: Subclass::NONE,
2291                base_class: ClassCode::UNCLASSIFIED,
2292                type0_sub_vendor_id: 0,
2293                type0_sub_system_id: 0,
2294            },
2295            vec![],
2296            DeviceBars::new(),
2297        );
2298
2299        let line_interrupt_d = LineInterrupt::detached();
2300        emu_d.set_interrupt_pin(PciInterruptPin::IntD, line_interrupt_d);
2301
2302        emu_d.read_u32(0x3C, &mut val).unwrap();
2303        assert_eq!((val >> 8) & 0xFF, 4); // Interrupt pin should be 4 (INTD)
2304    }
2305
2306    #[test]
2307    fn test_header_type_functionality() {
2308        // Test HeaderType enum values
2309        assert_eq!(HeaderType::Type0.bar_count(), 6);
2310        assert_eq!(HeaderType::Type1.bar_count(), 2);
2311        assert_eq!(usize::from(HeaderType::Type0), 6);
2312        assert_eq!(usize::from(HeaderType::Type1), 2);
2313
2314        // Test constant values
2315        assert_eq!(header_type_consts::TYPE0_BAR_COUNT, 6);
2316        assert_eq!(header_type_consts::TYPE1_BAR_COUNT, 2);
2317
2318        // Test Type 0 emulator
2319        let emu_type0 = create_type0_emulator(vec![]);
2320        assert_eq!(emu_type0.common.bar_count(), 6);
2321        assert_eq!(emu_type0.common.header_type(), HeaderType::Type0);
2322        assert!(emu_type0.common.validate_header_type(HeaderType::Type0));
2323        assert!(!emu_type0.common.validate_header_type(HeaderType::Type1));
2324
2325        // Test Type 1 emulator
2326        let emu_type1 = create_type1_emulator(vec![]);
2327        assert_eq!(emu_type1.common.bar_count(), 2);
2328        assert_eq!(emu_type1.common.header_type(), HeaderType::Type1);
2329        assert!(emu_type1.common.validate_header_type(HeaderType::Type1));
2330        assert!(!emu_type1.common.validate_header_type(HeaderType::Type0));
2331    }
2332}