1#[cfg(feature = "alloc")]
5pub use self::alloc_parse::*;
6
7use super::Table;
8use crate::packed_nums::*;
9use core::mem::size_of;
10use static_assertions::const_assert_eq;
11use thiserror::Error;
12use zerocopy::FromBytes;
13use zerocopy::Immutable;
14use zerocopy::IntoBytes;
15use zerocopy::KnownLayout;
16use zerocopy::Ref;
17use zerocopy::Unaligned;
18
19#[repr(C)]
20#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
21pub struct McfgHeader {
22 pub rsvd: u64_ne,
23}
24
25impl McfgHeader {
26 pub fn new() -> Self {
27 McfgHeader { rsvd: 0.into() }
28 }
29}
30
31impl Table for McfgHeader {
32 const SIGNATURE: [u8; 4] = *b"MCFG";
33}
34
35pub const MCFG_REVISION: u8 = 1;
36
37#[repr(C)]
38#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
39pub struct McfgSegmentBusRange {
40 pub ecam_base: u64_ne,
41 pub segment: u16_ne,
42 pub start_bus: u8,
43 pub end_bus: u8,
44 pub rsvd: u32_ne,
45}
46
47const_assert_eq!(size_of::<McfgSegmentBusRange>(), 16);
48
49impl McfgSegmentBusRange {
50 pub fn new(ecam_base: u64, segment: u16, start_bus: u8, end_bus: u8) -> Self {
51 Self {
52 ecam_base: ecam_base.into(),
53 segment: segment.into(),
54 start_bus,
55 end_bus,
56 rsvd: 0.into(),
57 }
58 }
59}
60
61#[derive(Debug, Error)]
62pub enum ParseMcfgError {
63 #[error("could not read standard ACPI header")]
64 MissingAcpiHeader,
65 #[error("invalid signature. expected b\"MCFG\", found {0:?}")]
66 InvalidSignature([u8; 4]),
67 #[error("mismatched lengh, header: {0}, actual: {1}")]
68 MismatchedLength(usize, usize),
69 #[error("could not read fixed MCFG header")]
70 MissingFixedHeader,
71 #[error("could not read segment bus range structure")]
72 BadSegmentBusRange,
73}
74
75pub fn parse_mcfg<'a>(
76 raw_mcfg: &'a [u8],
77 mut on_segment_bus_range: impl FnMut(&'a McfgSegmentBusRange),
78) -> Result<(&'a crate::Header, &'a McfgHeader), ParseMcfgError> {
79 let raw_mcfg_len = raw_mcfg.len();
80 let (acpi_header, buf) = Ref::<_, crate::Header>::from_prefix(raw_mcfg)
81 .map_err(|_| ParseMcfgError::MissingAcpiHeader)?;
82
83 if acpi_header.signature != *b"MCFG" {
84 return Err(ParseMcfgError::InvalidSignature(acpi_header.signature));
85 }
86
87 if acpi_header.length.get() as usize != raw_mcfg_len {
88 return Err(ParseMcfgError::MismatchedLength(
89 acpi_header.length.get() as usize,
90 raw_mcfg_len,
91 ));
92 }
93
94 let (mcfg_header, mut buf) =
95 Ref::<_, McfgHeader>::from_prefix(buf).map_err(|_| ParseMcfgError::MissingFixedHeader)?;
96
97 while !buf.is_empty() {
98 let (sbr, rest) = Ref::<_, McfgSegmentBusRange>::from_prefix(buf)
99 .map_err(|_| ParseMcfgError::BadSegmentBusRange)?;
100 on_segment_bus_range(Ref::into_ref(sbr));
101 buf = rest
102 }
103
104 Ok((Ref::into_ref(acpi_header), Ref::into_ref(mcfg_header)))
105}
106
107#[cfg(feature = "alloc")]
108pub mod alloc_parse {
109 use super::*;
110 use alloc::vec::Vec;
111
112 #[derive(Debug)]
113 pub struct BorrowedMcfg<'a> {
114 pub acpi_header: &'a crate::Header,
115 pub mcfg_header: &'a McfgHeader,
116 pub segment_bus_ranges: Vec<&'a McfgSegmentBusRange>,
117 }
118
119 #[derive(Debug)]
120 pub struct OwnedMcfg {
121 pub acpi_header: crate::Header,
122 pub mcfg_header: McfgHeader,
123 pub segment_bus_ranges: Vec<McfgSegmentBusRange>,
124 }
125
126 impl From<BorrowedMcfg<'_>> for OwnedMcfg {
127 fn from(b: BorrowedMcfg<'_>) -> Self {
128 OwnedMcfg {
129 acpi_header: *b.acpi_header,
130 mcfg_header: *b.mcfg_header,
131 segment_bus_ranges: b.segment_bus_ranges.into_iter().copied().collect(),
132 }
133 }
134 }
135
136 impl BorrowedMcfg<'_> {
137 pub fn new(raw_mcfg: &[u8]) -> Result<BorrowedMcfg<'_>, ParseMcfgError> {
138 let mut segment_bus_ranges = Vec::new();
139 let (acpi_header, mcfg_header) = parse_mcfg(raw_mcfg, |x| segment_bus_ranges.push(x))?;
140
141 Ok(BorrowedMcfg {
142 acpi_header,
143 mcfg_header,
144 segment_bus_ranges,
145 })
146 }
147 }
148
149 impl OwnedMcfg {
150 pub fn new(raw_mcfg: &[u8]) -> Result<OwnedMcfg, ParseMcfgError> {
151 Ok(BorrowedMcfg::new(raw_mcfg)?.into())
152 }
153 }
154}