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    subordinate_bus_number: u8,
1015    /// The secondary bus number register. Software programs
1016    /// this register with the bus number assigned to the secondary
1017    /// side of the bridge.
1018    secondary_bus_number: u8,
1019    /// The primary bus number register. This is unused for PCI Express but
1020    /// is supposed to be read/write for compability with legacy software.
1021    primary_bus_number: u8,
1022    /// The memory base register. Software programs the upper 12 bits of this
1023    /// register with the upper 12 bits of a 32-bit base address of MMIO assigned
1024    /// to the hierarchy under the bridge (the lower 20 bits are assumed to be 0s).
1025    memory_base: u16,
1026    /// The memory limit register. Software programs the upper 12 bits of this
1027    /// register with the upper 12 bits of a 32-bit limit address of MMIO assigned
1028    /// to the hierarchy under the bridge (the lower 20 bits are assumed to be 1s).
1029    memory_limit: u16,
1030    /// The prefetchable memory base register. Software programs the upper 12 bits of
1031    /// this register with bits 20:31 of the base address of the prefetchable MMIO
1032    /// window assigned to the hierarchy under the bridge. Bits 0:19 are assumed to
1033    /// be 0s.
1034    prefetch_base: u16,
1035    /// The prefetchable memory limit register. Software programs the upper 12 bits of
1036    /// this register with bits 20:31 of the limit address of the prefetchable MMIO
1037    /// window assigned to the hierarchy under the bridge. Bits 0:19 are assumed to
1038    /// be 1s.
1039    prefetch_limit: u16,
1040    /// The prefetchable memory base upper 32 bits register. When the bridge supports
1041    /// 64-bit addressing for prefetchable memory, software programs this register
1042    /// with the upper 32 bits of the base address of the prefetchable MMIO window
1043    /// assigned to the hierarchy under the bridge.
1044    prefetch_base_upper: u32,
1045    /// The prefetchable memory limit upper 32 bits register. When the bridge supports
1046    /// 64-bit addressing for prefetchable memory, software programs this register
1047    /// with the upper 32 bits of the base address of the prefetchable MMIO window
1048    /// assigned to the hierarchy under the bridge.
1049    prefetch_limit_upper: u32,
1050    /// The bridge control register. Contains various control bits for bridge behavior
1051    /// such as secondary bus reset, VGA enable, etc.
1052    bridge_control: u16,
1053}
1054
1055impl ConfigSpaceType1EmulatorState {
1056    fn new() -> Self {
1057        Self {
1058            subordinate_bus_number: 0,
1059            secondary_bus_number: 0,
1060            primary_bus_number: 0,
1061            memory_base: 0,
1062            memory_limit: 0,
1063            prefetch_base: 0,
1064            prefetch_limit: 0,
1065            prefetch_base_upper: 0,
1066            prefetch_limit_upper: 0,
1067            bridge_control: 0,
1068        }
1069    }
1070}
1071
1072/// Emulator for the standard Type 1 PCI configuration space header.
1073#[derive(Inspect)]
1074pub struct ConfigSpaceType1Emulator {
1075    /// The common header emulator that handles shared functionality
1076    #[inspect(flatten)]
1077    common: ConfigSpaceCommonHeaderEmulatorType1,
1078    /// Type 1 specific state
1079    state: ConfigSpaceType1EmulatorState,
1080}
1081
1082impl ConfigSpaceType1Emulator {
1083    /// Create a new [`ConfigSpaceType1Emulator`]
1084    pub fn new(hardware_ids: HardwareIds, capabilities: Vec<Box<dyn PciCapability>>) -> Self {
1085        let common =
1086            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, capabilities, DeviceBars::new());
1087
1088        Self {
1089            common,
1090            state: ConfigSpaceType1EmulatorState::new(),
1091        }
1092    }
1093
1094    /// Resets the configuration space state.
1095    pub fn reset(&mut self) {
1096        self.common.reset();
1097        self.state = ConfigSpaceType1EmulatorState::new();
1098    }
1099
1100    /// Set the multi-function bit for this device.
1101    pub fn with_multi_function_bit(mut self, multi_function: bool) -> Self {
1102        self.common = self.common.with_multi_function_bit(multi_function);
1103        self
1104    }
1105
1106    /// Returns the range of bus numbers the bridge is programmed to decode.
1107    pub fn assigned_bus_range(&self) -> RangeInclusive<u8> {
1108        let secondary = self.state.secondary_bus_number;
1109        let subordinate = self.state.subordinate_bus_number;
1110        if secondary <= subordinate {
1111            secondary..=subordinate
1112        } else {
1113            0..=0
1114        }
1115    }
1116
1117    fn decode_memory_range(&self, base_register: u16, limit_register: u16) -> (u32, u32) {
1118        let base_addr = ((base_register & !0b1111) as u32) << 16;
1119        let limit_addr = ((limit_register & !0b1111) as u32) << 16 | 0xF_FFFF;
1120        (base_addr, limit_addr)
1121    }
1122
1123    /// If memory decoding is currently enabled, and the memory window assignment is valid,
1124    /// returns the 32-bit memory addresses the bridge is programmed to decode.
1125    pub fn assigned_memory_range(&self) -> Option<RangeInclusive<u32>> {
1126        let (base_addr, limit_addr) =
1127            self.decode_memory_range(self.state.memory_base, self.state.memory_limit);
1128        if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1129            Some(base_addr..=limit_addr)
1130        } else {
1131            None
1132        }
1133    }
1134
1135    /// If memory decoding is currently enabled, and the prefetchable memory window assignment
1136    /// is valid, returns the 64-bit prefetchable memory addresses the bridge is programmed to decode.
1137    pub fn assigned_prefetch_range(&self) -> Option<RangeInclusive<u64>> {
1138        let (base_low, limit_low) =
1139            self.decode_memory_range(self.state.prefetch_base, self.state.prefetch_limit);
1140        let base_addr = (self.state.prefetch_base_upper as u64) << 32 | base_low as u64;
1141        let limit_addr = (self.state.prefetch_limit_upper as u64) << 32 | limit_low as u64;
1142        if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1143            Some(base_addr..=limit_addr)
1144        } else {
1145            None
1146        }
1147    }
1148
1149    /// Read from the config space. `offset` must be 32-bit aligned.
1150    pub fn read_u32(&self, offset: u16, value: &mut u32) -> IoResult {
1151        use cfg_space::HeaderType01;
1152
1153        // First try to handle with common header emulator
1154        match self.common.read_u32(offset, value) {
1155            CommonHeaderResult::Handled => return IoResult::Ok,
1156            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1157            CommonHeaderResult::Unhandled => {
1158                // Continue with Type 1 specific handling
1159            }
1160        }
1161
1162        // Handle Type 1 specific registers
1163        *value = match HeaderType01(offset) {
1164            HeaderType01::BIST_HEADER => {
1165                // Header type 01 with optional multi-function bit
1166                if self.common.multi_function_bit() {
1167                    0x00810000 // Header type 01 with multi-function bit (bit 23)
1168                } else {
1169                    0x00010000 // Header type 01 without multi-function bit
1170                }
1171            }
1172            HeaderType01::LATENCY_BUS_NUMBERS => {
1173                (self.state.subordinate_bus_number as u32) << 16
1174                    | (self.state.secondary_bus_number as u32) << 8
1175                    | self.state.primary_bus_number as u32
1176            }
1177            HeaderType01::SEC_STATUS_IO_RANGE => 0,
1178            HeaderType01::MEMORY_RANGE => {
1179                (self.state.memory_limit as u32) << 16 | self.state.memory_base as u32
1180            }
1181            HeaderType01::PREFETCH_RANGE => {
1182                // Set the low bit in both the limit and base registers to indicate
1183                // support for 64-bit addressing.
1184                ((self.state.prefetch_limit | 0b0001) as u32) << 16
1185                    | (self.state.prefetch_base | 0b0001) as u32
1186            }
1187            HeaderType01::PREFETCH_BASE_UPPER => self.state.prefetch_base_upper,
1188            HeaderType01::PREFETCH_LIMIT_UPPER => self.state.prefetch_limit_upper,
1189            HeaderType01::IO_RANGE_UPPER => 0,
1190            HeaderType01::EXPANSION_ROM_BASE => 0,
1191            HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1192                // Read interrupt line from common header and bridge control from state
1193                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin (0), Bits 31-16: Bridge Control
1194                (self.state.bridge_control as u32) << 16 | self.common.interrupt_line() as u32
1195            }
1196            _ => {
1197                tracelimit::warn_ratelimited!(offset, "unexpected config space read");
1198                return IoResult::Err(IoError::InvalidRegister);
1199            }
1200        };
1201
1202        IoResult::Ok
1203    }
1204
1205    /// Write to the config space. `offset` must be 32-bit aligned.
1206    pub fn write_u32(&mut self, offset: u16, val: u32) -> IoResult {
1207        use cfg_space::HeaderType01;
1208
1209        // First try to handle with common header emulator
1210        match self.common.write_u32(offset, val) {
1211            CommonHeaderResult::Handled => return IoResult::Ok,
1212            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1213            CommonHeaderResult::Unhandled => {
1214                // Continue with Type 1 specific handling
1215            }
1216        }
1217
1218        // Handle Type 1 specific registers
1219        match HeaderType01(offset) {
1220            HeaderType01::BIST_HEADER => {
1221                // BIST_HEADER - Type 1 specific handling
1222                // For now, just ignore these writes (latency timer would go here if supported)
1223            }
1224            HeaderType01::LATENCY_BUS_NUMBERS => {
1225                self.state.subordinate_bus_number = (val >> 16) as u8;
1226                self.state.secondary_bus_number = (val >> 8) as u8;
1227                self.state.primary_bus_number = val as u8;
1228            }
1229            HeaderType01::MEMORY_RANGE => {
1230                self.state.memory_base = val as u16;
1231                self.state.memory_limit = (val >> 16) as u16;
1232            }
1233            HeaderType01::PREFETCH_RANGE => {
1234                self.state.prefetch_base = val as u16;
1235                self.state.prefetch_limit = (val >> 16) as u16;
1236            }
1237            HeaderType01::PREFETCH_BASE_UPPER => {
1238                self.state.prefetch_base_upper = val;
1239            }
1240            HeaderType01::PREFETCH_LIMIT_UPPER => {
1241                self.state.prefetch_limit_upper = val;
1242            }
1243            HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1244                // Delegate interrupt line writes to common header and store bridge control
1245                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin (ignored), Bits 31-16: Bridge Control
1246                self.common.set_interrupt_line((val & 0xff) as u8);
1247                self.state.bridge_control = (val >> 16) as u16;
1248            }
1249            // all other base regs are noops
1250            _ if offset < 0x40 && offset.is_multiple_of(4) => (),
1251            _ => {
1252                tracelimit::warn_ratelimited!(offset, value = val, "unexpected config space write");
1253                return IoResult::Err(IoError::InvalidRegister);
1254            }
1255        }
1256
1257        IoResult::Ok
1258    }
1259
1260    /// Checks if this device is a PCIe device by looking for the PCI Express capability.
1261    pub fn is_pcie_device(&self) -> bool {
1262        self.common.is_pcie_device()
1263    }
1264
1265    /// Set the presence detect state for the slot.
1266    /// This method finds the PCIe Express capability and calls its set_presence_detect_state method.
1267    /// If the PCIe Express capability is not found, the call is silently ignored.
1268    ///
1269    /// # Arguments
1270    /// * `present` - true if a device is present in the slot, false if the slot is empty
1271    pub fn set_presence_detect_state(&mut self, present: bool) {
1272        // Find the PCIe Express capability
1273        for cap in self.common.capabilities_mut() {
1274            if cap.capability_id() == CapabilityId::PCI_EXPRESS {
1275                // Downcast to PciExpressCapability and call set_presence_detect_state
1276                if let Some(pcie_cap) = cap.as_pci_express_mut() {
1277                    pcie_cap.set_presence_detect_state(present);
1278                    return;
1279                }
1280            }
1281        }
1282        // If no PCIe Express capability is found, silently ignore the call
1283    }
1284}
1285
1286mod save_restore {
1287    use super::*;
1288    use thiserror::Error;
1289    use vmcore::save_restore::RestoreError;
1290    use vmcore::save_restore::SaveError;
1291    use vmcore::save_restore::SaveRestore;
1292
1293    mod state {
1294        use mesh::payload::Protobuf;
1295        use vmcore::save_restore::SavedStateBlob;
1296        use vmcore::save_restore::SavedStateRoot;
1297
1298        /// Unified saved state for both Type 0 and Type 1 PCI configuration space emulators.
1299        /// Type 1 specific fields (mesh indices 6-15) will be ignored when restoring Type 0 devices,
1300        /// and will have default values (0) when restoring old save state to Type 1 devices.
1301        #[derive(Protobuf, SavedStateRoot)]
1302        #[mesh(package = "pci.cfg_space_emu")]
1303        pub struct SavedState {
1304            // Common fields (used by both Type 0 and Type 1)
1305            #[mesh(1)]
1306            pub command: u16,
1307            #[mesh(2)]
1308            pub base_addresses: [u32; 6],
1309            #[mesh(3)]
1310            pub interrupt_line: u8,
1311            #[mesh(4)]
1312            pub latency_timer: u8,
1313            #[mesh(5)]
1314            pub capabilities: Vec<(String, SavedStateBlob)>,
1315
1316            // Type 1 specific fields (bridge devices)
1317            // These fields default to 0 for backward compatibility with old save state
1318            #[mesh(6)]
1319            pub subordinate_bus_number: u8,
1320            #[mesh(7)]
1321            pub secondary_bus_number: u8,
1322            #[mesh(8)]
1323            pub primary_bus_number: u8,
1324            #[mesh(9)]
1325            pub memory_base: u16,
1326            #[mesh(10)]
1327            pub memory_limit: u16,
1328            #[mesh(11)]
1329            pub prefetch_base: u16,
1330            #[mesh(12)]
1331            pub prefetch_limit: u16,
1332            #[mesh(13)]
1333            pub prefetch_base_upper: u32,
1334            #[mesh(14)]
1335            pub prefetch_limit_upper: u32,
1336            #[mesh(15)]
1337            pub bridge_control: u16,
1338        }
1339    }
1340
1341    #[derive(Debug, Error)]
1342    enum ConfigSpaceRestoreError {
1343        #[error("found invalid config bits in saved state")]
1344        InvalidConfigBits,
1345        #[error("found unexpected capability {0}")]
1346        InvalidCap(String),
1347    }
1348
1349    impl SaveRestore for ConfigSpaceType0Emulator {
1350        type SavedState = state::SavedState;
1351
1352        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1353            let ConfigSpaceType0EmulatorState { latency_timer } = self.state;
1354
1355            let saved_state = state::SavedState {
1356                command: self.common.command().into_bits(),
1357                base_addresses: *self.common.base_addresses(),
1358                interrupt_line: self.common.interrupt_line(),
1359                latency_timer,
1360                capabilities: self
1361                    .common
1362                    .capabilities_mut()
1363                    .iter_mut()
1364                    .map(|cap| {
1365                        let id = cap.label().to_owned();
1366                        Ok((id, cap.save()?))
1367                    })
1368                    .collect::<Result<_, _>>()?,
1369                // Type 1 specific fields - not used for Type 0
1370                subordinate_bus_number: 0,
1371                secondary_bus_number: 0,
1372                primary_bus_number: 0,
1373                memory_base: 0,
1374                memory_limit: 0,
1375                prefetch_base: 0,
1376                prefetch_limit: 0,
1377                prefetch_base_upper: 0,
1378                prefetch_limit_upper: 0,
1379                bridge_control: 0,
1380            };
1381
1382            Ok(saved_state)
1383        }
1384
1385        fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1386            let state::SavedState {
1387                command,
1388                base_addresses,
1389                interrupt_line,
1390                latency_timer,
1391                capabilities,
1392                // Type 1 specific fields - ignored for Type 0
1393                subordinate_bus_number: _,
1394                secondary_bus_number: _,
1395                primary_bus_number: _,
1396                memory_base: _,
1397                memory_limit: _,
1398                prefetch_base: _,
1399                prefetch_limit: _,
1400                prefetch_base_upper: _,
1401                prefetch_limit_upper: _,
1402                bridge_control: _,
1403            } = state;
1404
1405            self.state = ConfigSpaceType0EmulatorState { latency_timer };
1406
1407            self.common.set_base_addresses(&base_addresses);
1408            self.common.set_interrupt_line(interrupt_line);
1409            self.common
1410                .set_command(cfg_space::Command::from_bits(command));
1411
1412            if command & !SUPPORTED_COMMAND_BITS != 0 {
1413                return Err(RestoreError::InvalidSavedState(
1414                    ConfigSpaceRestoreError::InvalidConfigBits.into(),
1415                ));
1416            }
1417
1418            self.common.sync_command_register(self.common.command());
1419
1420            for (id, entry) in capabilities {
1421                tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1422
1423                // yes, yes, this is O(n^2), but devices never have more than a
1424                // handful of caps, so it's totally fine.
1425                let mut restored = false;
1426                for cap in self.common.capabilities_mut() {
1427                    if cap.label() == id {
1428                        cap.restore(entry)?;
1429                        restored = true;
1430                        break;
1431                    }
1432                }
1433
1434                if !restored {
1435                    return Err(RestoreError::InvalidSavedState(
1436                        ConfigSpaceRestoreError::InvalidCap(id).into(),
1437                    ));
1438                }
1439            }
1440
1441            Ok(())
1442        }
1443    }
1444
1445    impl SaveRestore for ConfigSpaceType1Emulator {
1446        type SavedState = state::SavedState;
1447
1448        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1449            let ConfigSpaceType1EmulatorState {
1450                subordinate_bus_number,
1451                secondary_bus_number,
1452                primary_bus_number,
1453                memory_base,
1454                memory_limit,
1455                prefetch_base,
1456                prefetch_limit,
1457                prefetch_base_upper,
1458                prefetch_limit_upper,
1459                bridge_control,
1460            } = self.state;
1461
1462            // Pad base_addresses to 6 elements for saved state (Type 1 uses 2 BARs)
1463            let type1_base_addresses = self.common.base_addresses();
1464            let mut saved_base_addresses = [0u32; 6];
1465            saved_base_addresses[0] = type1_base_addresses[0];
1466            saved_base_addresses[1] = type1_base_addresses[1];
1467
1468            let saved_state = state::SavedState {
1469                command: self.common.command().into_bits(),
1470                base_addresses: saved_base_addresses,
1471                interrupt_line: self.common.interrupt_line(),
1472                latency_timer: 0, // Not used for Type 1
1473                capabilities: self
1474                    .common
1475                    .capabilities_mut()
1476                    .iter_mut()
1477                    .map(|cap| {
1478                        let id = cap.label().to_owned();
1479                        Ok((id, cap.save()?))
1480                    })
1481                    .collect::<Result<_, _>>()?,
1482                // Type 1 specific fields
1483                subordinate_bus_number,
1484                secondary_bus_number,
1485                primary_bus_number,
1486                memory_base,
1487                memory_limit,
1488                prefetch_base,
1489                prefetch_limit,
1490                prefetch_base_upper,
1491                prefetch_limit_upper,
1492                bridge_control,
1493            };
1494
1495            Ok(saved_state)
1496        }
1497
1498        fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1499            let state::SavedState {
1500                command,
1501                base_addresses,
1502                interrupt_line,
1503                latency_timer: _, // Not used for Type 1
1504                capabilities,
1505                subordinate_bus_number,
1506                secondary_bus_number,
1507                primary_bus_number,
1508                memory_base,
1509                memory_limit,
1510                prefetch_base,
1511                prefetch_limit,
1512                prefetch_base_upper,
1513                prefetch_limit_upper,
1514                bridge_control,
1515            } = state;
1516
1517            self.state = ConfigSpaceType1EmulatorState {
1518                subordinate_bus_number,
1519                secondary_bus_number,
1520                primary_bus_number,
1521                memory_base,
1522                memory_limit,
1523                prefetch_base,
1524                prefetch_limit,
1525                prefetch_base_upper,
1526                prefetch_limit_upper,
1527                bridge_control,
1528            };
1529
1530            // Pad base_addresses to 6 elements for common header (Type 1 uses 2 BARs)
1531            let mut full_base_addresses = [0u32; 6];
1532            for (i, &addr) in base_addresses.iter().enumerate().take(2) {
1533                full_base_addresses[i] = addr;
1534            }
1535            self.common
1536                .set_base_addresses(&[full_base_addresses[0], full_base_addresses[1]]);
1537            self.common.set_interrupt_line(interrupt_line);
1538            self.common
1539                .set_command(cfg_space::Command::from_bits(command));
1540
1541            if command & !SUPPORTED_COMMAND_BITS != 0 {
1542                return Err(RestoreError::InvalidSavedState(
1543                    ConfigSpaceRestoreError::InvalidConfigBits.into(),
1544                ));
1545            }
1546
1547            self.common.sync_command_register(self.common.command());
1548
1549            for (id, entry) in capabilities {
1550                tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1551
1552                let mut restored = false;
1553                for cap in self.common.capabilities_mut() {
1554                    if cap.label() == id {
1555                        cap.restore(entry)?;
1556                        restored = true;
1557                        break;
1558                    }
1559                }
1560
1561                if !restored {
1562                    return Err(RestoreError::InvalidSavedState(
1563                        ConfigSpaceRestoreError::InvalidCap(id).into(),
1564                    ));
1565                }
1566            }
1567
1568            Ok(())
1569        }
1570    }
1571}
1572
1573#[cfg(test)]
1574mod tests {
1575    use super::*;
1576    use crate::capabilities::pci_express::PciExpressCapability;
1577    use crate::capabilities::read_only::ReadOnlyCapability;
1578    use crate::spec::caps::pci_express::DevicePortType;
1579    use crate::spec::hwid::ClassCode;
1580    use crate::spec::hwid::ProgrammingInterface;
1581    use crate::spec::hwid::Subclass;
1582
1583    fn create_type0_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType0Emulator {
1584        ConfigSpaceType0Emulator::new(
1585            HardwareIds {
1586                vendor_id: 0x1111,
1587                device_id: 0x2222,
1588                revision_id: 1,
1589                prog_if: ProgrammingInterface::NONE,
1590                sub_class: Subclass::NONE,
1591                base_class: ClassCode::UNCLASSIFIED,
1592                type0_sub_vendor_id: 0x3333,
1593                type0_sub_system_id: 0x4444,
1594            },
1595            caps,
1596            DeviceBars::new(),
1597        )
1598    }
1599
1600    fn create_type1_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType1Emulator {
1601        ConfigSpaceType1Emulator::new(
1602            HardwareIds {
1603                vendor_id: 0x1111,
1604                device_id: 0x2222,
1605                revision_id: 1,
1606                prog_if: ProgrammingInterface::NONE,
1607                sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1608                base_class: ClassCode::BRIDGE,
1609                type0_sub_vendor_id: 0,
1610                type0_sub_system_id: 0,
1611            },
1612            caps,
1613        )
1614    }
1615
1616    fn read_cfg(emulator: &ConfigSpaceType1Emulator, offset: u16) -> u32 {
1617        let mut val = 0;
1618        emulator.read_u32(offset, &mut val).unwrap();
1619        val
1620    }
1621
1622    #[test]
1623    fn test_type1_probe() {
1624        let emu = create_type1_emulator(vec![]);
1625        assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1626        assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0); // Capabilities pointer
1627
1628        let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1629        assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1630        assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0x10_0000); // Capabilities pointer
1631    }
1632
1633    #[test]
1634    fn test_type1_bus_number_assignment() {
1635        let mut emu = create_type1_emulator(vec![]);
1636
1637        // The bus number (and latency timer) registers are
1638        // all default 0.
1639        assert_eq!(read_cfg(&emu, 0x18), 0);
1640        assert_eq!(emu.assigned_bus_range(), 0..=0);
1641
1642        // The bus numbers can be programmed one by one,
1643        // and the range may not be valid during the middle
1644        // of allocation.
1645        emu.write_u32(0x18, 0x0000_1000).unwrap();
1646        assert_eq!(read_cfg(&emu, 0x18), 0x0000_1000);
1647        assert_eq!(emu.assigned_bus_range(), 0..=0);
1648        emu.write_u32(0x18, 0x0012_1000).unwrap();
1649        assert_eq!(read_cfg(&emu, 0x18), 0x0012_1000);
1650        assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1651
1652        // The primary bus number register is read/write for compatability
1653        // but unused.
1654        emu.write_u32(0x18, 0x0012_1033).unwrap();
1655        assert_eq!(read_cfg(&emu, 0x18), 0x0012_1033);
1656        assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1657
1658        // Software can also just write the entire 4byte value at once
1659        emu.write_u32(0x18, 0x0047_4411).unwrap();
1660        assert_eq!(read_cfg(&emu, 0x18), 0x0047_4411);
1661        assert_eq!(emu.assigned_bus_range(), 0x44..=0x47);
1662
1663        // The subordinate bus number can equal the secondary bus number...
1664        emu.write_u32(0x18, 0x0088_8800).unwrap();
1665        assert_eq!(emu.assigned_bus_range(), 0x88..=0x88);
1666
1667        // ... but it cannot be less, that's a confused guest OS.
1668        emu.write_u32(0x18, 0x0087_8800).unwrap();
1669        assert_eq!(emu.assigned_bus_range(), 0..=0);
1670    }
1671
1672    #[test]
1673    fn test_type1_memory_assignment() {
1674        const MMIO_ENABLED: u32 = 0x0000_0002;
1675        const MMIO_DISABLED: u32 = 0x0000_0000;
1676
1677        let mut emu = create_type1_emulator(vec![]);
1678        assert!(emu.assigned_memory_range().is_none());
1679
1680        // The guest can write whatever it wants while MMIO
1681        // is disabled.
1682        emu.write_u32(0x20, 0xDEAD_BEEF).unwrap();
1683        assert!(emu.assigned_memory_range().is_none());
1684
1685        // The guest can program a valid resource assignment...
1686        emu.write_u32(0x20, 0xFFF0_FF00).unwrap();
1687        assert!(emu.assigned_memory_range().is_none());
1688        // ... enable memory decoding...
1689        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1690        assert_eq!(emu.assigned_memory_range(), Some(0xFF00_0000..=0xFFFF_FFFF));
1691        // ... then disable memory decoding it.
1692        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1693        assert!(emu.assigned_memory_range().is_none());
1694
1695        // Setting memory base equal to memory limit is a valid 1MB range.
1696        emu.write_u32(0x20, 0xBBB0_BBB0).unwrap();
1697        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1698        assert_eq!(emu.assigned_memory_range(), Some(0xBBB0_0000..=0xBBBF_FFFF));
1699        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1700        assert!(emu.assigned_memory_range().is_none());
1701
1702        // The guest can try to program an invalid assignment (base > limit), we
1703        // just won't decode it.
1704        emu.write_u32(0x20, 0xAA00_BB00).unwrap();
1705        assert!(emu.assigned_memory_range().is_none());
1706        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1707        assert!(emu.assigned_memory_range().is_none());
1708        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1709        assert!(emu.assigned_memory_range().is_none());
1710    }
1711
1712    #[test]
1713    fn test_type1_prefetch_assignment() {
1714        const MMIO_ENABLED: u32 = 0x0000_0002;
1715        const MMIO_DISABLED: u32 = 0x0000_0000;
1716
1717        let mut emu = create_type1_emulator(vec![]);
1718        assert!(emu.assigned_prefetch_range().is_none());
1719
1720        // The guest can program a valid prefetch range...
1721        emu.write_u32(0x24, 0xFFF0_FF00).unwrap(); // limit + base
1722        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // base upper
1723        emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); // limit upper
1724        assert!(emu.assigned_prefetch_range().is_none());
1725        // ... enable memory decoding...
1726        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1727        assert_eq!(
1728            emu.assigned_prefetch_range(),
1729            Some(0x00AA_BBCC_FF00_0000..=0x00DD_EEFF_FFFF_FFFF)
1730        );
1731        // ... then disable memory decoding it.
1732        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1733        assert!(emu.assigned_prefetch_range().is_none());
1734
1735        // The validity of the assignment is determined using the combined 64-bit
1736        // address, not the lower bits or the upper bits in isolation.
1737
1738        // Lower bits of the limit are greater than the lower bits of the
1739        // base, but the upper bits make that valid.
1740        emu.write_u32(0x24, 0xFF00_FFF0).unwrap(); // limit + base
1741        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // base upper
1742        emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); // limit upper
1743        assert!(emu.assigned_prefetch_range().is_none());
1744        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1745        assert_eq!(
1746            emu.assigned_prefetch_range(),
1747            Some(0x00AA_BBCC_FFF0_0000..=0x00DD_EEFF_FF0F_FFFF)
1748        );
1749        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1750        assert!(emu.assigned_prefetch_range().is_none());
1751
1752        // The base can equal the limit, which is a valid 1MB range.
1753        emu.write_u32(0x24, 0xDD00_DD00).unwrap(); // limit + base
1754        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // base upper
1755        emu.write_u32(0x2C, 0x00AA_BBCC).unwrap(); // limit upper
1756        assert!(emu.assigned_prefetch_range().is_none());
1757        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1758        assert_eq!(
1759            emu.assigned_prefetch_range(),
1760            Some(0x00AA_BBCC_DD00_0000..=0x00AA_BBCC_DD0F_FFFF)
1761        );
1762        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1763        assert!(emu.assigned_prefetch_range().is_none());
1764    }
1765
1766    #[test]
1767    fn test_type1_is_pcie_device() {
1768        // Test Type 1 device without PCIe capability
1769        let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1770        assert!(!emu.is_pcie_device());
1771
1772        // Test Type 1 device with PCIe capability
1773        let emu = create_type1_emulator(vec![Box::new(PciExpressCapability::new(
1774            DevicePortType::RootPort,
1775            None,
1776        ))]);
1777        assert!(emu.is_pcie_device());
1778
1779        // Test Type 1 device with multiple capabilities including PCIe
1780        let emu = create_type1_emulator(vec![
1781            Box::new(ReadOnlyCapability::new("foo", 0)),
1782            Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1783            Box::new(ReadOnlyCapability::new("bar", 0)),
1784        ]);
1785        assert!(emu.is_pcie_device());
1786    }
1787
1788    #[test]
1789    fn test_type0_is_pcie_device() {
1790        // Test Type 0 device without PCIe capability
1791        let emu = ConfigSpaceType0Emulator::new(
1792            HardwareIds {
1793                vendor_id: 0x1111,
1794                device_id: 0x2222,
1795                revision_id: 1,
1796                prog_if: ProgrammingInterface::NONE,
1797                sub_class: Subclass::NONE,
1798                base_class: ClassCode::UNCLASSIFIED,
1799                type0_sub_vendor_id: 0,
1800                type0_sub_system_id: 0,
1801            },
1802            vec![Box::new(ReadOnlyCapability::new("foo", 0))],
1803            DeviceBars::new(),
1804        );
1805        assert!(!emu.is_pcie_device());
1806
1807        // Test Type 0 device with PCIe capability
1808        let emu = ConfigSpaceType0Emulator::new(
1809            HardwareIds {
1810                vendor_id: 0x1111,
1811                device_id: 0x2222,
1812                revision_id: 1,
1813                prog_if: ProgrammingInterface::NONE,
1814                sub_class: Subclass::NONE,
1815                base_class: ClassCode::UNCLASSIFIED,
1816                type0_sub_vendor_id: 0,
1817                type0_sub_system_id: 0,
1818            },
1819            vec![Box::new(PciExpressCapability::new(
1820                DevicePortType::Endpoint,
1821                None,
1822            ))],
1823            DeviceBars::new(),
1824        );
1825        assert!(emu.is_pcie_device());
1826
1827        // Test Type 0 device with multiple capabilities including PCIe
1828        let emu = ConfigSpaceType0Emulator::new(
1829            HardwareIds {
1830                vendor_id: 0x1111,
1831                device_id: 0x2222,
1832                revision_id: 1,
1833                prog_if: ProgrammingInterface::NONE,
1834                sub_class: Subclass::NONE,
1835                base_class: ClassCode::UNCLASSIFIED,
1836                type0_sub_vendor_id: 0,
1837                type0_sub_system_id: 0,
1838            },
1839            vec![
1840                Box::new(ReadOnlyCapability::new("foo", 0)),
1841                Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1842                Box::new(ReadOnlyCapability::new("bar", 0)),
1843            ],
1844            DeviceBars::new(),
1845        );
1846        assert!(emu.is_pcie_device());
1847
1848        // Test Type 0 device with no capabilities
1849        let emu = ConfigSpaceType0Emulator::new(
1850            HardwareIds {
1851                vendor_id: 0x1111,
1852                device_id: 0x2222,
1853                revision_id: 1,
1854                prog_if: ProgrammingInterface::NONE,
1855                sub_class: Subclass::NONE,
1856                base_class: ClassCode::UNCLASSIFIED,
1857                type0_sub_vendor_id: 0,
1858                type0_sub_system_id: 0,
1859            },
1860            vec![],
1861            DeviceBars::new(),
1862        );
1863        assert!(!emu.is_pcie_device());
1864    }
1865
1866    #[test]
1867    fn test_capability_ids() {
1868        // Test that capabilities return the correct capability IDs
1869        let pcie_cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
1870        assert_eq!(pcie_cap.capability_id(), CapabilityId::PCI_EXPRESS);
1871
1872        let read_only_cap = ReadOnlyCapability::new("test", 0u32);
1873        assert_eq!(read_only_cap.capability_id(), CapabilityId::VENDOR_SPECIFIC);
1874    }
1875
1876    #[test]
1877    fn test_common_header_emulator_type0() {
1878        // Test the common header emulator with Type 0 configuration (6 BARs)
1879        let hardware_ids = HardwareIds {
1880            vendor_id: 0x1111,
1881            device_id: 0x2222,
1882            revision_id: 1,
1883            prog_if: ProgrammingInterface::NONE,
1884            sub_class: Subclass::NONE,
1885            base_class: ClassCode::UNCLASSIFIED,
1886            type0_sub_vendor_id: 0,
1887            type0_sub_system_id: 0,
1888        };
1889
1890        let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1891
1892        let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1893            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1894
1895        assert_eq!(common_emu.hardware_ids().vendor_id, 0x1111);
1896        assert_eq!(common_emu.hardware_ids().device_id, 0x2222);
1897        assert!(!common_emu.multi_function_bit());
1898        assert!(!common_emu.is_pcie_device());
1899        assert_ne!(common_emu.bar_masks()[0], 0); // Should have a mask for BAR0
1900    }
1901
1902    #[test]
1903    fn test_common_header_emulator_type1() {
1904        // Test the common header emulator with Type 1 configuration (2 BARs)
1905        let hardware_ids = HardwareIds {
1906            vendor_id: 0x3333,
1907            device_id: 0x4444,
1908            revision_id: 1,
1909            prog_if: ProgrammingInterface::NONE,
1910            sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1911            base_class: ClassCode::BRIDGE,
1912            type0_sub_vendor_id: 0,
1913            type0_sub_system_id: 0,
1914        };
1915
1916        let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1917
1918        let mut common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
1919            ConfigSpaceCommonHeaderEmulator::new(
1920                hardware_ids,
1921                vec![Box::new(PciExpressCapability::new(
1922                    DevicePortType::RootPort,
1923                    None,
1924                ))],
1925                bars,
1926            )
1927            .with_multi_function_bit(true);
1928
1929        assert_eq!(common_emu.hardware_ids().vendor_id, 0x3333);
1930        assert_eq!(common_emu.hardware_ids().device_id, 0x4444);
1931        assert!(common_emu.multi_function_bit());
1932        assert!(common_emu.is_pcie_device());
1933        assert_ne!(common_emu.bar_masks()[0], 0); // Should have a mask for BAR0
1934        assert_eq!(common_emu.bar_masks().len(), 2);
1935
1936        // Test reset functionality
1937        common_emu.reset();
1938        assert_eq!(common_emu.capabilities().len(), 1); // capabilities should still be there
1939    }
1940
1941    #[test]
1942    fn test_common_header_emulator_no_bars() {
1943        // Test the common header emulator with no BARs configured
1944        let hardware_ids = HardwareIds {
1945            vendor_id: 0x5555,
1946            device_id: 0x6666,
1947            revision_id: 1,
1948            prog_if: ProgrammingInterface::NONE,
1949            sub_class: Subclass::NONE,
1950            base_class: ClassCode::UNCLASSIFIED,
1951            type0_sub_vendor_id: 0,
1952            type0_sub_system_id: 0,
1953        };
1954
1955        // Create bars with no BARs configured
1956        let bars = DeviceBars::new();
1957
1958        let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1959            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1960
1961        assert_eq!(common_emu.hardware_ids().vendor_id, 0x5555);
1962        assert_eq!(common_emu.hardware_ids().device_id, 0x6666);
1963
1964        // All BAR masks should be 0 when no BARs are configured
1965        for &mask in common_emu.bar_masks() {
1966            assert_eq!(mask, 0);
1967        }
1968    }
1969
1970    #[test]
1971    fn test_common_header_emulator_type1_ignores_extra_bars() {
1972        // Test that Type 1 emulator ignores BARs beyond index 1 (only supports 2 BARs)
1973        let hardware_ids = HardwareIds {
1974            vendor_id: 0x7777,
1975            device_id: 0x8888,
1976            revision_id: 1,
1977            prog_if: ProgrammingInterface::NONE,
1978            sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1979            base_class: ClassCode::BRIDGE,
1980            type0_sub_vendor_id: 0,
1981            type0_sub_system_id: 0,
1982        };
1983
1984        // Configure BARs 0, 2, and 4 - Type 1 should only use BAR0 (and BAR1 as upper 32 bits)
1985        let bars = DeviceBars::new()
1986            .bar0(4096, BarMemoryKind::Dummy)
1987            .bar2(8192, BarMemoryKind::Dummy)
1988            .bar4(16384, BarMemoryKind::Dummy);
1989
1990        let common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
1991            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1992
1993        assert_eq!(common_emu.hardware_ids().vendor_id, 0x7777);
1994        assert_eq!(common_emu.hardware_ids().device_id, 0x8888);
1995
1996        // Should have a mask for BAR0, and BAR1 should be the upper 32 bits (64-bit BAR)
1997        assert_ne!(common_emu.bar_masks()[0], 0); // BAR0 should be configured
1998        assert_ne!(common_emu.bar_masks()[1], 0); // BAR1 should be upper 32 bits of BAR0
1999        assert_eq!(common_emu.bar_masks().len(), 2); // Type 1 only has 2 BARs
2000
2001        // BAR2 and higher should be ignored (not accessible in Type 1 with N=2)
2002        // This demonstrates that extra BARs in DeviceBars are properly ignored
2003    }
2004
2005    #[test]
2006    fn test_common_header_extended_capabilities() {
2007        // Test common header emulator extended capabilities
2008        let mut common_emu_no_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2009            HardwareIds {
2010                vendor_id: 0x1111,
2011                device_id: 0x2222,
2012                revision_id: 1,
2013                prog_if: ProgrammingInterface::NONE,
2014                sub_class: Subclass::NONE,
2015                base_class: ClassCode::UNCLASSIFIED,
2016                type0_sub_vendor_id: 0,
2017                type0_sub_system_id: 0,
2018            },
2019            vec![Box::new(ReadOnlyCapability::new("foo", 0))],
2020            DeviceBars::new(),
2021        );
2022        assert!(!common_emu_no_pcie.is_pcie_device());
2023
2024        let mut common_emu_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2025            HardwareIds {
2026                vendor_id: 0x1111,
2027                device_id: 0x2222,
2028                revision_id: 1,
2029                prog_if: ProgrammingInterface::NONE,
2030                sub_class: Subclass::NONE,
2031                base_class: ClassCode::UNCLASSIFIED,
2032                type0_sub_vendor_id: 0,
2033                type0_sub_system_id: 0,
2034            },
2035            vec![Box::new(PciExpressCapability::new(
2036                DevicePortType::Endpoint,
2037                None,
2038            ))],
2039            DeviceBars::new(),
2040        );
2041        assert!(common_emu_pcie.is_pcie_device());
2042
2043        // Test reading extended capabilities - non-PCIe device should return error
2044        let mut value = 0;
2045        assert!(matches!(
2046            common_emu_no_pcie.read_extended_capabilities(0x100, &mut value),
2047            CommonHeaderResult::Failed(IoError::InvalidRegister)
2048        ));
2049
2050        // Test reading extended capabilities - PCIe device should return 0xffffffff
2051        let mut value = 0;
2052        assert!(matches!(
2053            common_emu_pcie.read_extended_capabilities(0x100, &mut value),
2054            CommonHeaderResult::Handled
2055        ));
2056        assert_eq!(value, 0xffffffff);
2057
2058        // Test writing extended capabilities - non-PCIe device should return error
2059        assert!(matches!(
2060            common_emu_no_pcie.write_extended_capabilities(0x100, 0x1234),
2061            CommonHeaderResult::Failed(IoError::InvalidRegister)
2062        ));
2063
2064        // Test writing extended capabilities - PCIe device should accept writes
2065        assert!(matches!(
2066            common_emu_pcie.write_extended_capabilities(0x100, 0x1234),
2067            CommonHeaderResult::Handled
2068        ));
2069
2070        // Test invalid offset ranges
2071        let mut value = 0;
2072        assert!(matches!(
2073            common_emu_pcie.read_extended_capabilities(0x99, &mut value),
2074            CommonHeaderResult::Failed(IoError::InvalidRegister)
2075        ));
2076        assert!(matches!(
2077            common_emu_pcie.read_extended_capabilities(0x1000, &mut value),
2078            CommonHeaderResult::Failed(IoError::InvalidRegister)
2079        ));
2080    }
2081
2082    #[test]
2083    fn test_type0_emulator_save_restore() {
2084        use vmcore::save_restore::SaveRestore;
2085
2086        // Test Type 0 emulator save/restore
2087        let mut emu = create_type0_emulator(vec![]);
2088
2089        // Modify some state by writing to command register
2090        emu.write_u32(0x04, 0x0007).unwrap(); // Enable some command bits
2091
2092        // Read back and verify
2093        let mut test_val = 0u32;
2094        emu.read_u32(0x04, &mut test_val).unwrap();
2095        assert_eq!(test_val & 0x0007, 0x0007);
2096
2097        // Write to latency timer / interrupt register
2098        emu.write_u32(0x3C, 0x0040_0000).unwrap(); // Set latency_timer
2099
2100        // Save the state
2101        let saved_state = emu.save().expect("save should succeed");
2102
2103        // Reset the emulator
2104        emu.reset();
2105
2106        // Verify state is reset
2107        emu.read_u32(0x04, &mut test_val).unwrap();
2108        assert_eq!(test_val & 0x0007, 0x0000); // Should be reset
2109
2110        // Restore the state
2111        emu.restore(saved_state).expect("restore should succeed");
2112
2113        // Verify state is restored
2114        emu.read_u32(0x04, &mut test_val).unwrap();
2115        assert_eq!(test_val & 0x0007, 0x0007); // Should be restored
2116    }
2117
2118    #[test]
2119    fn test_type1_emulator_save_restore() {
2120        use vmcore::save_restore::SaveRestore;
2121
2122        // Test Type 1 emulator save/restore
2123        let mut emu = create_type1_emulator(vec![]);
2124
2125        // Modify some state
2126        emu.write_u32(0x04, 0x0003).unwrap(); // Enable command bits
2127        emu.write_u32(0x18, 0x0012_1000).unwrap(); // Set bus numbers
2128        emu.write_u32(0x20, 0xFFF0_FF00).unwrap(); // Set memory range
2129        emu.write_u32(0x24, 0xFFF0_FF00).unwrap(); // Set prefetch range
2130        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // Set prefetch base upper
2131        emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); // Set prefetch limit upper
2132        emu.write_u32(0x3C, 0x0001_0000).unwrap(); // Set bridge control
2133
2134        // Verify values
2135        let mut test_val = 0u32;
2136        emu.read_u32(0x04, &mut test_val).unwrap();
2137        assert_eq!(test_val & 0x0003, 0x0003);
2138        emu.read_u32(0x18, &mut test_val).unwrap();
2139        assert_eq!(test_val, 0x0012_1000);
2140        emu.read_u32(0x20, &mut test_val).unwrap();
2141        assert_eq!(test_val, 0xFFF0_FF00);
2142        emu.read_u32(0x28, &mut test_val).unwrap();
2143        assert_eq!(test_val, 0x00AA_BBCC);
2144        emu.read_u32(0x2C, &mut test_val).unwrap();
2145        assert_eq!(test_val, 0x00DD_EEFF);
2146        emu.read_u32(0x3C, &mut test_val).unwrap();
2147        assert_eq!(test_val >> 16, 0x0001); // bridge_control
2148
2149        // Save the state
2150        let saved_state = emu.save().expect("save should succeed");
2151
2152        // Reset the emulator
2153        emu.reset();
2154
2155        // Verify state is reset
2156        emu.read_u32(0x04, &mut test_val).unwrap();
2157        assert_eq!(test_val & 0x0003, 0x0000);
2158        emu.read_u32(0x18, &mut test_val).unwrap();
2159        assert_eq!(test_val, 0x0000_0000);
2160
2161        // Restore the state
2162        emu.restore(saved_state).expect("restore should succeed");
2163
2164        // Verify state is restored
2165        emu.read_u32(0x04, &mut test_val).unwrap();
2166        assert_eq!(test_val & 0x0003, 0x0003);
2167        emu.read_u32(0x18, &mut test_val).unwrap();
2168        assert_eq!(test_val, 0x0012_1000);
2169        emu.read_u32(0x20, &mut test_val).unwrap();
2170        assert_eq!(test_val, 0xFFF0_FF00);
2171        emu.read_u32(0x28, &mut test_val).unwrap();
2172        assert_eq!(test_val, 0x00AA_BBCC);
2173        emu.read_u32(0x2C, &mut test_val).unwrap();
2174        assert_eq!(test_val, 0x00DD_EEFF);
2175        emu.read_u32(0x3C, &mut test_val).unwrap();
2176        assert_eq!(test_val >> 16, 0x0001); // bridge_control
2177    }
2178
2179    #[test]
2180    fn test_config_space_type1_set_presence_detect_state() {
2181        // Test that ConfigSpaceType1Emulator can set presence detect state
2182        // when it has a PCIe Express capability with hotplug support
2183
2184        // Create a PCIe Express capability with hotplug support
2185        let pcie_cap =
2186            PciExpressCapability::new(DevicePortType::RootPort, None).with_hotplug_support(1);
2187
2188        let mut emulator = create_type1_emulator(vec![Box::new(pcie_cap)]);
2189
2190        // Initially, presence detect state should be 0
2191        let mut slot_status_val = 0u32;
2192        let result = emulator.read_u32(0x58, &mut slot_status_val); // 0x40 (cap start) + 0x18 (slot control/status)
2193        assert!(matches!(result, IoResult::Ok));
2194        let initial_presence_detect = (slot_status_val >> 22) & 0x1; // presence_detect_state is bit 6 of slot status
2195        assert_eq!(
2196            initial_presence_detect, 0,
2197            "Initial presence detect state should be 0"
2198        );
2199
2200        // Set device as present
2201        emulator.set_presence_detect_state(true);
2202        let result = emulator.read_u32(0x58, &mut slot_status_val);
2203        assert!(matches!(result, IoResult::Ok));
2204        let present_presence_detect = (slot_status_val >> 22) & 0x1;
2205        assert_eq!(
2206            present_presence_detect, 1,
2207            "Presence detect state should be 1 when device is present"
2208        );
2209
2210        // Set device as not present
2211        emulator.set_presence_detect_state(false);
2212        let result = emulator.read_u32(0x58, &mut slot_status_val);
2213        assert!(matches!(result, IoResult::Ok));
2214        let absent_presence_detect = (slot_status_val >> 22) & 0x1;
2215        assert_eq!(
2216            absent_presence_detect, 0,
2217            "Presence detect state should be 0 when device is not present"
2218        );
2219    }
2220
2221    #[test]
2222    fn test_config_space_type1_set_presence_detect_state_without_pcie() {
2223        // Test that ConfigSpaceType1Emulator silently ignores set_presence_detect_state
2224        // when there is no PCIe Express capability
2225
2226        let mut emulator = create_type1_emulator(vec![]); // No capabilities
2227
2228        // Should not panic and should be silently ignored
2229        emulator.set_presence_detect_state(true);
2230        emulator.set_presence_detect_state(false);
2231    }
2232
2233    #[test]
2234    fn test_interrupt_pin_register() {
2235        use vmcore::line_interrupt::LineInterrupt;
2236
2237        // Test Type 0 device with interrupt pin configured
2238        let mut emu = ConfigSpaceType0Emulator::new(
2239            HardwareIds {
2240                vendor_id: 0x1111,
2241                device_id: 0x2222,
2242                revision_id: 1,
2243                prog_if: ProgrammingInterface::NONE,
2244                sub_class: Subclass::NONE,
2245                base_class: ClassCode::UNCLASSIFIED,
2246                type0_sub_vendor_id: 0,
2247                type0_sub_system_id: 0,
2248            },
2249            vec![],
2250            DeviceBars::new(),
2251        );
2252
2253        // Initially, no interrupt pin should be configured
2254        let mut val = 0u32;
2255        emu.read_u32(0x3C, &mut val).unwrap(); // LATENCY_INTERRUPT register
2256        assert_eq!(val & 0xFF00, 0); // Interrupt pin should be 0
2257
2258        // Configure interrupt pin A
2259        let line_interrupt = LineInterrupt::detached();
2260        emu.set_interrupt_pin(PciInterruptPin::IntA, line_interrupt);
2261
2262        // Read the register again
2263        emu.read_u32(0x3C, &mut val).unwrap();
2264        assert_eq!((val >> 8) & 0xFF, 1); // Interrupt pin should be 1 (INTA)
2265
2266        // Set interrupt line to 0x42 and verify both pin and line are correct
2267        emu.write_u32(0x3C, 0x00110042).unwrap(); // Latency=0x11, pin=ignored, line=0x42
2268        emu.read_u32(0x3C, &mut val).unwrap();
2269        assert_eq!(val & 0xFF, 0x42); // Interrupt line should be 0x42
2270        assert_eq!((val >> 8) & 0xFF, 1); // Interrupt pin should still be 1 (writes ignored)
2271        assert_eq!((val >> 16) & 0xFF, 0x11); // Latency timer should be 0x11
2272
2273        // Test with interrupt pin D
2274        let mut emu_d = ConfigSpaceType0Emulator::new(
2275            HardwareIds {
2276                vendor_id: 0x1111,
2277                device_id: 0x2222,
2278                revision_id: 1,
2279                prog_if: ProgrammingInterface::NONE,
2280                sub_class: Subclass::NONE,
2281                base_class: ClassCode::UNCLASSIFIED,
2282                type0_sub_vendor_id: 0,
2283                type0_sub_system_id: 0,
2284            },
2285            vec![],
2286            DeviceBars::new(),
2287        );
2288
2289        let line_interrupt_d = LineInterrupt::detached();
2290        emu_d.set_interrupt_pin(PciInterruptPin::IntD, line_interrupt_d);
2291
2292        emu_d.read_u32(0x3C, &mut val).unwrap();
2293        assert_eq!((val >> 8) & 0xFF, 4); // Interrupt pin should be 4 (INTD)
2294    }
2295
2296    #[test]
2297    fn test_header_type_functionality() {
2298        // Test HeaderType enum values
2299        assert_eq!(HeaderType::Type0.bar_count(), 6);
2300        assert_eq!(HeaderType::Type1.bar_count(), 2);
2301        assert_eq!(usize::from(HeaderType::Type0), 6);
2302        assert_eq!(usize::from(HeaderType::Type1), 2);
2303
2304        // Test constant values
2305        assert_eq!(header_type_consts::TYPE0_BAR_COUNT, 6);
2306        assert_eq!(header_type_consts::TYPE1_BAR_COUNT, 2);
2307
2308        // Test Type 0 emulator
2309        let emu_type0 = create_type0_emulator(vec![]);
2310        assert_eq!(emu_type0.common.bar_count(), 6);
2311        assert_eq!(emu_type0.common.header_type(), HeaderType::Type0);
2312        assert!(emu_type0.common.validate_header_type(HeaderType::Type0));
2313        assert!(!emu_type0.common.validate_header_type(HeaderType::Type1));
2314
2315        // Test Type 1 emulator
2316        let emu_type1 = create_type1_emulator(vec![]);
2317        assert_eq!(emu_type1.common.bar_count(), 2);
2318        assert_eq!(emu_type1.common.header_type(), HeaderType::Type1);
2319        assert!(emu_type1.common.validate_header_type(HeaderType::Type1));
2320        assert!(!emu_type1.common.validate_header_type(HeaderType::Type0));
2321    }
2322}