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, u64)> {
708        self.active_bars.find(address)
709    }
710
711    /// Gets the active base address for a specific BAR index, if mapped.
712    pub fn bar_address(&self, bar: u8) -> Option<u64> {
713        self.active_bars.get(bar)
714    }
715
716    /// Check if this device is a PCIe device by looking for the PCI Express capability.
717    pub fn is_pcie_device(&self) -> bool {
718        self.capabilities
719            .iter()
720            .any(|cap| cap.capability_id() == CapabilityId::PCI_EXPRESS)
721    }
722
723    /// Get capability index and offset for a given offset
724    fn get_capability_index_and_offset(&self, offset: u16) -> Option<(usize, u16)> {
725        let mut cap_offset = 0;
726        for i in 0..self.capabilities.len() {
727            let cap_size = self.capabilities[i].len() as u16;
728            if offset < cap_offset + cap_size {
729                return Some((i, offset - cap_offset));
730            }
731            cap_offset += cap_size;
732        }
733        None
734    }
735
736    /// Check if an offset corresponds to a BAR register
737    fn is_bar_offset(&self, offset: u16) -> bool {
738        // Type 0: BAR0-BAR5 (0x10-0x27), Type 1: BAR0-BAR1 (0x10-0x17)
739        let bar_start = cfg_space::HeaderType00::BAR0.0;
740        let bar_end = bar_start + (N as u16) * 4;
741        (bar_start..bar_end).contains(&offset) && offset.is_multiple_of(4)
742    }
743
744    /// Get the BAR index for a given offset
745    fn get_bar_index(&self, offset: u16) -> usize {
746        ((offset - cfg_space::HeaderType00::BAR0.0) / 4) as usize
747    }
748
749    /// Get BAR masks (for testing only)
750    #[cfg(test)]
751    pub fn bar_masks(&self) -> &[u32; N] {
752        &self.bar_masks
753    }
754}
755
756#[derive(Debug, Inspect)]
757struct ConfigSpaceType0EmulatorState {
758    /// A read/write register that doesn't matter in virtualized contexts
759    latency_timer: u8,
760}
761
762impl ConfigSpaceType0EmulatorState {
763    fn new() -> Self {
764        Self { latency_timer: 0 }
765    }
766}
767
768/// Emulator for the standard Type 0 PCI configuration space header.
769#[derive(Inspect)]
770pub struct ConfigSpaceType0Emulator {
771    /// The common header emulator that handles shared functionality
772    #[inspect(flatten)]
773    common: ConfigSpaceCommonHeaderEmulatorType0,
774    /// Type 0 specific state
775    state: ConfigSpaceType0EmulatorState,
776}
777
778mod inspect_helpers {
779    use super::*;
780
781    pub(crate) fn bars_generic<const N: usize>(bars: &[u32; N]) -> impl Inspect + '_ {
782        inspect::AsHex(inspect::iter_by_index(bars).prefix("bar"))
783    }
784}
785
786/// Different kinds of memory that a BAR can be backed by
787#[derive(Inspect)]
788#[inspect(tag = "kind")]
789pub enum BarMemoryKind {
790    /// BAR memory is routed to the device's `MmioIntercept` handler
791    Intercept(#[inspect(rename = "handle")] Box<dyn ControlMmioIntercept>),
792    /// BAR memory is routed to a shared memory region
793    SharedMem(#[inspect(skip)] Box<dyn MappableGuestMemory>),
794    /// **TESTING ONLY** BAR memory isn't backed by anything!
795    Dummy,
796}
797
798impl std::fmt::Debug for BarMemoryKind {
799    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
800        match self {
801            Self::Intercept(control) => {
802                write!(f, "Intercept(region_name: {}, ..)", control.region_name())
803            }
804            Self::SharedMem(_) => write!(f, "Mmap(..)"),
805            Self::Dummy => write!(f, "Dummy"),
806        }
807    }
808}
809
810impl BarMemoryKind {
811    fn map_to_guest(&mut self, gpa: u64) -> std::io::Result<()> {
812        match self {
813            BarMemoryKind::Intercept(control) => {
814                control.map(gpa);
815                Ok(())
816            }
817            BarMemoryKind::SharedMem(control) => control.map_to_guest(gpa, true),
818            BarMemoryKind::Dummy => Ok(()),
819        }
820    }
821
822    fn unmap_from_guest(&mut self) {
823        match self {
824            BarMemoryKind::Intercept(control) => control.unmap(),
825            BarMemoryKind::SharedMem(control) => control.unmap_from_guest(),
826            BarMemoryKind::Dummy => {}
827        }
828    }
829}
830
831/// Container type that describes a device's available BARs
832// TODO: support more advanced BAR configurations
833// e.g: mixed 32-bit and 64-bit
834// e.g: IO space BARs
835#[derive(Debug)]
836pub struct DeviceBars {
837    bars: [Option<(u64, BarMemoryKind)>; 6],
838}
839
840impl DeviceBars {
841    /// Create a new instance of [`DeviceBars`]
842    pub fn new() -> DeviceBars {
843        DeviceBars {
844            bars: Default::default(),
845        }
846    }
847
848    /// Set BAR0
849    pub fn bar0(mut self, len: u64, memory: BarMemoryKind) -> Self {
850        self.bars[0] = Some((len, memory));
851        self
852    }
853
854    /// Set BAR2
855    pub fn bar2(mut self, len: u64, memory: BarMemoryKind) -> Self {
856        self.bars[2] = Some((len, memory));
857        self
858    }
859
860    /// Set BAR4
861    pub fn bar4(mut self, len: u64, memory: BarMemoryKind) -> Self {
862        self.bars[4] = Some((len, memory));
863        self
864    }
865}
866
867impl ConfigSpaceType0Emulator {
868    /// Create a new [`ConfigSpaceType0Emulator`]
869    pub fn new(
870        hardware_ids: HardwareIds,
871        capabilities: Vec<Box<dyn PciCapability>>,
872        bars: DeviceBars,
873    ) -> Self {
874        let common = ConfigSpaceCommonHeaderEmulator::new(hardware_ids, capabilities, bars);
875
876        Self {
877            common,
878            state: ConfigSpaceType0EmulatorState::new(),
879        }
880    }
881
882    /// If the device is multi-function, enable bit 7 in the Header register.
883    pub fn with_multi_function_bit(mut self, bit: bool) -> Self {
884        self.common = self.common.with_multi_function_bit(bit);
885        self
886    }
887
888    /// If using legacy INT#x interrupts: wire a LineInterrupt to one of the 4
889    /// INT#x pins, returning an object that manages configuration space bits
890    /// when the device sets the interrupt level.
891    pub fn set_interrupt_pin(
892        &mut self,
893        pin: PciInterruptPin,
894        line: LineInterrupt,
895    ) -> Arc<IntxInterrupt> {
896        self.common.set_interrupt_pin(pin, line)
897    }
898
899    /// Resets the configuration space state.
900    pub fn reset(&mut self) {
901        self.common.reset();
902        self.state = ConfigSpaceType0EmulatorState::new();
903    }
904
905    /// Read from the config space. `offset` must be 32-bit aligned.
906    pub fn read_u32(&self, offset: u16, value: &mut u32) -> IoResult {
907        use cfg_space::HeaderType00;
908
909        // First try to handle with common header emulator
910        match self.common.read_u32(offset, value) {
911            CommonHeaderResult::Handled => return IoResult::Ok,
912            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
913            CommonHeaderResult::Unhandled => {
914                // Continue with Type 0 specific handling
915            }
916        }
917
918        // Handle Type 0 specific registers
919        *value = match HeaderType00(offset) {
920            HeaderType00::BIST_HEADER => {
921                let mut v = (self.state.latency_timer as u32) << 8;
922                if self.common.multi_function_bit() {
923                    // enable top-most bit of the header register
924                    v |= 0x80 << 16;
925                }
926                v
927            }
928            HeaderType00::CARDBUS_CIS_PTR => 0,
929            HeaderType00::SUBSYSTEM_ID => {
930                (self.common.hardware_ids().type0_sub_system_id as u32) << 16
931                    | self.common.hardware_ids().type0_sub_vendor_id as u32
932            }
933            HeaderType00::EXPANSION_ROM_BASE => 0,
934            HeaderType00::RESERVED => 0,
935            HeaderType00::LATENCY_INTERRUPT => {
936                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin, Bits 31-16: Latency Timer
937                (self.state.latency_timer as u32) << 16
938                    | (self.common.interrupt_pin() as u32) << 8
939                    | self.common.interrupt_line() as u32
940            }
941            _ => {
942                tracelimit::warn_ratelimited!(offset, "unexpected config space read");
943                return IoResult::Err(IoError::InvalidRegister);
944            }
945        };
946
947        IoResult::Ok
948    }
949
950    /// Write to the config space. `offset` must be 32-bit aligned.
951    pub fn write_u32(&mut self, offset: u16, val: u32) -> IoResult {
952        use cfg_space::HeaderType00;
953
954        // First try to handle with common header emulator
955        match self.common.write_u32(offset, val) {
956            CommonHeaderResult::Handled => return IoResult::Ok,
957            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
958            CommonHeaderResult::Unhandled => {
959                // Continue with Type 0 specific handling
960            }
961        }
962
963        // Handle Type 0 specific registers
964        match HeaderType00(offset) {
965            HeaderType00::BIST_HEADER => {
966                // BIST_HEADER - Type 0 specific handling
967                // For now, just ignore these writes (header type is read-only)
968            }
969            HeaderType00::LATENCY_INTERRUPT => {
970                // Bits 7-0: Interrupt Line (read/write)
971                // Bits 15-8: Interrupt Pin (read-only, ignore writes)
972                // Bits 31-16: Latency Timer (read/write)
973                self.common.set_interrupt_line((val & 0xff) as u8);
974                self.state.latency_timer = (val >> 16) as u8;
975            }
976            // all other base regs are noops
977            _ if offset < 0x40 && offset.is_multiple_of(4) => (),
978            _ => {
979                tracelimit::warn_ratelimited!(offset, value = val, "unexpected config space write");
980                return IoResult::Err(IoError::InvalidRegister);
981            }
982        }
983
984        IoResult::Ok
985    }
986
987    /// Finds a BAR + offset by address.
988    pub fn find_bar(&self, address: u64) -> Option<(u8, u64)> {
989        self.common.find_bar(address)
990    }
991
992    /// Gets the active base address for a specific BAR index, if mapped.
993    pub fn bar_address(&self, bar: u8) -> Option<u64> {
994        self.common.bar_address(bar)
995    }
996
997    /// Checks if this device is a PCIe device by looking for the PCI Express capability.
998    pub fn is_pcie_device(&self) -> bool {
999        self.common.is_pcie_device()
1000    }
1001
1002    /// Set the presence detect state for a hotplug-capable slot.
1003    /// This method finds the PCIe Express capability and calls its set_presence_detect_state method.
1004    /// If the PCIe Express capability is not found, the call is silently ignored.
1005    ///
1006    /// # Arguments
1007    /// * `present` - true if a device is present in the slot, false if the slot is empty
1008    pub fn set_presence_detect_state(&mut self, present: bool) {
1009        for capability in self.common.capabilities_mut() {
1010            if let Some(pcie_cap) = capability.as_pci_express_mut() {
1011                pcie_cap.set_presence_detect_state(present);
1012                return;
1013            }
1014        }
1015
1016        // PCIe Express capability not found - silently ignore
1017    }
1018}
1019
1020#[derive(Debug, Inspect)]
1021struct ConfigSpaceType1EmulatorState {
1022    /// The subordinate bus number register. Software programs
1023    /// this register with the highest bus number below the bridge.
1024    #[inspect(hex)]
1025    subordinate_bus_number: u8,
1026    /// The secondary bus number register. Software programs
1027    /// this register with the bus number assigned to the secondary
1028    /// side of the bridge.
1029    #[inspect(hex)]
1030    secondary_bus_number: u8,
1031    /// The primary bus number register. This is unused for PCI Express but
1032    /// is supposed to be read/write for compability with legacy software.
1033    #[inspect(hex)]
1034    primary_bus_number: u8,
1035    /// The memory base register. Software programs the upper 12 bits of this
1036    /// register with the upper 12 bits of a 32-bit base address of MMIO assigned
1037    /// to the hierarchy under the bridge (the lower 20 bits are assumed to be 0s).
1038    #[inspect(hex)]
1039    memory_base: u16,
1040    /// The memory limit register. Software programs the upper 12 bits of this
1041    /// register with the upper 12 bits of a 32-bit limit address of MMIO assigned
1042    /// to the hierarchy under the bridge (the lower 20 bits are assumed to be 1s).
1043    #[inspect(hex)]
1044    memory_limit: u16,
1045    /// The prefetchable memory base register. Software programs the upper 12 bits of
1046    /// this register with bits 20:31 of the base address of the prefetchable MMIO
1047    /// window assigned to the hierarchy under the bridge. Bits 0:19 are assumed to
1048    /// be 0s.
1049    #[inspect(hex)]
1050    prefetch_base: u16,
1051    /// The prefetchable memory limit register. Software programs the upper 12 bits of
1052    /// this register with bits 20:31 of the limit address of the prefetchable MMIO
1053    /// window assigned to the hierarchy under the bridge. Bits 0:19 are assumed to
1054    /// be 1s.
1055    #[inspect(hex)]
1056    prefetch_limit: u16,
1057    /// The prefetchable memory base upper 32 bits register. When the bridge supports
1058    /// 64-bit addressing for prefetchable memory, software programs this register
1059    /// with the upper 32 bits of the base address of the prefetchable MMIO window
1060    /// assigned to the hierarchy under the bridge.
1061    #[inspect(hex)]
1062    prefetch_base_upper: u32,
1063    /// The prefetchable memory limit upper 32 bits register. When the bridge supports
1064    /// 64-bit addressing for prefetchable memory, software programs this register
1065    /// with the upper 32 bits of the base address of the prefetchable MMIO window
1066    /// assigned to the hierarchy under the bridge.
1067    #[inspect(hex)]
1068    prefetch_limit_upper: u32,
1069    /// The bridge control register. Contains various control bits for bridge behavior
1070    /// such as secondary bus reset, VGA enable, etc.
1071    #[inspect(hex)]
1072    bridge_control: u16,
1073}
1074
1075impl ConfigSpaceType1EmulatorState {
1076    fn new() -> Self {
1077        Self {
1078            subordinate_bus_number: 0,
1079            secondary_bus_number: 0,
1080            primary_bus_number: 0,
1081            memory_base: 0,
1082            memory_limit: 0,
1083            prefetch_base: 0,
1084            prefetch_limit: 0,
1085            prefetch_base_upper: 0,
1086            prefetch_limit_upper: 0,
1087            bridge_control: 0,
1088        }
1089    }
1090}
1091
1092/// Emulator for the standard Type 1 PCI configuration space header.
1093#[derive(Inspect)]
1094pub struct ConfigSpaceType1Emulator {
1095    /// The common header emulator that handles shared functionality
1096    #[inspect(flatten)]
1097    common: ConfigSpaceCommonHeaderEmulatorType1,
1098    /// Type 1 specific state
1099    state: ConfigSpaceType1EmulatorState,
1100}
1101
1102impl ConfigSpaceType1Emulator {
1103    /// Create a new [`ConfigSpaceType1Emulator`]
1104    pub fn new(hardware_ids: HardwareIds, capabilities: Vec<Box<dyn PciCapability>>) -> Self {
1105        let common =
1106            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, capabilities, DeviceBars::new());
1107
1108        Self {
1109            common,
1110            state: ConfigSpaceType1EmulatorState::new(),
1111        }
1112    }
1113
1114    /// Resets the configuration space state.
1115    pub fn reset(&mut self) {
1116        self.common.reset();
1117        self.state = ConfigSpaceType1EmulatorState::new();
1118    }
1119
1120    /// Set the multi-function bit for this device.
1121    pub fn with_multi_function_bit(mut self, multi_function: bool) -> Self {
1122        self.common = self.common.with_multi_function_bit(multi_function);
1123        self
1124    }
1125
1126    /// Returns the range of bus numbers the bridge is programmed to decode.
1127    pub fn assigned_bus_range(&self) -> RangeInclusive<u8> {
1128        let secondary = self.state.secondary_bus_number;
1129        let subordinate = self.state.subordinate_bus_number;
1130        if secondary <= subordinate {
1131            secondary..=subordinate
1132        } else {
1133            0..=0
1134        }
1135    }
1136
1137    fn decode_memory_range(&self, base_register: u16, limit_register: u16) -> (u32, u32) {
1138        let base_addr = ((base_register & !0b1111) as u32) << 16;
1139        let limit_addr = ((limit_register & !0b1111) as u32) << 16 | 0xF_FFFF;
1140        (base_addr, limit_addr)
1141    }
1142
1143    /// If memory decoding is currently enabled, and the memory window assignment is valid,
1144    /// returns the 32-bit memory addresses the bridge is programmed to decode.
1145    pub fn assigned_memory_range(&self) -> Option<RangeInclusive<u32>> {
1146        let (base_addr, limit_addr) =
1147            self.decode_memory_range(self.state.memory_base, self.state.memory_limit);
1148        if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1149            Some(base_addr..=limit_addr)
1150        } else {
1151            None
1152        }
1153    }
1154
1155    /// If memory decoding is currently enabled, and the prefetchable memory window assignment
1156    /// is valid, returns the 64-bit prefetchable memory addresses the bridge is programmed to decode.
1157    pub fn assigned_prefetch_range(&self) -> Option<RangeInclusive<u64>> {
1158        let (base_low, limit_low) =
1159            self.decode_memory_range(self.state.prefetch_base, self.state.prefetch_limit);
1160        let base_addr = (self.state.prefetch_base_upper as u64) << 32 | base_low as u64;
1161        let limit_addr = (self.state.prefetch_limit_upper as u64) << 32 | limit_low as u64;
1162        if self.common.command().mmio_enabled() && base_addr <= limit_addr {
1163            Some(base_addr..=limit_addr)
1164        } else {
1165            None
1166        }
1167    }
1168
1169    /// Read from the config space. `offset` must be 32-bit aligned.
1170    pub fn read_u32(&self, offset: u16, value: &mut u32) -> IoResult {
1171        use cfg_space::HeaderType01;
1172
1173        // First try to handle with common header emulator
1174        match self.common.read_u32(offset, value) {
1175            CommonHeaderResult::Handled => return IoResult::Ok,
1176            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1177            CommonHeaderResult::Unhandled => {
1178                // Continue with Type 1 specific handling
1179            }
1180        }
1181
1182        // Handle Type 1 specific registers
1183        *value = match HeaderType01(offset) {
1184            HeaderType01::BIST_HEADER => {
1185                // Header type 01 with optional multi-function bit
1186                if self.common.multi_function_bit() {
1187                    0x00810000 // Header type 01 with multi-function bit (bit 23)
1188                } else {
1189                    0x00010000 // Header type 01 without multi-function bit
1190                }
1191            }
1192            HeaderType01::LATENCY_BUS_NUMBERS => {
1193                (self.state.subordinate_bus_number as u32) << 16
1194                    | (self.state.secondary_bus_number as u32) << 8
1195                    | self.state.primary_bus_number as u32
1196            }
1197            HeaderType01::SEC_STATUS_IO_RANGE => 0,
1198            HeaderType01::MEMORY_RANGE => {
1199                (self.state.memory_limit as u32) << 16 | self.state.memory_base as u32
1200            }
1201            HeaderType01::PREFETCH_RANGE => {
1202                // Set the low bit in both the limit and base registers to indicate
1203                // support for 64-bit addressing.
1204                ((self.state.prefetch_limit | 0b0001) as u32) << 16
1205                    | (self.state.prefetch_base | 0b0001) as u32
1206            }
1207            HeaderType01::PREFETCH_BASE_UPPER => self.state.prefetch_base_upper,
1208            HeaderType01::PREFETCH_LIMIT_UPPER => self.state.prefetch_limit_upper,
1209            HeaderType01::IO_RANGE_UPPER => 0,
1210            HeaderType01::EXPANSION_ROM_BASE => 0,
1211            HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1212                // Read interrupt line from common header and bridge control from state
1213                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin (0), Bits 31-16: Bridge Control
1214                (self.state.bridge_control as u32) << 16 | self.common.interrupt_line() as u32
1215            }
1216            _ => {
1217                tracelimit::warn_ratelimited!(offset, "unexpected config space read");
1218                return IoResult::Err(IoError::InvalidRegister);
1219            }
1220        };
1221
1222        IoResult::Ok
1223    }
1224
1225    /// Write to the config space. `offset` must be 32-bit aligned.
1226    pub fn write_u32(&mut self, offset: u16, val: u32) -> IoResult {
1227        use cfg_space::HeaderType01;
1228
1229        // First try to handle with common header emulator
1230        match self.common.write_u32(offset, val) {
1231            CommonHeaderResult::Handled => return IoResult::Ok,
1232            CommonHeaderResult::Failed(err) => return IoResult::Err(err),
1233            CommonHeaderResult::Unhandled => {
1234                // Continue with Type 1 specific handling
1235            }
1236        }
1237
1238        // Handle Type 1 specific registers
1239        match HeaderType01(offset) {
1240            HeaderType01::BIST_HEADER => {
1241                // BIST_HEADER - Type 1 specific handling
1242                // For now, just ignore these writes (latency timer would go here if supported)
1243            }
1244            HeaderType01::LATENCY_BUS_NUMBERS => {
1245                self.state.subordinate_bus_number = (val >> 16) as u8;
1246                self.state.secondary_bus_number = (val >> 8) as u8;
1247                self.state.primary_bus_number = val as u8;
1248            }
1249            HeaderType01::MEMORY_RANGE => {
1250                self.state.memory_base = val as u16;
1251                self.state.memory_limit = (val >> 16) as u16;
1252            }
1253            HeaderType01::PREFETCH_RANGE => {
1254                self.state.prefetch_base = val as u16;
1255                self.state.prefetch_limit = (val >> 16) as u16;
1256            }
1257            HeaderType01::PREFETCH_BASE_UPPER => {
1258                self.state.prefetch_base_upper = val;
1259            }
1260            HeaderType01::PREFETCH_LIMIT_UPPER => {
1261                self.state.prefetch_limit_upper = val;
1262            }
1263            HeaderType01::BRDIGE_CTRL_INTERRUPT => {
1264                // Delegate interrupt line writes to common header and store bridge control
1265                // Bits 7-0: Interrupt Line, Bits 15-8: Interrupt Pin (ignored), Bits 31-16: Bridge Control
1266                self.common.set_interrupt_line((val & 0xff) as u8);
1267                self.state.bridge_control = (val >> 16) as u16;
1268            }
1269            // all other base regs are noops
1270            _ if offset < 0x40 && offset.is_multiple_of(4) => (),
1271            _ => {
1272                tracelimit::warn_ratelimited!(offset, value = val, "unexpected config space write");
1273                return IoResult::Err(IoError::InvalidRegister);
1274            }
1275        }
1276
1277        IoResult::Ok
1278    }
1279
1280    /// Checks if this device is a PCIe device by looking for the PCI Express capability.
1281    pub fn is_pcie_device(&self) -> bool {
1282        self.common.is_pcie_device()
1283    }
1284
1285    /// Set the presence detect state for the slot.
1286    /// This method finds the PCIe Express capability and calls its set_presence_detect_state method.
1287    /// If the PCIe Express capability is not found, the call is silently ignored.
1288    ///
1289    /// # Arguments
1290    /// * `present` - true if a device is present in the slot, false if the slot is empty
1291    pub fn set_presence_detect_state(&mut self, present: bool) {
1292        // Find the PCIe Express capability
1293        for cap in self.common.capabilities_mut() {
1294            if cap.capability_id() == CapabilityId::PCI_EXPRESS {
1295                // Downcast to PciExpressCapability and call set_presence_detect_state
1296                if let Some(pcie_cap) = cap.as_pci_express_mut() {
1297                    pcie_cap.set_presence_detect_state(present);
1298                    return;
1299                }
1300            }
1301        }
1302        // If no PCIe Express capability is found, silently ignore the call
1303    }
1304
1305    /// Get the list of PCI capabilities.
1306    pub fn capabilities(&self) -> &[Box<dyn PciCapability>] {
1307        self.common.capabilities()
1308    }
1309
1310    /// Get the list of PCI capabilities (mutable).
1311    pub fn capabilities_mut(&mut self) -> &mut [Box<dyn PciCapability>] {
1312        self.common.capabilities_mut()
1313    }
1314}
1315
1316mod save_restore {
1317    use super::*;
1318    use thiserror::Error;
1319    use vmcore::save_restore::RestoreError;
1320    use vmcore::save_restore::SaveError;
1321    use vmcore::save_restore::SaveRestore;
1322
1323    mod state {
1324        use mesh::payload::Protobuf;
1325        use vmcore::save_restore::SavedStateBlob;
1326        use vmcore::save_restore::SavedStateRoot;
1327
1328        /// Unified saved state for both Type 0 and Type 1 PCI configuration space emulators.
1329        /// Type 1 specific fields (mesh indices 6-15) will be ignored when restoring Type 0 devices,
1330        /// and will have default values (0) when restoring old save state to Type 1 devices.
1331        #[derive(Protobuf, SavedStateRoot)]
1332        #[mesh(package = "pci.cfg_space_emu")]
1333        pub struct SavedState {
1334            // Common fields (used by both Type 0 and Type 1)
1335            #[mesh(1)]
1336            pub command: u16,
1337            #[mesh(2)]
1338            pub base_addresses: [u32; 6],
1339            #[mesh(3)]
1340            pub interrupt_line: u8,
1341            #[mesh(4)]
1342            pub latency_timer: u8,
1343            #[mesh(5)]
1344            pub capabilities: Vec<(String, SavedStateBlob)>,
1345
1346            // Type 1 specific fields (bridge devices)
1347            // These fields default to 0 for backward compatibility with old save state
1348            #[mesh(6)]
1349            pub subordinate_bus_number: u8,
1350            #[mesh(7)]
1351            pub secondary_bus_number: u8,
1352            #[mesh(8)]
1353            pub primary_bus_number: u8,
1354            #[mesh(9)]
1355            pub memory_base: u16,
1356            #[mesh(10)]
1357            pub memory_limit: u16,
1358            #[mesh(11)]
1359            pub prefetch_base: u16,
1360            #[mesh(12)]
1361            pub prefetch_limit: u16,
1362            #[mesh(13)]
1363            pub prefetch_base_upper: u32,
1364            #[mesh(14)]
1365            pub prefetch_limit_upper: u32,
1366            #[mesh(15)]
1367            pub bridge_control: u16,
1368        }
1369    }
1370
1371    #[derive(Debug, Error)]
1372    enum ConfigSpaceRestoreError {
1373        #[error("found invalid config bits in saved state")]
1374        InvalidConfigBits,
1375        #[error("found unexpected capability {0}")]
1376        InvalidCap(String),
1377    }
1378
1379    impl SaveRestore for ConfigSpaceType0Emulator {
1380        type SavedState = state::SavedState;
1381
1382        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1383            let ConfigSpaceType0EmulatorState { latency_timer } = self.state;
1384
1385            let saved_state = state::SavedState {
1386                command: self.common.command().into_bits(),
1387                base_addresses: *self.common.base_addresses(),
1388                interrupt_line: self.common.interrupt_line(),
1389                latency_timer,
1390                capabilities: self
1391                    .common
1392                    .capabilities_mut()
1393                    .iter_mut()
1394                    .map(|cap| {
1395                        let id = cap.label().to_owned();
1396                        Ok((id, cap.save()?))
1397                    })
1398                    .collect::<Result<_, _>>()?,
1399                // Type 1 specific fields - not used for Type 0
1400                subordinate_bus_number: 0,
1401                secondary_bus_number: 0,
1402                primary_bus_number: 0,
1403                memory_base: 0,
1404                memory_limit: 0,
1405                prefetch_base: 0,
1406                prefetch_limit: 0,
1407                prefetch_base_upper: 0,
1408                prefetch_limit_upper: 0,
1409                bridge_control: 0,
1410            };
1411
1412            Ok(saved_state)
1413        }
1414
1415        fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1416            let state::SavedState {
1417                command,
1418                base_addresses,
1419                interrupt_line,
1420                latency_timer,
1421                capabilities,
1422                // Type 1 specific fields - ignored for Type 0
1423                subordinate_bus_number: _,
1424                secondary_bus_number: _,
1425                primary_bus_number: _,
1426                memory_base: _,
1427                memory_limit: _,
1428                prefetch_base: _,
1429                prefetch_limit: _,
1430                prefetch_base_upper: _,
1431                prefetch_limit_upper: _,
1432                bridge_control: _,
1433            } = state;
1434
1435            self.state = ConfigSpaceType0EmulatorState { latency_timer };
1436
1437            self.common.set_base_addresses(&base_addresses);
1438            self.common.set_interrupt_line(interrupt_line);
1439            self.common
1440                .set_command(cfg_space::Command::from_bits(command));
1441
1442            if command & !SUPPORTED_COMMAND_BITS != 0 {
1443                return Err(RestoreError::InvalidSavedState(
1444                    ConfigSpaceRestoreError::InvalidConfigBits.into(),
1445                ));
1446            }
1447
1448            self.common.sync_command_register(self.common.command());
1449
1450            for (id, entry) in capabilities {
1451                tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1452
1453                // yes, yes, this is O(n^2), but devices never have more than a
1454                // handful of caps, so it's totally fine.
1455                let mut restored = false;
1456                for cap in self.common.capabilities_mut() {
1457                    if cap.label() == id {
1458                        cap.restore(entry)?;
1459                        restored = true;
1460                        break;
1461                    }
1462                }
1463
1464                if !restored {
1465                    return Err(RestoreError::InvalidSavedState(
1466                        ConfigSpaceRestoreError::InvalidCap(id).into(),
1467                    ));
1468                }
1469            }
1470
1471            Ok(())
1472        }
1473    }
1474
1475    impl SaveRestore for ConfigSpaceType1Emulator {
1476        type SavedState = state::SavedState;
1477
1478        fn save(&mut self) -> Result<Self::SavedState, SaveError> {
1479            let ConfigSpaceType1EmulatorState {
1480                subordinate_bus_number,
1481                secondary_bus_number,
1482                primary_bus_number,
1483                memory_base,
1484                memory_limit,
1485                prefetch_base,
1486                prefetch_limit,
1487                prefetch_base_upper,
1488                prefetch_limit_upper,
1489                bridge_control,
1490            } = self.state;
1491
1492            // Pad base_addresses to 6 elements for saved state (Type 1 uses 2 BARs)
1493            let type1_base_addresses = self.common.base_addresses();
1494            let mut saved_base_addresses = [0u32; 6];
1495            saved_base_addresses[0] = type1_base_addresses[0];
1496            saved_base_addresses[1] = type1_base_addresses[1];
1497
1498            let saved_state = state::SavedState {
1499                command: self.common.command().into_bits(),
1500                base_addresses: saved_base_addresses,
1501                interrupt_line: self.common.interrupt_line(),
1502                latency_timer: 0, // Not used for Type 1
1503                capabilities: self
1504                    .common
1505                    .capabilities_mut()
1506                    .iter_mut()
1507                    .map(|cap| {
1508                        let id = cap.label().to_owned();
1509                        Ok((id, cap.save()?))
1510                    })
1511                    .collect::<Result<_, _>>()?,
1512                // Type 1 specific fields
1513                subordinate_bus_number,
1514                secondary_bus_number,
1515                primary_bus_number,
1516                memory_base,
1517                memory_limit,
1518                prefetch_base,
1519                prefetch_limit,
1520                prefetch_base_upper,
1521                prefetch_limit_upper,
1522                bridge_control,
1523            };
1524
1525            Ok(saved_state)
1526        }
1527
1528        fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
1529            let state::SavedState {
1530                command,
1531                base_addresses,
1532                interrupt_line,
1533                latency_timer: _, // Not used for Type 1
1534                capabilities,
1535                subordinate_bus_number,
1536                secondary_bus_number,
1537                primary_bus_number,
1538                memory_base,
1539                memory_limit,
1540                prefetch_base,
1541                prefetch_limit,
1542                prefetch_base_upper,
1543                prefetch_limit_upper,
1544                bridge_control,
1545            } = state;
1546
1547            self.state = ConfigSpaceType1EmulatorState {
1548                subordinate_bus_number,
1549                secondary_bus_number,
1550                primary_bus_number,
1551                memory_base,
1552                memory_limit,
1553                prefetch_base,
1554                prefetch_limit,
1555                prefetch_base_upper,
1556                prefetch_limit_upper,
1557                bridge_control,
1558            };
1559
1560            // Pad base_addresses to 6 elements for common header (Type 1 uses 2 BARs)
1561            let mut full_base_addresses = [0u32; 6];
1562            for (i, &addr) in base_addresses.iter().enumerate().take(2) {
1563                full_base_addresses[i] = addr;
1564            }
1565            self.common
1566                .set_base_addresses(&[full_base_addresses[0], full_base_addresses[1]]);
1567            self.common.set_interrupt_line(interrupt_line);
1568            self.common
1569                .set_command(cfg_space::Command::from_bits(command));
1570
1571            if command & !SUPPORTED_COMMAND_BITS != 0 {
1572                return Err(RestoreError::InvalidSavedState(
1573                    ConfigSpaceRestoreError::InvalidConfigBits.into(),
1574                ));
1575            }
1576
1577            self.common.sync_command_register(self.common.command());
1578
1579            for (id, entry) in capabilities {
1580                tracing::debug!(save_id = id.as_str(), "restoring pci capability");
1581
1582                let mut restored = false;
1583                for cap in self.common.capabilities_mut() {
1584                    if cap.label() == id {
1585                        cap.restore(entry)?;
1586                        restored = true;
1587                        break;
1588                    }
1589                }
1590
1591                if !restored {
1592                    return Err(RestoreError::InvalidSavedState(
1593                        ConfigSpaceRestoreError::InvalidCap(id).into(),
1594                    ));
1595                }
1596            }
1597
1598            Ok(())
1599        }
1600    }
1601}
1602
1603#[cfg(test)]
1604mod tests {
1605    use super::*;
1606    use crate::capabilities::pci_express::PciExpressCapability;
1607    use crate::capabilities::read_only::ReadOnlyCapability;
1608    use crate::spec::caps::pci_express::DevicePortType;
1609    use crate::spec::hwid::ClassCode;
1610    use crate::spec::hwid::ProgrammingInterface;
1611    use crate::spec::hwid::Subclass;
1612
1613    fn create_type0_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType0Emulator {
1614        ConfigSpaceType0Emulator::new(
1615            HardwareIds {
1616                vendor_id: 0x1111,
1617                device_id: 0x2222,
1618                revision_id: 1,
1619                prog_if: ProgrammingInterface::NONE,
1620                sub_class: Subclass::NONE,
1621                base_class: ClassCode::UNCLASSIFIED,
1622                type0_sub_vendor_id: 0x3333,
1623                type0_sub_system_id: 0x4444,
1624            },
1625            caps,
1626            DeviceBars::new(),
1627        )
1628    }
1629
1630    fn create_type1_emulator(caps: Vec<Box<dyn PciCapability>>) -> ConfigSpaceType1Emulator {
1631        ConfigSpaceType1Emulator::new(
1632            HardwareIds {
1633                vendor_id: 0x1111,
1634                device_id: 0x2222,
1635                revision_id: 1,
1636                prog_if: ProgrammingInterface::NONE,
1637                sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1638                base_class: ClassCode::BRIDGE,
1639                type0_sub_vendor_id: 0,
1640                type0_sub_system_id: 0,
1641            },
1642            caps,
1643        )
1644    }
1645
1646    fn read_cfg(emulator: &ConfigSpaceType1Emulator, offset: u16) -> u32 {
1647        let mut val = 0;
1648        emulator.read_u32(offset, &mut val).unwrap();
1649        val
1650    }
1651
1652    #[test]
1653    fn test_type1_probe() {
1654        let emu = create_type1_emulator(vec![]);
1655        assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1656        assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0); // Capabilities pointer
1657
1658        let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1659        assert_eq!(read_cfg(&emu, 0), 0x2222_1111);
1660        assert_eq!(read_cfg(&emu, 4) & 0x10_0000, 0x10_0000); // Capabilities pointer
1661    }
1662
1663    #[test]
1664    fn test_type1_bus_number_assignment() {
1665        let mut emu = create_type1_emulator(vec![]);
1666
1667        // The bus number (and latency timer) registers are
1668        // all default 0.
1669        assert_eq!(read_cfg(&emu, 0x18), 0);
1670        assert_eq!(emu.assigned_bus_range(), 0..=0);
1671
1672        // The bus numbers can be programmed one by one,
1673        // and the range may not be valid during the middle
1674        // of allocation.
1675        emu.write_u32(0x18, 0x0000_1000).unwrap();
1676        assert_eq!(read_cfg(&emu, 0x18), 0x0000_1000);
1677        assert_eq!(emu.assigned_bus_range(), 0..=0);
1678        emu.write_u32(0x18, 0x0012_1000).unwrap();
1679        assert_eq!(read_cfg(&emu, 0x18), 0x0012_1000);
1680        assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1681
1682        // The primary bus number register is read/write for compatability
1683        // but unused.
1684        emu.write_u32(0x18, 0x0012_1033).unwrap();
1685        assert_eq!(read_cfg(&emu, 0x18), 0x0012_1033);
1686        assert_eq!(emu.assigned_bus_range(), 0x10..=0x12);
1687
1688        // Software can also just write the entire 4byte value at once
1689        emu.write_u32(0x18, 0x0047_4411).unwrap();
1690        assert_eq!(read_cfg(&emu, 0x18), 0x0047_4411);
1691        assert_eq!(emu.assigned_bus_range(), 0x44..=0x47);
1692
1693        // The subordinate bus number can equal the secondary bus number...
1694        emu.write_u32(0x18, 0x0088_8800).unwrap();
1695        assert_eq!(emu.assigned_bus_range(), 0x88..=0x88);
1696
1697        // ... but it cannot be less, that's a confused guest OS.
1698        emu.write_u32(0x18, 0x0087_8800).unwrap();
1699        assert_eq!(emu.assigned_bus_range(), 0..=0);
1700    }
1701
1702    #[test]
1703    fn test_type1_memory_assignment() {
1704        const MMIO_ENABLED: u32 = 0x0000_0002;
1705        const MMIO_DISABLED: u32 = 0x0000_0000;
1706
1707        let mut emu = create_type1_emulator(vec![]);
1708        assert!(emu.assigned_memory_range().is_none());
1709
1710        // The guest can write whatever it wants while MMIO
1711        // is disabled.
1712        emu.write_u32(0x20, 0xDEAD_BEEF).unwrap();
1713        assert!(emu.assigned_memory_range().is_none());
1714
1715        // The guest can program a valid resource assignment...
1716        emu.write_u32(0x20, 0xFFF0_FF00).unwrap();
1717        assert!(emu.assigned_memory_range().is_none());
1718        // ... enable memory decoding...
1719        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1720        assert_eq!(emu.assigned_memory_range(), Some(0xFF00_0000..=0xFFFF_FFFF));
1721        // ... then disable memory decoding it.
1722        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1723        assert!(emu.assigned_memory_range().is_none());
1724
1725        // Setting memory base equal to memory limit is a valid 1MB range.
1726        emu.write_u32(0x20, 0xBBB0_BBB0).unwrap();
1727        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1728        assert_eq!(emu.assigned_memory_range(), Some(0xBBB0_0000..=0xBBBF_FFFF));
1729        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1730        assert!(emu.assigned_memory_range().is_none());
1731
1732        // The guest can try to program an invalid assignment (base > limit), we
1733        // just won't decode it.
1734        emu.write_u32(0x20, 0xAA00_BB00).unwrap();
1735        assert!(emu.assigned_memory_range().is_none());
1736        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1737        assert!(emu.assigned_memory_range().is_none());
1738        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1739        assert!(emu.assigned_memory_range().is_none());
1740    }
1741
1742    #[test]
1743    fn test_type1_prefetch_assignment() {
1744        const MMIO_ENABLED: u32 = 0x0000_0002;
1745        const MMIO_DISABLED: u32 = 0x0000_0000;
1746
1747        let mut emu = create_type1_emulator(vec![]);
1748        assert!(emu.assigned_prefetch_range().is_none());
1749
1750        // The guest can program a valid prefetch range...
1751        emu.write_u32(0x24, 0xFFF0_FF00).unwrap(); // limit + base
1752        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // base upper
1753        emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); // limit upper
1754        assert!(emu.assigned_prefetch_range().is_none());
1755        // ... enable memory decoding...
1756        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1757        assert_eq!(
1758            emu.assigned_prefetch_range(),
1759            Some(0x00AA_BBCC_FF00_0000..=0x00DD_EEFF_FFFF_FFFF)
1760        );
1761        // ... then disable memory decoding it.
1762        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1763        assert!(emu.assigned_prefetch_range().is_none());
1764
1765        // The validity of the assignment is determined using the combined 64-bit
1766        // address, not the lower bits or the upper bits in isolation.
1767
1768        // Lower bits of the limit are greater than the lower bits of the
1769        // base, but the upper bits make that valid.
1770        emu.write_u32(0x24, 0xFF00_FFF0).unwrap(); // limit + base
1771        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // base upper
1772        emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); // limit upper
1773        assert!(emu.assigned_prefetch_range().is_none());
1774        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1775        assert_eq!(
1776            emu.assigned_prefetch_range(),
1777            Some(0x00AA_BBCC_FFF0_0000..=0x00DD_EEFF_FF0F_FFFF)
1778        );
1779        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1780        assert!(emu.assigned_prefetch_range().is_none());
1781
1782        // The base can equal the limit, which is a valid 1MB range.
1783        emu.write_u32(0x24, 0xDD00_DD00).unwrap(); // limit + base
1784        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // base upper
1785        emu.write_u32(0x2C, 0x00AA_BBCC).unwrap(); // limit upper
1786        assert!(emu.assigned_prefetch_range().is_none());
1787        emu.write_u32(0x4, MMIO_ENABLED).unwrap();
1788        assert_eq!(
1789            emu.assigned_prefetch_range(),
1790            Some(0x00AA_BBCC_DD00_0000..=0x00AA_BBCC_DD0F_FFFF)
1791        );
1792        emu.write_u32(0x4, MMIO_DISABLED).unwrap();
1793        assert!(emu.assigned_prefetch_range().is_none());
1794    }
1795
1796    #[test]
1797    fn test_type1_is_pcie_device() {
1798        // Test Type 1 device without PCIe capability
1799        let emu = create_type1_emulator(vec![Box::new(ReadOnlyCapability::new("foo", 0))]);
1800        assert!(!emu.is_pcie_device());
1801
1802        // Test Type 1 device with PCIe capability
1803        let emu = create_type1_emulator(vec![Box::new(PciExpressCapability::new(
1804            DevicePortType::RootPort,
1805            None,
1806        ))]);
1807        assert!(emu.is_pcie_device());
1808
1809        // Test Type 1 device with multiple capabilities including PCIe
1810        let emu = create_type1_emulator(vec![
1811            Box::new(ReadOnlyCapability::new("foo", 0)),
1812            Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1813            Box::new(ReadOnlyCapability::new("bar", 0)),
1814        ]);
1815        assert!(emu.is_pcie_device());
1816    }
1817
1818    #[test]
1819    fn test_type0_is_pcie_device() {
1820        // Test Type 0 device without PCIe capability
1821        let emu = ConfigSpaceType0Emulator::new(
1822            HardwareIds {
1823                vendor_id: 0x1111,
1824                device_id: 0x2222,
1825                revision_id: 1,
1826                prog_if: ProgrammingInterface::NONE,
1827                sub_class: Subclass::NONE,
1828                base_class: ClassCode::UNCLASSIFIED,
1829                type0_sub_vendor_id: 0,
1830                type0_sub_system_id: 0,
1831            },
1832            vec![Box::new(ReadOnlyCapability::new("foo", 0))],
1833            DeviceBars::new(),
1834        );
1835        assert!(!emu.is_pcie_device());
1836
1837        // Test Type 0 device with PCIe capability
1838        let emu = ConfigSpaceType0Emulator::new(
1839            HardwareIds {
1840                vendor_id: 0x1111,
1841                device_id: 0x2222,
1842                revision_id: 1,
1843                prog_if: ProgrammingInterface::NONE,
1844                sub_class: Subclass::NONE,
1845                base_class: ClassCode::UNCLASSIFIED,
1846                type0_sub_vendor_id: 0,
1847                type0_sub_system_id: 0,
1848            },
1849            vec![Box::new(PciExpressCapability::new(
1850                DevicePortType::Endpoint,
1851                None,
1852            ))],
1853            DeviceBars::new(),
1854        );
1855        assert!(emu.is_pcie_device());
1856
1857        // Test Type 0 device with multiple capabilities including PCIe
1858        let emu = ConfigSpaceType0Emulator::new(
1859            HardwareIds {
1860                vendor_id: 0x1111,
1861                device_id: 0x2222,
1862                revision_id: 1,
1863                prog_if: ProgrammingInterface::NONE,
1864                sub_class: Subclass::NONE,
1865                base_class: ClassCode::UNCLASSIFIED,
1866                type0_sub_vendor_id: 0,
1867                type0_sub_system_id: 0,
1868            },
1869            vec![
1870                Box::new(ReadOnlyCapability::new("foo", 0)),
1871                Box::new(PciExpressCapability::new(DevicePortType::Endpoint, None)),
1872                Box::new(ReadOnlyCapability::new("bar", 0)),
1873            ],
1874            DeviceBars::new(),
1875        );
1876        assert!(emu.is_pcie_device());
1877
1878        // Test Type 0 device with no capabilities
1879        let emu = ConfigSpaceType0Emulator::new(
1880            HardwareIds {
1881                vendor_id: 0x1111,
1882                device_id: 0x2222,
1883                revision_id: 1,
1884                prog_if: ProgrammingInterface::NONE,
1885                sub_class: Subclass::NONE,
1886                base_class: ClassCode::UNCLASSIFIED,
1887                type0_sub_vendor_id: 0,
1888                type0_sub_system_id: 0,
1889            },
1890            vec![],
1891            DeviceBars::new(),
1892        );
1893        assert!(!emu.is_pcie_device());
1894    }
1895
1896    #[test]
1897    fn test_capability_ids() {
1898        // Test that capabilities return the correct capability IDs
1899        let pcie_cap = PciExpressCapability::new(DevicePortType::Endpoint, None);
1900        assert_eq!(pcie_cap.capability_id(), CapabilityId::PCI_EXPRESS);
1901
1902        let read_only_cap = ReadOnlyCapability::new("test", 0u32);
1903        assert_eq!(read_only_cap.capability_id(), CapabilityId::VENDOR_SPECIFIC);
1904    }
1905
1906    #[test]
1907    fn test_common_header_emulator_type0() {
1908        // Test the common header emulator with Type 0 configuration (6 BARs)
1909        let hardware_ids = HardwareIds {
1910            vendor_id: 0x1111,
1911            device_id: 0x2222,
1912            revision_id: 1,
1913            prog_if: ProgrammingInterface::NONE,
1914            sub_class: Subclass::NONE,
1915            base_class: ClassCode::UNCLASSIFIED,
1916            type0_sub_vendor_id: 0,
1917            type0_sub_system_id: 0,
1918        };
1919
1920        let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1921
1922        let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1923            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1924
1925        assert_eq!(common_emu.hardware_ids().vendor_id, 0x1111);
1926        assert_eq!(common_emu.hardware_ids().device_id, 0x2222);
1927        assert!(!common_emu.multi_function_bit());
1928        assert!(!common_emu.is_pcie_device());
1929        assert_ne!(common_emu.bar_masks()[0], 0); // Should have a mask for BAR0
1930    }
1931
1932    #[test]
1933    fn test_common_header_emulator_type1() {
1934        // Test the common header emulator with Type 1 configuration (2 BARs)
1935        let hardware_ids = HardwareIds {
1936            vendor_id: 0x3333,
1937            device_id: 0x4444,
1938            revision_id: 1,
1939            prog_if: ProgrammingInterface::NONE,
1940            sub_class: Subclass::BRIDGE_PCI_TO_PCI,
1941            base_class: ClassCode::BRIDGE,
1942            type0_sub_vendor_id: 0,
1943            type0_sub_system_id: 0,
1944        };
1945
1946        let bars = DeviceBars::new().bar0(4096, BarMemoryKind::Dummy);
1947
1948        let mut common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
1949            ConfigSpaceCommonHeaderEmulator::new(
1950                hardware_ids,
1951                vec![Box::new(PciExpressCapability::new(
1952                    DevicePortType::RootPort,
1953                    None,
1954                ))],
1955                bars,
1956            )
1957            .with_multi_function_bit(true);
1958
1959        assert_eq!(common_emu.hardware_ids().vendor_id, 0x3333);
1960        assert_eq!(common_emu.hardware_ids().device_id, 0x4444);
1961        assert!(common_emu.multi_function_bit());
1962        assert!(common_emu.is_pcie_device());
1963        assert_ne!(common_emu.bar_masks()[0], 0); // Should have a mask for BAR0
1964        assert_eq!(common_emu.bar_masks().len(), 2);
1965
1966        // Test reset functionality
1967        common_emu.reset();
1968        assert_eq!(common_emu.capabilities().len(), 1); // capabilities should still be there
1969    }
1970
1971    #[test]
1972    fn test_common_header_emulator_no_bars() {
1973        // Test the common header emulator with no BARs configured
1974        let hardware_ids = HardwareIds {
1975            vendor_id: 0x5555,
1976            device_id: 0x6666,
1977            revision_id: 1,
1978            prog_if: ProgrammingInterface::NONE,
1979            sub_class: Subclass::NONE,
1980            base_class: ClassCode::UNCLASSIFIED,
1981            type0_sub_vendor_id: 0,
1982            type0_sub_system_id: 0,
1983        };
1984
1985        // Create bars with no BARs configured
1986        let bars = DeviceBars::new();
1987
1988        let common_emu: ConfigSpaceCommonHeaderEmulatorType0 =
1989            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
1990
1991        assert_eq!(common_emu.hardware_ids().vendor_id, 0x5555);
1992        assert_eq!(common_emu.hardware_ids().device_id, 0x6666);
1993
1994        // All BAR masks should be 0 when no BARs are configured
1995        for &mask in common_emu.bar_masks() {
1996            assert_eq!(mask, 0);
1997        }
1998    }
1999
2000    #[test]
2001    fn test_common_header_emulator_type1_ignores_extra_bars() {
2002        // Test that Type 1 emulator ignores BARs beyond index 1 (only supports 2 BARs)
2003        let hardware_ids = HardwareIds {
2004            vendor_id: 0x7777,
2005            device_id: 0x8888,
2006            revision_id: 1,
2007            prog_if: ProgrammingInterface::NONE,
2008            sub_class: Subclass::BRIDGE_PCI_TO_PCI,
2009            base_class: ClassCode::BRIDGE,
2010            type0_sub_vendor_id: 0,
2011            type0_sub_system_id: 0,
2012        };
2013
2014        // Configure BARs 0, 2, and 4 - Type 1 should only use BAR0 (and BAR1 as upper 32 bits)
2015        let bars = DeviceBars::new()
2016            .bar0(4096, BarMemoryKind::Dummy)
2017            .bar2(8192, BarMemoryKind::Dummy)
2018            .bar4(16384, BarMemoryKind::Dummy);
2019
2020        let common_emu: ConfigSpaceCommonHeaderEmulatorType1 =
2021            ConfigSpaceCommonHeaderEmulator::new(hardware_ids, vec![], bars);
2022
2023        assert_eq!(common_emu.hardware_ids().vendor_id, 0x7777);
2024        assert_eq!(common_emu.hardware_ids().device_id, 0x8888);
2025
2026        // Should have a mask for BAR0, and BAR1 should be the upper 32 bits (64-bit BAR)
2027        assert_ne!(common_emu.bar_masks()[0], 0); // BAR0 should be configured
2028        assert_ne!(common_emu.bar_masks()[1], 0); // BAR1 should be upper 32 bits of BAR0
2029        assert_eq!(common_emu.bar_masks().len(), 2); // Type 1 only has 2 BARs
2030
2031        // BAR2 and higher should be ignored (not accessible in Type 1 with N=2)
2032        // This demonstrates that extra BARs in DeviceBars are properly ignored
2033    }
2034
2035    #[test]
2036    fn test_common_header_extended_capabilities() {
2037        // Test common header emulator extended capabilities
2038        let mut common_emu_no_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2039            HardwareIds {
2040                vendor_id: 0x1111,
2041                device_id: 0x2222,
2042                revision_id: 1,
2043                prog_if: ProgrammingInterface::NONE,
2044                sub_class: Subclass::NONE,
2045                base_class: ClassCode::UNCLASSIFIED,
2046                type0_sub_vendor_id: 0,
2047                type0_sub_system_id: 0,
2048            },
2049            vec![Box::new(ReadOnlyCapability::new("foo", 0))],
2050            DeviceBars::new(),
2051        );
2052        assert!(!common_emu_no_pcie.is_pcie_device());
2053
2054        let mut common_emu_pcie = ConfigSpaceCommonHeaderEmulatorType0::new(
2055            HardwareIds {
2056                vendor_id: 0x1111,
2057                device_id: 0x2222,
2058                revision_id: 1,
2059                prog_if: ProgrammingInterface::NONE,
2060                sub_class: Subclass::NONE,
2061                base_class: ClassCode::UNCLASSIFIED,
2062                type0_sub_vendor_id: 0,
2063                type0_sub_system_id: 0,
2064            },
2065            vec![Box::new(PciExpressCapability::new(
2066                DevicePortType::Endpoint,
2067                None,
2068            ))],
2069            DeviceBars::new(),
2070        );
2071        assert!(common_emu_pcie.is_pcie_device());
2072
2073        // Test reading extended capabilities - non-PCIe device should return error
2074        let mut value = 0;
2075        assert!(matches!(
2076            common_emu_no_pcie.read_extended_capabilities(0x100, &mut value),
2077            CommonHeaderResult::Failed(IoError::InvalidRegister)
2078        ));
2079
2080        // Test reading extended capabilities - PCIe device should return 0xffffffff
2081        let mut value = 0;
2082        assert!(matches!(
2083            common_emu_pcie.read_extended_capabilities(0x100, &mut value),
2084            CommonHeaderResult::Handled
2085        ));
2086        assert_eq!(value, 0xffffffff);
2087
2088        // Test writing extended capabilities - non-PCIe device should return error
2089        assert!(matches!(
2090            common_emu_no_pcie.write_extended_capabilities(0x100, 0x1234),
2091            CommonHeaderResult::Failed(IoError::InvalidRegister)
2092        ));
2093
2094        // Test writing extended capabilities - PCIe device should accept writes
2095        assert!(matches!(
2096            common_emu_pcie.write_extended_capabilities(0x100, 0x1234),
2097            CommonHeaderResult::Handled
2098        ));
2099
2100        // Test invalid offset ranges
2101        let mut value = 0;
2102        assert!(matches!(
2103            common_emu_pcie.read_extended_capabilities(0x99, &mut value),
2104            CommonHeaderResult::Failed(IoError::InvalidRegister)
2105        ));
2106        assert!(matches!(
2107            common_emu_pcie.read_extended_capabilities(0x1000, &mut value),
2108            CommonHeaderResult::Failed(IoError::InvalidRegister)
2109        ));
2110    }
2111
2112    #[test]
2113    fn test_type0_emulator_save_restore() {
2114        use vmcore::save_restore::SaveRestore;
2115
2116        // Test Type 0 emulator save/restore
2117        let mut emu = create_type0_emulator(vec![]);
2118
2119        // Modify some state by writing to command register
2120        emu.write_u32(0x04, 0x0007).unwrap(); // Enable some command bits
2121
2122        // Read back and verify
2123        let mut test_val = 0u32;
2124        emu.read_u32(0x04, &mut test_val).unwrap();
2125        assert_eq!(test_val & 0x0007, 0x0007);
2126
2127        // Write to latency timer / interrupt register
2128        emu.write_u32(0x3C, 0x0040_0000).unwrap(); // Set latency_timer
2129
2130        // Save the state
2131        let saved_state = emu.save().expect("save should succeed");
2132
2133        // Reset the emulator
2134        emu.reset();
2135
2136        // Verify state is reset
2137        emu.read_u32(0x04, &mut test_val).unwrap();
2138        assert_eq!(test_val & 0x0007, 0x0000); // Should be reset
2139
2140        // Restore the state
2141        emu.restore(saved_state).expect("restore should succeed");
2142
2143        // Verify state is restored
2144        emu.read_u32(0x04, &mut test_val).unwrap();
2145        assert_eq!(test_val & 0x0007, 0x0007); // Should be restored
2146    }
2147
2148    #[test]
2149    fn test_type1_emulator_save_restore() {
2150        use vmcore::save_restore::SaveRestore;
2151
2152        // Test Type 1 emulator save/restore
2153        let mut emu = create_type1_emulator(vec![]);
2154
2155        // Modify some state
2156        emu.write_u32(0x04, 0x0003).unwrap(); // Enable command bits
2157        emu.write_u32(0x18, 0x0012_1000).unwrap(); // Set bus numbers
2158        emu.write_u32(0x20, 0xFFF0_FF00).unwrap(); // Set memory range
2159        emu.write_u32(0x24, 0xFFF0_FF00).unwrap(); // Set prefetch range
2160        emu.write_u32(0x28, 0x00AA_BBCC).unwrap(); // Set prefetch base upper
2161        emu.write_u32(0x2C, 0x00DD_EEFF).unwrap(); // Set prefetch limit upper
2162        emu.write_u32(0x3C, 0x0001_0000).unwrap(); // Set bridge control
2163
2164        // Verify values
2165        let mut test_val = 0u32;
2166        emu.read_u32(0x04, &mut test_val).unwrap();
2167        assert_eq!(test_val & 0x0003, 0x0003);
2168        emu.read_u32(0x18, &mut test_val).unwrap();
2169        assert_eq!(test_val, 0x0012_1000);
2170        emu.read_u32(0x20, &mut test_val).unwrap();
2171        assert_eq!(test_val, 0xFFF0_FF00);
2172        emu.read_u32(0x28, &mut test_val).unwrap();
2173        assert_eq!(test_val, 0x00AA_BBCC);
2174        emu.read_u32(0x2C, &mut test_val).unwrap();
2175        assert_eq!(test_val, 0x00DD_EEFF);
2176        emu.read_u32(0x3C, &mut test_val).unwrap();
2177        assert_eq!(test_val >> 16, 0x0001); // bridge_control
2178
2179        // Save the state
2180        let saved_state = emu.save().expect("save should succeed");
2181
2182        // Reset the emulator
2183        emu.reset();
2184
2185        // Verify state is reset
2186        emu.read_u32(0x04, &mut test_val).unwrap();
2187        assert_eq!(test_val & 0x0003, 0x0000);
2188        emu.read_u32(0x18, &mut test_val).unwrap();
2189        assert_eq!(test_val, 0x0000_0000);
2190
2191        // Restore the state
2192        emu.restore(saved_state).expect("restore should succeed");
2193
2194        // Verify state is restored
2195        emu.read_u32(0x04, &mut test_val).unwrap();
2196        assert_eq!(test_val & 0x0003, 0x0003);
2197        emu.read_u32(0x18, &mut test_val).unwrap();
2198        assert_eq!(test_val, 0x0012_1000);
2199        emu.read_u32(0x20, &mut test_val).unwrap();
2200        assert_eq!(test_val, 0xFFF0_FF00);
2201        emu.read_u32(0x28, &mut test_val).unwrap();
2202        assert_eq!(test_val, 0x00AA_BBCC);
2203        emu.read_u32(0x2C, &mut test_val).unwrap();
2204        assert_eq!(test_val, 0x00DD_EEFF);
2205        emu.read_u32(0x3C, &mut test_val).unwrap();
2206        assert_eq!(test_val >> 16, 0x0001); // bridge_control
2207    }
2208
2209    #[test]
2210    fn test_config_space_type1_set_presence_detect_state() {
2211        // Test that ConfigSpaceType1Emulator can set presence detect state
2212        // when it has a PCIe Express capability with hotplug support
2213
2214        // Create a PCIe Express capability with hotplug support
2215        let pcie_cap =
2216            PciExpressCapability::new(DevicePortType::RootPort, None).with_hotplug_support(1);
2217
2218        let mut emulator = create_type1_emulator(vec![Box::new(pcie_cap)]);
2219
2220        // Initially, presence detect state should be 0
2221        let mut slot_status_val = 0u32;
2222        let result = emulator.read_u32(0x58, &mut slot_status_val); // 0x40 (cap start) + 0x18 (slot control/status)
2223        assert!(matches!(result, IoResult::Ok));
2224        let initial_presence_detect = (slot_status_val >> 22) & 0x1; // presence_detect_state is bit 6 of slot status
2225        assert_eq!(
2226            initial_presence_detect, 0,
2227            "Initial presence detect state should be 0"
2228        );
2229
2230        // Set device as present
2231        emulator.set_presence_detect_state(true);
2232        let result = emulator.read_u32(0x58, &mut slot_status_val);
2233        assert!(matches!(result, IoResult::Ok));
2234        let present_presence_detect = (slot_status_val >> 22) & 0x1;
2235        assert_eq!(
2236            present_presence_detect, 1,
2237            "Presence detect state should be 1 when device is present"
2238        );
2239
2240        // Set device as not present
2241        emulator.set_presence_detect_state(false);
2242        let result = emulator.read_u32(0x58, &mut slot_status_val);
2243        assert!(matches!(result, IoResult::Ok));
2244        let absent_presence_detect = (slot_status_val >> 22) & 0x1;
2245        assert_eq!(
2246            absent_presence_detect, 0,
2247            "Presence detect state should be 0 when device is not present"
2248        );
2249    }
2250
2251    #[test]
2252    fn test_config_space_type1_set_presence_detect_state_without_pcie() {
2253        // Test that ConfigSpaceType1Emulator silently ignores set_presence_detect_state
2254        // when there is no PCIe Express capability
2255
2256        let mut emulator = create_type1_emulator(vec![]); // No capabilities
2257
2258        // Should not panic and should be silently ignored
2259        emulator.set_presence_detect_state(true);
2260        emulator.set_presence_detect_state(false);
2261    }
2262
2263    #[test]
2264    fn test_interrupt_pin_register() {
2265        use vmcore::line_interrupt::LineInterrupt;
2266
2267        // Test Type 0 device with interrupt pin configured
2268        let mut emu = ConfigSpaceType0Emulator::new(
2269            HardwareIds {
2270                vendor_id: 0x1111,
2271                device_id: 0x2222,
2272                revision_id: 1,
2273                prog_if: ProgrammingInterface::NONE,
2274                sub_class: Subclass::NONE,
2275                base_class: ClassCode::UNCLASSIFIED,
2276                type0_sub_vendor_id: 0,
2277                type0_sub_system_id: 0,
2278            },
2279            vec![],
2280            DeviceBars::new(),
2281        );
2282
2283        // Initially, no interrupt pin should be configured
2284        let mut val = 0u32;
2285        emu.read_u32(0x3C, &mut val).unwrap(); // LATENCY_INTERRUPT register
2286        assert_eq!(val & 0xFF00, 0); // Interrupt pin should be 0
2287
2288        // Configure interrupt pin A
2289        let line_interrupt = LineInterrupt::detached();
2290        emu.set_interrupt_pin(PciInterruptPin::IntA, line_interrupt);
2291
2292        // Read the register again
2293        emu.read_u32(0x3C, &mut val).unwrap();
2294        assert_eq!((val >> 8) & 0xFF, 1); // Interrupt pin should be 1 (INTA)
2295
2296        // Set interrupt line to 0x42 and verify both pin and line are correct
2297        emu.write_u32(0x3C, 0x00110042).unwrap(); // Latency=0x11, pin=ignored, line=0x42
2298        emu.read_u32(0x3C, &mut val).unwrap();
2299        assert_eq!(val & 0xFF, 0x42); // Interrupt line should be 0x42
2300        assert_eq!((val >> 8) & 0xFF, 1); // Interrupt pin should still be 1 (writes ignored)
2301        assert_eq!((val >> 16) & 0xFF, 0x11); // Latency timer should be 0x11
2302
2303        // Test with interrupt pin D
2304        let mut emu_d = ConfigSpaceType0Emulator::new(
2305            HardwareIds {
2306                vendor_id: 0x1111,
2307                device_id: 0x2222,
2308                revision_id: 1,
2309                prog_if: ProgrammingInterface::NONE,
2310                sub_class: Subclass::NONE,
2311                base_class: ClassCode::UNCLASSIFIED,
2312                type0_sub_vendor_id: 0,
2313                type0_sub_system_id: 0,
2314            },
2315            vec![],
2316            DeviceBars::new(),
2317        );
2318
2319        let line_interrupt_d = LineInterrupt::detached();
2320        emu_d.set_interrupt_pin(PciInterruptPin::IntD, line_interrupt_d);
2321
2322        emu_d.read_u32(0x3C, &mut val).unwrap();
2323        assert_eq!((val >> 8) & 0xFF, 4); // Interrupt pin should be 4 (INTD)
2324    }
2325
2326    #[test]
2327    fn test_header_type_functionality() {
2328        // Test HeaderType enum values
2329        assert_eq!(HeaderType::Type0.bar_count(), 6);
2330        assert_eq!(HeaderType::Type1.bar_count(), 2);
2331        assert_eq!(usize::from(HeaderType::Type0), 6);
2332        assert_eq!(usize::from(HeaderType::Type1), 2);
2333
2334        // Test constant values
2335        assert_eq!(header_type_consts::TYPE0_BAR_COUNT, 6);
2336        assert_eq!(header_type_consts::TYPE1_BAR_COUNT, 2);
2337
2338        // Test Type 0 emulator
2339        let emu_type0 = create_type0_emulator(vec![]);
2340        assert_eq!(emu_type0.common.bar_count(), 6);
2341        assert_eq!(emu_type0.common.header_type(), HeaderType::Type0);
2342        assert!(emu_type0.common.validate_header_type(HeaderType::Type0));
2343        assert!(!emu_type0.common.validate_header_type(HeaderType::Type1));
2344
2345        // Test Type 1 emulator
2346        let emu_type1 = create_type1_emulator(vec![]);
2347        assert_eq!(emu_type1.common.bar_count(), 2);
2348        assert_eq!(emu_type1.common.header_type(), HeaderType::Type1);
2349        assert!(emu_type1.common.validate_header_type(HeaderType::Type1));
2350        assert!(!emu_type1.common.validate_header_type(HeaderType::Type0));
2351    }
2352
2353    /// Ensure that `find_bar` correctly returns a full `u64` offset for BARs
2354    /// larger than 64KiB, guarding against truncation back to `u16`.
2355    #[test]
2356    fn find_bar_returns_full_u64_offset_for_large_bar() {
2357        use crate::bar_mapping::BarMappings;
2358
2359        // Set up a 64-bit BAR0 at base address 0x1_0000_0000 with size
2360        // 0x2_0000 (128KiB). The mask encodes the size via the complement:
2361        //   mask = !(size - 1) = !(0x1_FFFF) = 0xFFFF_FFFE_0000
2362        // Split across two 32-bit BAR registers (BAR0 low + BAR1 high).
2363        let bar_base: u64 = 0x1_0000_0000;
2364        let bar_size: u64 = 0x2_0000; // 128KiB — larger than u16::MAX
2365        let mask64 = !(bar_size - 1); // 0xFFFF_FFFE_0000
2366
2367        let mut base_addresses = [0u32; 6];
2368        let mut bar_masks = [0u32; 6];
2369
2370        // BAR0 low: set the 64-bit type bit in the mask and the base address.
2371        bar_masks[0] = cfg_space::BarEncodingBits::from_bits(mask64 as u32)
2372            .with_type_64_bit(true)
2373            .into_bits();
2374        bar_masks[1] = (mask64 >> 32) as u32;
2375        base_addresses[0] = bar_base as u32;
2376        base_addresses[1] = (bar_base >> 32) as u32;
2377
2378        let bar_mappings = BarMappings::parse(&base_addresses, &bar_masks);
2379
2380        // Query an address whose offset within BAR0 exceeds 0xFFFF.
2381        let expected_offset: u64 = 0x1_2345;
2382        let address: u64 = bar_base + expected_offset;
2383
2384        let (found_bar, offset) = bar_mappings
2385            .find(address)
2386            .expect("address should resolve to BAR 0");
2387        assert_eq!(found_bar, 0);
2388        assert_eq!(offset, expected_offset);
2389    }
2390}