virtio_drivers/transport/pci/
bus.rs

1//! Module for dealing with a PCI bus in general, without anything specific to VirtIO.
2
3use bitflags::bitflags;
4use core::{
5    array,
6    convert::TryFrom,
7    fmt::{self, Display, Formatter},
8    ops::Deref,
9    ptr::NonNull,
10};
11use log::warn;
12use safe_mmio::{fields::ReadPureWrite, UniqueMmioPointer};
13use thiserror::Error;
14
15const INVALID_READ: u32 = 0xffffffff;
16
17/// The maximum number of devices on a bus.
18const MAX_DEVICES: u8 = 32;
19/// The maximum number of functions on a device.
20const MAX_FUNCTIONS: u8 = 8;
21
22/// The offset in bytes to the status and command fields within PCI configuration space.
23const STATUS_COMMAND_OFFSET: u8 = 0x04;
24/// The offset in bytes to BAR0 within PCI configuration space.
25const BAR0_OFFSET: u8 = 0x10;
26
27/// ID for vendor-specific PCI capabilities.
28pub const PCI_CAP_ID_VNDR: u8 = 0x09;
29
30bitflags! {
31    /// The status register in PCI configuration space.
32    #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
33    pub struct Status: u16 {
34        // Bits 0-2 are reserved.
35        /// The state of the device's INTx# signal.
36        const INTERRUPT_STATUS = 1 << 3;
37        /// The device has a linked list of capabilities.
38        const CAPABILITIES_LIST = 1 << 4;
39        /// The device is capabile of running at 66 MHz rather than 33 MHz.
40        const MHZ_66_CAPABLE = 1 << 5;
41        // Bit 6 is reserved.
42        /// The device can accept fast back-to-back transactions not from the same agent.
43        const FAST_BACK_TO_BACK_CAPABLE = 1 << 7;
44        /// The bus agent observed a parity error (if parity error handling is enabled).
45        const MASTER_DATA_PARITY_ERROR = 1 << 8;
46        // Bits 9-10 are DEVSEL timing.
47        /// A target device terminated a transaction with target-abort.
48        const SIGNALED_TARGET_ABORT = 1 << 11;
49        /// A master device transaction was terminated with target-abort.
50        const RECEIVED_TARGET_ABORT = 1 << 12;
51        /// A master device transaction was terminated with master-abort.
52        const RECEIVED_MASTER_ABORT = 1 << 13;
53        /// A device asserts SERR#.
54        const SIGNALED_SYSTEM_ERROR = 1 << 14;
55        /// The device detects a parity error, even if parity error handling is disabled.
56        const DETECTED_PARITY_ERROR = 1 << 15;
57    }
58}
59
60bitflags! {
61    /// The command register in PCI configuration space.
62    #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
63    pub struct Command: u16 {
64        /// The device can respond to I/O Space accesses.
65        const IO_SPACE = 1 << 0;
66        /// The device can respond to Memory Space accesses.
67        const MEMORY_SPACE = 1 << 1;
68        /// The device can behave as a bus master.
69        const BUS_MASTER = 1 << 2;
70        /// The device can monitor Special Cycle operations.
71        const SPECIAL_CYCLES = 1 << 3;
72        /// The device can generate the Memory Write and Invalidate command.
73        const MEMORY_WRITE_AND_INVALIDATE_ENABLE = 1 << 4;
74        /// The device will snoop palette register data.
75        const VGA_PALETTE_SNOOP = 1 << 5;
76        /// The device should take its normal action when a parity error is detected.
77        const PARITY_ERROR_RESPONSE = 1 << 6;
78        // Bit 7 is reserved.
79        /// The SERR# driver is enabled.
80        const SERR_ENABLE = 1 << 8;
81        /// The device is allowed to generate fast back-to-back transactions.
82        const FAST_BACK_TO_BACK_ENABLE = 1 << 9;
83        /// Assertion of the device's INTx# signal is disabled.
84        const INTERRUPT_DISABLE = 1 << 10;
85    }
86}
87
88/// Errors accessing a PCI device.
89#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
90pub enum PciError {
91    /// The device reported an invalid BAR type.
92    #[error("Invalid PCI BAR type")]
93    InvalidBarType,
94}
95
96/// The root complex of a PCI bus.
97#[derive(Debug)]
98pub struct PciRoot<C: ConfigurationAccess> {
99    pub(crate) configuration_access: C,
100}
101
102/// A PCI Configuration Access Mechanism.
103#[derive(Copy, Clone, Debug, Eq, PartialEq)]
104pub enum Cam {
105    /// The PCI memory-mapped Configuration Access Mechanism.
106    ///
107    /// This provides access to 256 bytes of configuration space per device function.
108    MmioCam,
109    /// The PCIe memory-mapped Enhanced Configuration Access Mechanism.
110    ///
111    /// This provides access to 4 KiB of configuration space per device function.
112    Ecam,
113}
114
115impl Cam {
116    /// Returns the total size in bytes of the memory-mapped region.
117    pub const fn size(self) -> u32 {
118        match self {
119            Self::MmioCam => 0x1000000,
120            Self::Ecam => 0x10000000,
121        }
122    }
123
124    /// Returns the offset in bytes within the CAM region for the given device, function and
125    /// register.
126    pub fn cam_offset(self, device_function: DeviceFunction, register_offset: u8) -> u32 {
127        assert!(device_function.valid());
128
129        let bdf = ((device_function.bus as u32) << 8)
130            | ((device_function.device as u32) << 3)
131            | (device_function.function as u32);
132        let address =
133            (bdf << match self {
134                Cam::MmioCam => 8,
135                Cam::Ecam => 12,
136            }) | (register_offset as u32);
137        // Ensure that address is within range.
138        assert!(address < self.size());
139        // Ensure that address is word-aligned.
140        assert!(address & 0x3 == 0);
141        address
142    }
143}
144
145impl<C: ConfigurationAccess> PciRoot<C> {
146    /// Creates a new `PciRoot` to access a PCI root complex through the given configuration access
147    /// implementation.
148    pub fn new(configuration_access: C) -> Self {
149        Self {
150            configuration_access,
151        }
152    }
153
154    /// Enumerates PCI devices on the given bus.
155    pub fn enumerate_bus(&self, bus: u8) -> BusDeviceIterator<C> {
156        // SAFETY: The `BusDeviceIterator` only reads read-only fields.
157        let configuration_access = unsafe { self.configuration_access.unsafe_clone() };
158        BusDeviceIterator {
159            configuration_access,
160            next: DeviceFunction {
161                bus,
162                device: 0,
163                function: 0,
164            },
165        }
166    }
167
168    /// Reads the status and command registers of the given device function.
169    pub fn get_status_command(&self, device_function: DeviceFunction) -> (Status, Command) {
170        let status_command = self
171            .configuration_access
172            .read_word(device_function, STATUS_COMMAND_OFFSET);
173        let status = Status::from_bits_truncate((status_command >> 16) as u16);
174        let command = Command::from_bits_truncate(status_command as u16);
175        (status, command)
176    }
177
178    /// Sets the command register of the given device function.
179    pub fn set_command(&mut self, device_function: DeviceFunction, command: Command) {
180        self.configuration_access.write_word(
181            device_function,
182            STATUS_COMMAND_OFFSET,
183            command.bits().into(),
184        );
185    }
186
187    /// Gets an iterator over the capabilities of the given device function.
188    pub fn capabilities(&self, device_function: DeviceFunction) -> CapabilityIterator<'_, C> {
189        CapabilityIterator {
190            configuration_access: &self.configuration_access,
191            device_function,
192            next_capability_offset: self.capabilities_offset(device_function),
193        }
194    }
195
196    /// Returns information about all the given device function's BARs.
197    pub fn bars(
198        &mut self,
199        device_function: DeviceFunction,
200    ) -> Result<[Option<BarInfo>; 6], PciError> {
201        let mut bars = array::from_fn(|_| None);
202        let mut bar_index = 0;
203        while bar_index < 6 {
204            let info = self.bar_info(device_function, bar_index)?;
205            let bar_entries = if info.as_ref().is_some_and(BarInfo::takes_two_entries) {
206                2
207            } else {
208                1
209            };
210            bars[usize::from(bar_index)] = info;
211            bar_index += bar_entries;
212        }
213        Ok(bars)
214    }
215
216    /// Gets information about the given BAR of the given device function.
217    pub fn bar_info(
218        &mut self,
219        device_function: DeviceFunction,
220        bar_index: u8,
221    ) -> Result<Option<BarInfo>, PciError> {
222        // Disable address decoding while sizing the BAR.
223        let (_status, command_orig) = self.get_status_command(device_function);
224        let command_disable_decode = command_orig & !(Command::IO_SPACE | Command::MEMORY_SPACE);
225        if command_disable_decode != command_orig {
226            self.set_command(device_function, command_disable_decode);
227        }
228
229        let bar_orig = self
230            .configuration_access
231            .read_word(device_function, BAR0_OFFSET + 4 * bar_index);
232        let io_space = bar_orig & 0x00000001 == 0x00000001;
233
234        // Get the size of the BAR.
235        self.configuration_access.write_word(
236            device_function,
237            BAR0_OFFSET + 4 * bar_index,
238            0xffffffff,
239        );
240        let mut size_mask = u64::from(
241            self.configuration_access
242                .read_word(device_function, BAR0_OFFSET + 4 * bar_index),
243        );
244
245        // Read the upper 32 bits of 64-bit memory BARs.
246        let (address_top, size_top) = if bar_orig & 0b111 == 0b100 {
247            if bar_index >= 5 {
248                return Err(PciError::InvalidBarType);
249            }
250            let bar_top_orig = self
251                .configuration_access
252                .read_word(device_function, BAR0_OFFSET + 4 * (bar_index + 1));
253            self.configuration_access.write_word(
254                device_function,
255                BAR0_OFFSET + 4 * (bar_index + 1),
256                0xffffffff,
257            );
258            let size_top = self
259                .configuration_access
260                .read_word(device_function, BAR0_OFFSET + 4 * (bar_index + 1));
261            self.configuration_access.write_word(
262                device_function,
263                BAR0_OFFSET + 4 * (bar_index + 1),
264                bar_top_orig,
265            );
266            (bar_top_orig, size_top)
267        } else {
268            let size_top = if size_mask == 0 { 0 } else { 0xffffffff };
269            (0, size_top)
270        };
271        size_mask |= u64::from(size_top) << 32;
272
273        // For IO BARs bits 2 and 3 can be part of the address.
274        let flag_bits = if io_space { 0b11 } else { 0b1111 };
275        // A wrapping add is necessary to correctly handle the case of unused BARs, which read back
276        // as 0, and should be treated as size 0.
277        let size = (!(size_mask & !flag_bits)).wrapping_add(1);
278
279        // Restore the original value.
280        self.configuration_access.write_word(
281            device_function,
282            BAR0_OFFSET + 4 * bar_index,
283            bar_orig,
284        );
285
286        if command_disable_decode != command_orig {
287            self.set_command(device_function, command_orig);
288        }
289
290        if size_mask == 0 {
291            Ok(None)
292        } else if io_space {
293            // I/O space
294            let address = bar_orig & 0xfffffffc;
295            Ok(Some(BarInfo::IO {
296                address,
297                size: size as u32,
298            }))
299        } else {
300            // Memory space
301            let address = u64::from(bar_orig & 0xfffffff0) | (u64::from(address_top) << 32);
302            let prefetchable = bar_orig & 0x00000008 != 0;
303            let address_type = MemoryBarType::try_from(((bar_orig & 0x00000006) >> 1) as u8)?;
304            Ok(Some(BarInfo::Memory {
305                address_type,
306                prefetchable,
307                address,
308                size,
309            }))
310        }
311    }
312
313    /// Sets the address of the given 32-bit memory or I/O BAR of the given device function.
314    pub fn set_bar_32(&mut self, device_function: DeviceFunction, bar_index: u8, address: u32) {
315        self.configuration_access
316            .write_word(device_function, BAR0_OFFSET + 4 * bar_index, address);
317    }
318
319    /// Sets the address of the given 64-bit memory BAR of the given device function.
320    pub fn set_bar_64(&mut self, device_function: DeviceFunction, bar_index: u8, address: u64) {
321        self.configuration_access.write_word(
322            device_function,
323            BAR0_OFFSET + 4 * bar_index,
324            address as u32,
325        );
326        self.configuration_access.write_word(
327            device_function,
328            BAR0_OFFSET + 4 * (bar_index + 1),
329            (address >> 32) as u32,
330        );
331    }
332
333    /// Gets the capabilities 'pointer' for the device function, if any.
334    fn capabilities_offset(&self, device_function: DeviceFunction) -> Option<u8> {
335        let (status, _) = self.get_status_command(device_function);
336        if status.contains(Status::CAPABILITIES_LIST) {
337            Some((self.configuration_access.read_word(device_function, 0x34) & 0xFC) as u8)
338        } else {
339            None
340        }
341    }
342}
343
344/// A method to access PCI configuration space for a particular PCI bus.
345pub trait ConfigurationAccess {
346    /// Reads 4 bytes from the configuration space.
347    fn read_word(&self, device_function: DeviceFunction, register_offset: u8) -> u32;
348
349    /// Writes 4 bytes to the configuration space.
350    fn write_word(&mut self, device_function: DeviceFunction, register_offset: u8, data: u32);
351
352    /// Makes a clone of the `ConfigurationAccess`, accessing the same PCI bus.
353    ///
354    /// # Safety
355    ///
356    /// This function allows concurrent mutable access to the PCI CAM. To avoid this causing
357    /// problems, the returned `ConfigurationAccess` instance must only be used to read read-only
358    /// fields.
359    unsafe fn unsafe_clone(&self) -> Self;
360}
361
362/// `ConfigurationAccess` implementation for memory-mapped access to a PCI root complex, via either
363/// a 16 MiB region for the PCI Configuration Access Mechanism or a 256 MiB region for the PCIe
364/// Enhanced Configuration Access Mechanism.
365pub struct MmioCam<'a> {
366    mmio: UniqueMmioPointer<'a, [ReadPureWrite<u32>]>,
367    cam: Cam,
368}
369
370impl MmioCam<'_> {
371    /// Wraps the PCI root complex with the given MMIO base address.
372    ///
373    /// Panics if the base address is not aligned to a 4-byte boundary.
374    ///
375    /// # Safety
376    ///
377    /// `mmio_base` must be a valid pointer to an appropriately-mapped MMIO region of at least
378    /// 16 MiB (if `cam == Cam::MmioCam`) or 256 MiB (if `cam == Cam::Ecam`). The pointer must be
379    /// valid for the lifetime `'a`, which implies that no Rust references may be used to access any
380    /// of the memory region at least during that lifetime.
381    pub unsafe fn new(mmio_base: *mut u8, cam: Cam) -> Self {
382        assert!(mmio_base as usize & 0x3 == 0);
383        Self {
384            mmio: UniqueMmioPointer::new(NonNull::slice_from_raw_parts(
385                NonNull::new(mmio_base as *mut ReadPureWrite<u32>).unwrap(),
386                cam.size() as usize / size_of::<u32>(),
387            )),
388            cam,
389        }
390    }
391}
392
393impl ConfigurationAccess for MmioCam<'_> {
394    fn read_word(&self, device_function: DeviceFunction, register_offset: u8) -> u32 {
395        let address = self.cam.cam_offset(device_function, register_offset);
396        // Right shift to convert from byte offset to word offset.
397        self.mmio
398            .deref()
399            .get((address >> 2) as usize)
400            .unwrap()
401            .read()
402    }
403
404    fn write_word(&mut self, device_function: DeviceFunction, register_offset: u8, data: u32) {
405        let address = self.cam.cam_offset(device_function, register_offset);
406        self.mmio.get((address >> 2) as usize).unwrap().write(data);
407    }
408
409    unsafe fn unsafe_clone(&self) -> Self {
410        Self {
411            mmio: UniqueMmioPointer::new(NonNull::new(self.mmio.ptr().cast_mut()).unwrap()),
412            cam: self.cam,
413        }
414    }
415}
416
417// SAFETY: `&MmioCam` only allows MMIO reads, which are fine to happen concurrently on different CPU
418// cores.
419unsafe impl Sync for MmioCam<'_> {}
420
421/// Information about a PCI Base Address Register.
422#[derive(Clone, Debug, Eq, PartialEq)]
423pub enum BarInfo {
424    /// The BAR is for a memory region.
425    Memory {
426        /// The size of the BAR address and where it can be located.
427        address_type: MemoryBarType,
428        /// If true, then reading from the region doesn't have side effects. The CPU may cache reads
429        /// and merge repeated stores.
430        prefetchable: bool,
431        /// The memory address, always 16-byte aligned.
432        address: u64,
433        /// The size of the BAR in bytes.
434        size: u64,
435    },
436    /// The BAR is for an I/O region.
437    IO {
438        /// The I/O address, always 4-byte aligned.
439        address: u32,
440        /// The size of the BAR in bytes.
441        size: u32,
442    },
443}
444
445impl BarInfo {
446    /// Returns whether this BAR is a 64-bit memory region, and so takes two entries in the table in
447    /// configuration space.
448    pub fn takes_two_entries(&self) -> bool {
449        matches!(
450            self,
451            BarInfo::Memory {
452                address_type: MemoryBarType::Width64,
453                ..
454            }
455        )
456    }
457
458    /// Returns the address and size of this BAR if it is a memory bar, or `None` if it is an IO
459    /// BAR.
460    pub fn memory_address_size(&self) -> Option<(u64, u64)> {
461        if let Self::Memory { address, size, .. } = self {
462            Some((*address, *size))
463        } else {
464            None
465        }
466    }
467}
468
469impl Display for BarInfo {
470    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
471        match self {
472            Self::Memory {
473                address_type,
474                prefetchable,
475                address,
476                size,
477            } => write!(
478                f,
479                "Memory space at {:#010x}, size {}, type {:?}, prefetchable {}",
480                address, size, address_type, prefetchable
481            ),
482            Self::IO { address, size } => {
483                write!(f, "I/O space at {:#010x}, size {}", address, size)
484            }
485        }
486    }
487}
488
489/// The location allowed for a memory BAR.
490#[derive(Copy, Clone, Debug, Eq, PartialEq)]
491pub enum MemoryBarType {
492    /// The BAR has a 32-bit address and can be mapped anywhere in 32-bit address space.
493    Width32,
494    /// The BAR must be mapped below 1MiB.
495    Below1MiB,
496    /// The BAR has a 64-bit address and can be mapped anywhere in 64-bit address space.
497    Width64,
498}
499
500impl From<MemoryBarType> for u8 {
501    fn from(bar_type: MemoryBarType) -> Self {
502        match bar_type {
503            MemoryBarType::Width32 => 0,
504            MemoryBarType::Below1MiB => 1,
505            MemoryBarType::Width64 => 2,
506        }
507    }
508}
509
510impl TryFrom<u8> for MemoryBarType {
511    type Error = PciError;
512
513    fn try_from(value: u8) -> Result<Self, Self::Error> {
514        match value {
515            0 => Ok(Self::Width32),
516            1 => Ok(Self::Below1MiB),
517            2 => Ok(Self::Width64),
518            _ => Err(PciError::InvalidBarType),
519        }
520    }
521}
522
523/// Iterator over capabilities for a device.
524#[derive(Debug)]
525pub struct CapabilityIterator<'a, C: ConfigurationAccess> {
526    configuration_access: &'a C,
527    device_function: DeviceFunction,
528    next_capability_offset: Option<u8>,
529}
530
531impl<C: ConfigurationAccess> Iterator for CapabilityIterator<'_, C> {
532    type Item = CapabilityInfo;
533
534    fn next(&mut self) -> Option<Self::Item> {
535        let offset = self.next_capability_offset?;
536
537        // Read the first 4 bytes of the capability.
538        let capability_header = self
539            .configuration_access
540            .read_word(self.device_function, offset);
541        let id = capability_header as u8;
542        let next_offset = (capability_header >> 8) as u8;
543        let private_header = (capability_header >> 16) as u16;
544
545        self.next_capability_offset = if next_offset == 0 {
546            None
547        } else if next_offset < 64 || next_offset & 0x3 != 0 {
548            warn!("Invalid next capability offset {:#04x}", next_offset);
549            None
550        } else {
551            Some(next_offset)
552        };
553
554        Some(CapabilityInfo {
555            offset,
556            id,
557            private_header,
558        })
559    }
560}
561
562/// Information about a PCI device capability.
563#[derive(Debug, Copy, Clone, Eq, PartialEq)]
564pub struct CapabilityInfo {
565    /// The offset of the capability in the PCI configuration space of the device function.
566    pub offset: u8,
567    /// The ID of the capability.
568    pub id: u8,
569    /// The third and fourth bytes of the capability, to save reading them again.
570    pub private_header: u16,
571}
572
573/// An iterator which enumerates PCI devices and functions on a given bus.
574#[derive(Debug)]
575pub struct BusDeviceIterator<C: ConfigurationAccess> {
576    /// This must only be used to read read-only fields, and must not be exposed outside this
577    /// module, because it uses the same CAM as the main `PciRoot` instance.
578    configuration_access: C,
579    next: DeviceFunction,
580}
581
582impl<C: ConfigurationAccess> Iterator for BusDeviceIterator<C> {
583    type Item = (DeviceFunction, DeviceFunctionInfo);
584
585    fn next(&mut self) -> Option<Self::Item> {
586        while self.next.device < MAX_DEVICES {
587            // Read the header for the current device and function.
588            let current = self.next;
589            let device_vendor = self.configuration_access.read_word(current, 0);
590
591            // Advance to the next device or function.
592            self.next.function += 1;
593            if self.next.function >= MAX_FUNCTIONS {
594                self.next.function = 0;
595                self.next.device += 1;
596            }
597
598            if device_vendor != INVALID_READ {
599                let class_revision = self.configuration_access.read_word(current, 8);
600                let device_id = (device_vendor >> 16) as u16;
601                let vendor_id = device_vendor as u16;
602                let class = (class_revision >> 24) as u8;
603                let subclass = (class_revision >> 16) as u8;
604                let prog_if = (class_revision >> 8) as u8;
605                let revision = class_revision as u8;
606                let bist_type_latency_cache = self.configuration_access.read_word(current, 12);
607                let header_type = HeaderType::from((bist_type_latency_cache >> 16) as u8 & 0x7f);
608                return Some((
609                    current,
610                    DeviceFunctionInfo {
611                        vendor_id,
612                        device_id,
613                        class,
614                        subclass,
615                        prog_if,
616                        revision,
617                        header_type,
618                    },
619                ));
620            }
621        }
622        None
623    }
624}
625
626/// An identifier for a PCI bus, device and function.
627#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
628pub struct DeviceFunction {
629    /// The PCI bus number, between 0 and 255.
630    pub bus: u8,
631    /// The device number on the bus, between 0 and 31.
632    pub device: u8,
633    /// The function number of the device, between 0 and 7.
634    pub function: u8,
635}
636
637impl DeviceFunction {
638    /// Returns whether the device and function numbers are valid, i.e. the device is between 0 and
639    /// 31, and the function is between 0 and 7.
640    pub fn valid(&self) -> bool {
641        self.device < 32 && self.function < 8
642    }
643}
644
645impl Display for DeviceFunction {
646    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
647        write!(f, "{:02x}:{:02x}.{}", self.bus, self.device, self.function)
648    }
649}
650
651/// Information about a PCI device function.
652#[derive(Clone, Debug, Eq, PartialEq)]
653pub struct DeviceFunctionInfo {
654    /// The PCI vendor ID.
655    pub vendor_id: u16,
656    /// The PCI device ID.
657    pub device_id: u16,
658    /// The PCI class.
659    pub class: u8,
660    /// The PCI subclass.
661    pub subclass: u8,
662    /// The PCI programming interface byte.
663    pub prog_if: u8,
664    /// The PCI revision ID.
665    pub revision: u8,
666    /// The type of PCI device.
667    pub header_type: HeaderType,
668}
669
670impl Display for DeviceFunctionInfo {
671    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
672        write!(
673            f,
674            "{:04x}:{:04x} (class {:02x}.{:02x}, rev {:02x}) {:?}",
675            self.vendor_id,
676            self.device_id,
677            self.class,
678            self.subclass,
679            self.revision,
680            self.header_type,
681        )
682    }
683}
684
685/// The type of a PCI device function header.
686#[derive(Copy, Clone, Debug, Eq, PartialEq)]
687pub enum HeaderType {
688    /// A normal PCI device.
689    Standard,
690    /// A PCI to PCI bridge.
691    PciPciBridge,
692    /// A PCI to CardBus bridge.
693    PciCardbusBridge,
694    /// Unrecognised header type.
695    Unrecognised(u8),
696}
697
698impl From<u8> for HeaderType {
699    fn from(value: u8) -> Self {
700        match value {
701            0x00 => Self::Standard,
702            0x01 => Self::PciPciBridge,
703            0x02 => Self::PciCardbusBridge,
704            _ => Self::Unrecognised(value),
705        }
706    }
707}
708
709#[cfg(test)]
710mod tests {
711    use super::*;
712
713    #[test]
714    fn read_status_command() {
715        let status_command = 0x0020_0003;
716        let device_function = DeviceFunction {
717            bus: 0,
718            device: 1,
719            function: 2,
720        };
721        let fake_cam = FakeCam {
722            device_function,
723            bar_values: [0, 1, 4, 0, 0, 0],
724            bar_masks: [
725                0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
726            ],
727            status_command,
728        };
729        let root = PciRoot::new(fake_cam);
730
731        assert_eq!(
732            root.get_status_command(device_function),
733            (
734                Status::MHZ_66_CAPABLE,
735                Command::IO_SPACE | Command::MEMORY_SPACE
736            )
737        );
738    }
739
740    #[test]
741    fn bar_info_unused() {
742        let status_command = 0x0020_0003;
743        let device_function = DeviceFunction {
744            bus: 0,
745            device: 1,
746            function: 2,
747        };
748        let fake_cam = FakeCam {
749            device_function,
750            bar_values: [0, 1, 4, 0, 0, 0],
751            bar_masks: [
752                0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
753            ],
754            status_command,
755        };
756        let fake_cam_orig = fake_cam.clone();
757        let mut root = PciRoot::new(fake_cam);
758
759        assert_eq!(
760            root.bars(device_function).unwrap(),
761            [
762                None,
763                Some(BarInfo::IO {
764                    address: 0,
765                    size: 0,
766                }),
767                Some(BarInfo::Memory {
768                    address_type: MemoryBarType::Width64,
769                    prefetchable: false,
770                    address: 0,
771                    size: 0,
772                }),
773                None,
774                None,
775                None,
776            ]
777        );
778
779        // Status and command should be restored to their initial values, as should BAR values.
780        assert_eq!(root.configuration_access, fake_cam_orig);
781    }
782
783    #[test]
784    fn bar_info_32() {
785        let status_command = 0x0020_0003;
786        let device_function = DeviceFunction {
787            bus: 0,
788            device: 1,
789            function: 2,
790        };
791        let fake_cam = FakeCam {
792            device_function,
793            bar_values: [0b0000, 0b0010, 0b1000, 0b01, 0b0000, 0b0000],
794            bar_masks: [63, 31, 127, 7, 1023, 255],
795            status_command,
796        };
797        let fake_cam_orig = fake_cam.clone();
798        let mut root = PciRoot::new(fake_cam);
799
800        assert_eq!(
801            root.bars(device_function).unwrap(),
802            [
803                Some(BarInfo::Memory {
804                    address_type: MemoryBarType::Width32,
805                    prefetchable: false,
806                    address: 0,
807                    size: 64,
808                }),
809                Some(BarInfo::Memory {
810                    address_type: MemoryBarType::Below1MiB,
811                    prefetchable: false,
812                    address: 0,
813                    size: 32,
814                }),
815                Some(BarInfo::Memory {
816                    address_type: MemoryBarType::Width32,
817                    prefetchable: true,
818                    address: 0,
819                    size: 128,
820                }),
821                Some(BarInfo::IO {
822                    address: 0,
823                    size: 8,
824                }),
825                Some(BarInfo::Memory {
826                    address_type: MemoryBarType::Width32,
827                    prefetchable: false,
828                    address: 0,
829                    size: 1024,
830                }),
831                Some(BarInfo::Memory {
832                    address_type: MemoryBarType::Width32,
833                    prefetchable: false,
834                    address: 0,
835                    size: 256,
836                }),
837            ]
838        );
839
840        // Status and command should be restored to their initial values, as should BAR values.
841        assert_eq!(root.configuration_access, fake_cam_orig);
842    }
843
844    #[test]
845    fn bar_info_64() {
846        let status_command = 0x0020_0003;
847        let device_function = DeviceFunction {
848            bus: 0,
849            device: 1,
850            function: 2,
851        };
852        let fake_cam = FakeCam {
853            device_function,
854            bar_values: [0b0100, 0, 0b0100, 0, 0b1100, 0],
855            bar_masks: [127, 0, 0xffffffff, 3, 255, 0],
856            status_command,
857        };
858        let fake_cam_orig = fake_cam.clone();
859        let mut root = PciRoot::new(fake_cam);
860
861        assert_eq!(
862            root.bars(device_function).unwrap(),
863            [
864                Some(BarInfo::Memory {
865                    address_type: MemoryBarType::Width64,
866                    prefetchable: false,
867                    address: 0,
868                    size: 128,
869                }),
870                None,
871                Some(BarInfo::Memory {
872                    address_type: MemoryBarType::Width64,
873                    prefetchable: false,
874                    address: 0,
875                    size: 0x400000000,
876                }),
877                None,
878                Some(BarInfo::Memory {
879                    address_type: MemoryBarType::Width64,
880                    prefetchable: true,
881                    address: 0,
882                    size: 256,
883                }),
884                None,
885            ]
886        );
887
888        // Status and command should be restored to their initial values, as should BAR values.
889        assert_eq!(root.configuration_access, fake_cam_orig);
890    }
891
892    #[derive(Clone, Debug, Eq, PartialEq)]
893    struct FakeCam {
894        device_function: DeviceFunction,
895        bar_values: [u32; 6],
896        // Bits which can't be changed.
897        bar_masks: [u32; 6],
898        status_command: u32,
899    }
900
901    impl ConfigurationAccess for FakeCam {
902        fn read_word(&self, device_function: DeviceFunction, register_offset: u8) -> u32 {
903            assert_eq!(device_function, self.device_function);
904            assert_eq!(register_offset & 0b11, 0);
905            if register_offset == STATUS_COMMAND_OFFSET {
906                self.status_command
907            } else if register_offset >= BAR0_OFFSET && register_offset < 0x28 {
908                let bar_index = usize::from((register_offset - BAR0_OFFSET) / 4);
909                self.bar_values[bar_index]
910            } else {
911                println!("Reading unsupported register offset {}", register_offset);
912                0xffffffff
913            }
914        }
915
916        fn write_word(&mut self, device_function: DeviceFunction, register_offset: u8, data: u32) {
917            assert_eq!(device_function, self.device_function);
918            assert_eq!(register_offset & 0b11, 0);
919            if register_offset == STATUS_COMMAND_OFFSET {
920                // Ignore write to status, only write to command.
921                self.status_command = (self.status_command & 0xffff_0000) | (data & 0x0000_ffff);
922            } else if register_offset >= BAR0_OFFSET && register_offset < 0x28 {
923                let bar_index = usize::from((register_offset - BAR0_OFFSET) / 4);
924                let bar_mask = self.bar_masks[bar_index];
925                self.bar_values[bar_index] =
926                    (bar_mask & self.bar_values[bar_index]) | (!bar_mask & data);
927            } else {
928                println!("Ignoring write of {:#010x} to {}", data, register_offset);
929                return;
930            }
931        }
932
933        unsafe fn unsafe_clone(&self) -> Self {
934            self.clone()
935        }
936    }
937}