1use crate::{
2 sdt::{SdtHeader, Signature},
3 AcpiTable,
4};
5use core::{mem, slice};
6
7#[cfg(feature = "allocator_api")]
13pub struct PciConfigRegions<'a, A>
14where
15 A: core::alloc::Allocator,
16{
17 regions: crate::ManagedSlice<'a, McfgEntry, A>,
18}
19
20#[cfg(feature = "alloc")]
21impl<'a> PciConfigRegions<'a, alloc::alloc::Global> {
22 pub fn new<H>(tables: &crate::AcpiTables<H>) -> crate::AcpiResult<PciConfigRegions<'a, alloc::alloc::Global>>
23 where
24 H: crate::AcpiHandler,
25 {
26 Self::new_in(tables, alloc::alloc::Global)
27 }
28}
29
30#[cfg(feature = "allocator_api")]
31impl<'a, A> PciConfigRegions<'a, A>
32where
33 A: core::alloc::Allocator,
34{
35 pub fn new_in<H>(tables: &crate::AcpiTables<H>, allocator: A) -> crate::AcpiResult<PciConfigRegions<'a, A>>
36 where
37 H: crate::AcpiHandler,
38 {
39 let mcfg = tables.find_table::<Mcfg>()?;
40 let mcfg_entries = mcfg.entries();
41
42 let mut regions = crate::ManagedSlice::new_in(mcfg_entries.len(), allocator)?;
43 regions.copy_from_slice(mcfg_entries);
44
45 Ok(Self { regions })
46 }
47
48 pub fn physical_address(&self, segment_group_no: u16, bus: u8, device: u8, function: u8) -> Option<u64> {
51 let region = self.regions.iter().find(|region| {
55 region.pci_segment_group == segment_group_no
56 && (region.bus_number_start..=region.bus_number_end).contains(&bus)
57 })?;
58
59 Some(
60 region.base_address
61 + ((u64::from(bus - region.bus_number_start) << 20)
62 | (u64::from(device) << 15)
63 | (u64::from(function) << 12)),
64 )
65 }
66
67 pub fn iter(&self) -> PciConfigEntryIterator {
70 PciConfigEntryIterator { entries: &self.regions, index: 0 }
71 }
72}
73
74pub struct PciConfigEntry {
76 pub segment_group: u16,
77 pub bus_range: core::ops::RangeInclusive<u8>,
78 pub physical_address: usize,
79}
80
81pub struct PciConfigEntryIterator<'a> {
83 entries: &'a [McfgEntry],
84 index: usize,
85}
86
87impl Iterator for PciConfigEntryIterator<'_> {
88 type Item = PciConfigEntry;
89
90 fn next(&mut self) -> Option<Self::Item> {
91 let entry = self.entries.get(self.index)?;
92 self.index += 1;
93
94 Some(PciConfigEntry {
95 segment_group: entry.pci_segment_group,
96 bus_range: entry.bus_number_start..=entry.bus_number_end,
97 physical_address: entry.base_address as usize,
98 })
99 }
100}
101
102#[repr(C, packed)]
103pub struct Mcfg {
104 header: SdtHeader,
105 _reserved: u64,
106 }
108
109unsafe impl AcpiTable for Mcfg {
111 const SIGNATURE: Signature = Signature::MCFG;
112
113 fn header(&self) -> &SdtHeader {
114 &self.header
115 }
116}
117
118impl Mcfg {
119 pub fn entries(&self) -> &[McfgEntry] {
122 let length = self.header.length as usize - mem::size_of::<Mcfg>();
123
124 let num_entries = length / mem::size_of::<McfgEntry>();
127
128 unsafe {
129 let pointer = (self as *const Mcfg as *const u8).add(mem::size_of::<Mcfg>()) as *const McfgEntry;
130 slice::from_raw_parts(pointer, num_entries)
131 }
132 }
133}
134
135impl core::fmt::Debug for Mcfg {
136 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
137 formatter.debug_struct("Mcfg").field("header", &self.header).field("entries", &self.entries()).finish()
138 }
139}
140
141#[derive(Clone, Copy, Debug)]
142#[repr(C, packed)]
143pub struct McfgEntry {
144 pub base_address: u64,
145 pub pci_segment_group: u16,
146 pub bus_number_start: u8,
147 pub bus_number_end: u8,
148 _reserved: u32,
149}