Nothing to see here, move along meow
1use crate::static_vec::StaticVec;
2
3const DMAR_HEADER_SIZE: usize = 48;
4
5const DRHD_TYPE: u16 = 0;
6const RMRR_TYPE: u16 = 1;
7
8#[repr(C, packed)]
9struct DmarHeader {
10 _sdt_header: [u8; 36],
11 host_address_width: u8,
12 flags: u8,
13 _reserved: [u8; 10],
14}
15
16#[repr(C, packed)]
17struct RemappingStructHeader {
18 structure_type: u16,
19 length: u16,
20}
21
22#[repr(C, packed)]
23struct DrhdEntry {
24 _header: RemappingStructHeader,
25 flags: u8,
26 _reserved: u8,
27 segment: u16,
28 register_base: u64,
29}
30
31#[repr(C, packed)]
32struct RmrrEntry {
33 _header: RemappingStructHeader,
34 _reserved: u16,
35 segment: u16,
36 base_address: u64,
37 limit_address: u64,
38}
39
40#[repr(C, packed)]
41struct DeviceScopeEntry {
42 scope_type: u8,
43 length: u8,
44 _reserved: u16,
45 enumeration_id: u8,
46 start_bus: u8,
47}
48
49#[repr(C, packed)]
50struct DeviceScopePath {
51 device: u8,
52 function: u8,
53}
54
55#[derive(Debug, Clone)]
56#[allow(dead_code)]
57pub struct DeviceScopeInfo {
58 pub scope_type: u8,
59 pub enumeration_id: u8,
60 pub start_bus: u8,
61 pub path: StaticVec<(u8, u8), 4>,
62}
63
64#[derive(Debug, Clone)]
65pub struct DrhdInfo {
66 pub register_base: u64,
67 pub segment: u16,
68 pub flags: u8,
69 #[allow(dead_code)]
70 pub device_scopes: StaticVec<DeviceScopeInfo, 8>,
71}
72
73#[derive(Debug, Clone)]
74pub struct RmrrInfo {
75 #[allow(dead_code)]
76 pub segment: u16,
77 pub base_address: u64,
78 pub limit_address: u64,
79 pub device_scopes: StaticVec<DeviceScopeInfo, 8>,
80}
81
82#[derive(Debug, Clone)]
83pub struct DmarInfo {
84 #[allow(dead_code)]
85 pub host_address_width: u8,
86 #[allow(dead_code)]
87 pub flags: u8,
88 pub drhd_units: StaticVec<DrhdInfo, 4>,
89 pub rmrr_regions: StaticVec<RmrrInfo, 8>,
90}
91
92fn parse_device_scopes(
93 base: *const u8,
94 entry_len: usize,
95 fixed_header_size: usize,
96) -> StaticVec<DeviceScopeInfo, 8> {
97 let scope_start = fixed_header_size;
98 let min_scope = core::mem::size_of::<DeviceScopeEntry>();
99 core::iter::successors(Some(scope_start), move |&offset| {
100 if offset + min_scope > entry_len {
101 return None;
102 }
103 let scope_ptr = unsafe { base.add(offset) } as *const DeviceScopeEntry;
104 let scope_len =
105 unsafe { core::ptr::addr_of!((*scope_ptr).length).read_unaligned() } as usize;
106 if scope_len < min_scope {
107 None
108 } else {
109 Some(offset + scope_len)
110 }
111 })
112 .take_while(|&offset| offset + min_scope <= entry_len)
113 .fold(StaticVec::new(), |mut scopes, offset| {
114 let scope_ptr = unsafe { base.add(offset) } as *const DeviceScopeEntry;
115 let raw_scope_len =
116 unsafe { core::ptr::addr_of!((*scope_ptr).length).read_unaligned() } as usize;
117 let scope_len = raw_scope_len.min(entry_len.saturating_sub(offset));
118 let scope_type = unsafe { core::ptr::addr_of!((*scope_ptr).scope_type).read_unaligned() };
119 let enumeration_id =
120 unsafe { core::ptr::addr_of!((*scope_ptr).enumeration_id).read_unaligned() };
121 let start_bus = unsafe { core::ptr::addr_of!((*scope_ptr).start_bus).read_unaligned() };
122
123 let path_offset = core::mem::size_of::<DeviceScopeEntry>();
124 let path_bytes = scope_len.saturating_sub(path_offset);
125 let path_count = path_bytes / core::mem::size_of::<DeviceScopePath>();
126
127 let path = (0..path_count).fold(StaticVec::new(), |mut p, i| {
128 let path_ptr =
129 unsafe { base.add(offset + path_offset + i * 2) } as *const DeviceScopePath;
130 let device = unsafe { core::ptr::addr_of!((*path_ptr).device).read_unaligned() };
131 let function = unsafe { core::ptr::addr_of!((*path_ptr).function).read_unaligned() };
132 let _ = p.push((device, function));
133 p
134 });
135
136 let _ = scopes.push(DeviceScopeInfo {
137 scope_type,
138 enumeration_id,
139 start_bus,
140 path,
141 });
142 scopes
143 })
144}
145
146pub fn parse_dmar(virt_addr: u64, length: u32) -> DmarInfo {
147 let base = virt_addr as *const u8;
148 let hdr_ptr = base as *const DmarHeader;
149 let host_address_width =
150 unsafe { core::ptr::addr_of!((*hdr_ptr).host_address_width).read_unaligned() };
151 let flags = unsafe { core::ptr::addr_of!((*hdr_ptr).flags).read_unaligned() };
152
153 crate::kprintln!(
154 " DMAR: host address width {}, flags {:#x}",
155 host_address_width,
156 flags
157 );
158
159 let min_entry = core::mem::size_of::<RemappingStructHeader>();
160 let entries = core::iter::successors(Some(DMAR_HEADER_SIZE), move |&offset| {
161 if offset + min_entry > length as usize {
162 return None;
163 }
164 let header_ptr = unsafe { base.add(offset) } as *const RemappingStructHeader;
165 let entry_len =
166 unsafe { core::ptr::addr_of!((*header_ptr).length).read_unaligned() } as usize;
167 if entry_len < min_entry {
168 None
169 } else {
170 Some(offset + entry_len)
171 }
172 });
173
174 let (drhd_units, rmrr_regions) = entries
175 .take_while(|&offset| offset + min_entry <= length as usize)
176 .fold(
177 (StaticVec::new(), StaticVec::new()),
178 |(mut units, mut rmrrs), offset| {
179 let header_ptr = unsafe { base.add(offset) } as *const RemappingStructHeader;
180 let structure_type =
181 unsafe { core::ptr::addr_of!((*header_ptr).structure_type).read_unaligned() };
182 let entry_len =
183 unsafe { core::ptr::addr_of!((*header_ptr).length).read_unaligned() } as usize;
184
185 match structure_type {
186 DRHD_TYPE if entry_len >= core::mem::size_of::<DrhdEntry>() => {
187 let drhd_ptr = unsafe { base.add(offset) } as *const DrhdEntry;
188 let drhd_flags =
189 unsafe { core::ptr::addr_of!((*drhd_ptr).flags).read_unaligned() };
190 let segment =
191 unsafe { core::ptr::addr_of!((*drhd_ptr).segment).read_unaligned() };
192 let register_base = unsafe {
193 core::ptr::addr_of!((*drhd_ptr).register_base).read_unaligned()
194 };
195
196 let device_scopes = parse_device_scopes(
197 unsafe { base.add(offset) },
198 entry_len,
199 core::mem::size_of::<DrhdEntry>(),
200 );
201
202 crate::kprintln!(
203 " DMAR: DRHD at {:#x}, segment {}, flags {:#x}, {} device scope(s)",
204 register_base,
205 segment,
206 drhd_flags,
207 device_scopes.len()
208 );
209
210 let _ = units.push(DrhdInfo {
211 register_base,
212 segment,
213 flags: drhd_flags,
214 device_scopes,
215 });
216 }
217 RMRR_TYPE if entry_len >= core::mem::size_of::<RmrrEntry>() => {
218 let rmrr_ptr = unsafe { base.add(offset) } as *const RmrrEntry;
219 let segment =
220 unsafe { core::ptr::addr_of!((*rmrr_ptr).segment).read_unaligned() };
221 let base_address = unsafe {
222 core::ptr::addr_of!((*rmrr_ptr).base_address).read_unaligned()
223 };
224 let limit_address = unsafe {
225 core::ptr::addr_of!((*rmrr_ptr).limit_address).read_unaligned()
226 };
227
228 let device_scopes = parse_device_scopes(
229 unsafe { base.add(offset) },
230 entry_len,
231 core::mem::size_of::<RmrrEntry>(),
232 );
233
234 crate::kprintln!(
235 " DMAR: RMRR {:#x}-{:#x}, segment {}, {} device scope(s)",
236 base_address,
237 limit_address,
238 segment,
239 device_scopes.len()
240 );
241
242 let _ = rmrrs.push(RmrrInfo {
243 segment,
244 base_address,
245 limit_address,
246 device_scopes,
247 });
248 }
249 _ => {}
250 }
251
252 (units, rmrrs)
253 },
254 );
255
256 DmarInfo {
257 host_address_width,
258 flags,
259 drhd_units,
260 rmrr_regions,
261 }
262}