chipset_device/pci.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! PCI configuration space access
5
6use crate::ChipsetDevice;
7use crate::io::IoResult;
8
9/// Implemented by devices which have a PCI config space.
10pub trait PciConfigSpace: ChipsetDevice {
11 /// Dispatch a PCI config space read to the device with the given address.
12 fn pci_cfg_read(&mut self, offset: u16, value: &mut u32) -> IoResult;
13 /// Dispatch a PCI config space write to the device with the given address.
14 fn pci_cfg_write(&mut self, offset: u16, value: u32) -> IoResult;
15
16 /// Forward a PCI configuration space read to a downstream device.
17 ///
18 /// Default implementation returns `None`, indicating this device doesn't support routing.
19 /// Routing components like switches and bridges should override this method.
20 ///
21 /// # Parameters
22 /// - `bus`: Target bus number for the downstream device
23 /// - `device_function`: Combined device and function number (device << 3 | function)
24 /// - `offset`: Configuration space offset within the target device
25 /// - `value`: Pointer to receive the read value
26 ///
27 /// # Returns
28 /// `Some(IoResult)` if the routing component handled the forward, `None` if
29 /// the component doesn't support routing or the target is not reachable.
30 fn pci_cfg_read_forward(
31 &mut self,
32 _bus: u8,
33 _device_function: u8,
34 _offset: u16,
35 _value: &mut u32,
36 ) -> Option<IoResult> {
37 None
38 }
39
40 /// Forward a PCI configuration space write to a downstream device.
41 ///
42 /// Default implementation returns `None`, indicating this device doesn't support routing.
43 /// Routing components like switches and bridges should override this method.
44 ///
45 /// # Parameters
46 /// - `bus`: Target bus number for the downstream device
47 /// - `device_function`: Combined device and function number (device << 3 | function)
48 /// - `offset`: Configuration space offset within the target device
49 /// - `value`: Value to write to the target device
50 ///
51 /// # Returns
52 /// `Some(IoResult)` if the routing component handled the forward, `None` if
53 /// the component doesn't support routing or the target is not reachable.
54 fn pci_cfg_write_forward(
55 &mut self,
56 _bus: u8,
57 _device_function: u8,
58 _offset: u16,
59 _value: u32,
60 ) -> Option<IoResult> {
61 None
62 }
63
64 /// Check if the device has a suggested (bus, device, function) it expects
65 /// to be located at.
66 ///
67 /// The term "suggested" is important here, as it's important to note that
68 /// one of the major selling points of PCI was that PCI devices _shouldn't_
69 /// need to care about about what PCI address they are initialized at. i.e:
70 /// on a physical machine, it shouldn't matter that your fancy GTX 4090 is
71 /// plugged into the first vs. second PCI slot.
72 ///
73 /// ..that said, there are some instances where it makes sense for an
74 /// emulated device to declare its suggested PCI address:
75 ///
76 /// 1. Devices that emulate bespoke PCI devices part of a particular
77 /// system's chipset.
78 /// - e.g: the PIIX4 chipset includes several bespoke PCI devices that are
79 /// required to have specific PCI addresses. While it _would_ be
80 /// possible to relocate them to a different address, it may break OSes
81 /// that assume they exist at those spec-declared addresses.
82 /// 2. Multi-function PCI devices
83 /// - In an unfortunate case of inverted responsibilities, there is a
84 /// single bit in the PCI configuration space's `Header` register that
85 /// denotes if a particular PCI card includes multiple functions.
86 /// - Since multi-function devices are pretty rare, `ChipsetDevice` opted
87 /// to model each function as its own device, which in turn implies that
88 /// in order to correctly init a multi-function PCI card, the
89 /// `ChipsetDevice` with function 0 _must_ report if there are other
90 /// functions at the same bus and device.
91 fn suggested_bdf(&mut self) -> Option<(u8, u8, u8)> {
92 None
93 }
94}