1use super::Table;
7use crate::packed_nums::*;
8use core::mem::size_of;
9use static_assertions::const_assert_eq;
10use zerocopy::FromBytes;
11use zerocopy::Immutable;
12use zerocopy::IntoBytes;
13use zerocopy::KnownLayout;
14use zerocopy::Unaligned;
15
16pub const IORT_REVISION: u8 = 5;
17pub const IORT_NODE_OFFSET: u32 = size_of::<crate::Header>() as u32 + size_of::<Iort>() as u32;
18
19pub const IORT_NODE_TYPE_ITS_GROUP: u8 = 0x00;
20pub const IORT_NODE_TYPE_PCI_ROOT_COMPLEX: u8 = 0x02;
21pub const IORT_NODE_TYPE_SMMUV3: u8 = 0x04;
22pub const IORT_NODE_TYPE_RMR: u8 = 0x06;
23
24pub const IORT_PCI_ROOT_COMPLEX_REVISION: u8 = 3;
25pub const IORT_ITS_GROUP_REVISION: u8 = 1;
26pub const IORT_SMMUV3_REVISION: u8 = 5;
27
28pub const IORT_NODE_COHERENT: u32 = 0x00000001;
29pub const IORT_MEMORY_ACCESS_COHERENCY: u8 = 1 << 0;
30pub const IORT_MEMORY_ACCESS_ATTRIBUTES: u8 = 1 << 1;
31pub const IORT_ID_SINGLE_MAPPING: u32 = 1 << 0;
32
33#[repr(C)]
34#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
35pub struct Iort {
36 pub node_count: u32_ne,
37 pub node_offset: u32_ne,
38 pub reserved: u32_ne,
39}
40
41impl Iort {
42 pub fn new(node_count: u32) -> Self {
43 Self {
44 node_count: node_count.into(),
45 node_offset: IORT_NODE_OFFSET.into(),
46 reserved: 0.into(),
47 }
48 }
49}
50
51impl Table for Iort {
52 const SIGNATURE: [u8; 4] = *b"IORT";
53}
54
55const_assert_eq!(size_of::<Iort>(), 12);
56const_assert_eq!(IORT_NODE_OFFSET as usize, 48);
57
58#[repr(C, packed)]
59#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
60pub struct IortNodeHeader {
61 pub node_type: u8,
62 pub length: u16_ne,
63 pub revision: u8,
64 pub identifier: u32_ne,
65 pub mapping_count: u32_ne,
66 pub mapping_offset: u32_ne,
67}
68
69impl IortNodeHeader {
70 pub fn new<T>(node_type: u8, revision: u8, identifier: u32, mapping_count: u32) -> Self {
71 Self {
72 node_type,
73 length: (size_of::<T>() as u16).into(),
74 revision,
75 identifier: identifier.into(),
76 mapping_count: mapping_count.into(),
77 mapping_offset: if mapping_count == 0 {
78 0.into()
79 } else {
80 (size_of::<T>() as u32).into()
81 },
82 }
83 }
84}
85
86const_assert_eq!(size_of::<IortNodeHeader>(), 16);
87
88#[repr(C)]
89#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
90pub struct IortMemoryAccessProperties {
91 pub cache_coherency: u32_ne,
92 pub hints: u8,
93 pub reserved: u16_ne,
94 pub memory_flags: u8,
95}
96
97impl IortMemoryAccessProperties {
98 pub fn coherent() -> Self {
99 Self {
100 cache_coherency: IORT_NODE_COHERENT.into(),
101 hints: 0,
102 reserved: 0.into(),
103 memory_flags: IORT_MEMORY_ACCESS_COHERENCY | IORT_MEMORY_ACCESS_ATTRIBUTES,
104 }
105 }
106}
107
108const_assert_eq!(size_of::<IortMemoryAccessProperties>(), 8);
109
110#[repr(C, packed)]
111#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
112pub struct IortPciRootComplex {
113 pub header: IortNodeHeader,
114 pub memory_properties: IortMemoryAccessProperties,
115 pub ats_attribute: u32_ne,
116 pub pci_segment_number: u32_ne,
117 pub memory_address_limit: u8,
118 pub reserved: [u8; 3],
119}
120
121impl IortPciRootComplex {
122 pub fn new(identifier: u32, pci_segment_number: u16, mapping_count: u32) -> Self {
126 let mut header = IortNodeHeader::new::<Self>(
127 IORT_NODE_TYPE_PCI_ROOT_COMPLEX,
128 IORT_PCI_ROOT_COMPLEX_REVISION,
129 identifier,
130 mapping_count,
131 );
132 let total =
134 size_of::<Self>() as u16 + (mapping_count as u16) * size_of::<IortIdMapping>() as u16;
135 header.length = total.into();
136 Self {
137 header,
138 memory_properties: IortMemoryAccessProperties::coherent(),
139 ats_attribute: 0.into(),
140 pci_segment_number: u32::from(pci_segment_number).into(),
141 memory_address_limit: 64,
142 reserved: [0; 3],
143 }
144 }
145}
146
147const_assert_eq!(size_of::<IortPciRootComplex>(), 36);
148
149#[repr(C, packed)]
150#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
151pub struct IortIdMapping {
152 pub input_base: u32_ne,
153 pub id_count: u32_ne,
154 pub output_base: u32_ne,
155 pub output_reference: u32_ne,
156 pub flags: u32_ne,
157}
158
159impl IortIdMapping {
160 pub fn new(
161 input_base: u32,
162 id_count: u32,
163 output_base: u32,
164 output_reference: u32,
165 flags: u32,
166 ) -> Self {
167 Self {
168 input_base: input_base.into(),
169 id_count: id_count.into(),
170 output_base: output_base.into(),
171 output_reference: output_reference.into(),
172 flags: flags.into(),
173 }
174 }
175}
176
177const_assert_eq!(size_of::<IortIdMapping>(), 20);
178
179#[repr(C, packed)]
181#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
182pub struct IortItsGroup {
183 pub header: IortNodeHeader,
184 pub its_count: u32_ne,
185}
186
187impl IortItsGroup {
188 pub fn new(identifier: u32, its_count: u32) -> Self {
192 let mut header = IortNodeHeader::new::<Self>(
193 IORT_NODE_TYPE_ITS_GROUP,
194 IORT_ITS_GROUP_REVISION,
195 identifier,
196 0,
197 );
198 let total = size_of::<Self>() as u16 + (its_count as u16) * 4;
200 header.length = total.into();
201 Self {
202 header,
203 its_count: its_count.into(),
204 }
205 }
206}
207
208const_assert_eq!(size_of::<IortItsGroup>(), 20);
209
210pub const IORT_SMMUV3_FLAG_COHACC: u32 = 1 << 0;
212pub const IORT_SMMUV3_FLAG_DEVICEID_VALID: u32 = 1 << 4;
214
215pub const IORT_SMMUV3_MODEL_GENERIC: u32 = 0;
217
218#[repr(C, packed)]
220#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
221pub struct IortSmmuV3 {
222 pub header: IortNodeHeader,
223 pub base_address: u64_ne,
224 pub flags: u32_ne,
225 pub reserved: u32_ne,
226 pub vatos_address: u64_ne,
227 pub model: u32_ne,
228 pub event_gsiv: u32_ne,
229 pub pri_gsiv: u32_ne,
230 pub gerr_gsiv: u32_ne,
231 pub sync_gsiv: u32_ne,
232 pub proximity_domain: u32_ne,
233 pub device_id_mapping_index: u32_ne,
234}
235
236impl IortSmmuV3 {
237 pub fn new(
242 identifier: u32,
243 base_address: u64,
244 mapping_count: u32,
245 event_gsiv: u32,
246 gerr_gsiv: u32,
247 ) -> Self {
248 Self::new_with_device_id_mapping(
249 identifier,
250 base_address,
251 mapping_count,
252 event_gsiv,
253 gerr_gsiv,
254 0,
255 )
256 }
257
258 pub fn new_with_device_id_mapping(
265 identifier: u32,
266 base_address: u64,
267 mapping_count: u32,
268 event_gsiv: u32,
269 gerr_gsiv: u32,
270 device_id_mapping_index: u32,
271 ) -> Self {
272 let mut header = IortNodeHeader::new::<Self>(
273 IORT_NODE_TYPE_SMMUV3,
274 IORT_SMMUV3_REVISION,
275 identifier,
276 mapping_count,
277 );
278 let total =
279 size_of::<Self>() as u16 + (mapping_count as u16) * size_of::<IortIdMapping>() as u16;
280 header.length = total.into();
281 Self {
282 header,
283 base_address: base_address.into(),
284 flags: (IORT_SMMUV3_FLAG_COHACC
285 | if mapping_count > 0 {
286 IORT_SMMUV3_FLAG_DEVICEID_VALID
287 } else {
288 0
289 })
290 .into(),
291 reserved: 0.into(),
292 vatos_address: 0.into(),
293 model: IORT_SMMUV3_MODEL_GENERIC.into(),
294 event_gsiv: event_gsiv.into(),
295 pri_gsiv: 0.into(),
296 gerr_gsiv: gerr_gsiv.into(),
297 sync_gsiv: 0.into(),
298 proximity_domain: 0.into(),
299 device_id_mapping_index: device_id_mapping_index.into(),
300 }
301 }
302}
303
304const_assert_eq!(size_of::<IortSmmuV3>(), 68);
305
306pub const IORT_RMR_REVISION: u8 = 3;
309
310pub const IORT_RMR_ACCESS_PRIVILEGE: u32 = 1 << 0;
313pub const IORT_RMR_REMAP_PERMITTED: u32 = 1 << 1;
316
317#[repr(C, packed)]
320#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
321pub struct IortRmr {
322 pub header: IortNodeHeader,
323 pub flags: u32_ne,
324 pub rmr_count: u32_ne,
325 pub rmr_offset: u32_ne,
326}
327
328impl IortRmr {
329 pub fn new(identifier: u32, flags: u32, rmr_count: u32, mapping_count: u32) -> Self {
333 let mut header = IortNodeHeader::new::<Self>(
334 IORT_NODE_TYPE_RMR,
335 IORT_RMR_REVISION,
336 identifier,
337 mapping_count,
338 );
339 let total = size_of::<Self>()
344 + mapping_count as usize * size_of::<IortIdMapping>()
345 + rmr_count as usize * size_of::<IortRmrDescriptor>();
346 header.length = u16::try_from(total)
347 .expect("IORT RMR node length exceeds u16")
348 .into();
349 if mapping_count > 0 {
351 header.mapping_offset = (size_of::<Self>() as u32).into();
352 }
353 let rmr_offset = if rmr_count > 0 {
356 u32::try_from(size_of::<Self>() + mapping_count as usize * size_of::<IortIdMapping>())
357 .expect("IORT RMR descriptor offset exceeds u32")
358 } else {
359 0
360 };
361 Self {
362 header,
363 flags: flags.into(),
364 rmr_count: rmr_count.into(),
365 rmr_offset: rmr_offset.into(),
366 }
367 }
368}
369
370const_assert_eq!(size_of::<IortRmr>(), 28);
371
372#[repr(C, packed)]
374#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
375pub struct IortRmrDescriptor {
376 pub base_address: u64_ne,
377 pub length: u64_ne,
378 pub reserved: u32_ne,
379}
380
381impl IortRmrDescriptor {
382 pub fn new(base_address: u64, length: u64) -> Self {
383 Self {
384 base_address: base_address.into(),
385 length: length.into(),
386 reserved: 0.into(),
387 }
388 }
389}
390
391const_assert_eq!(size_of::<IortRmrDescriptor>(), 20);