4 Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - IO Remapping Table, Platform Design Document, Revision D, March 2018
11 #include <IndustryStandard/IoRemappingTable.h>
12 #include <Library/PrintLib.h>
13 #include <Library/UefiLib.h>
14 #include "AcpiParser.h"
15 #include "AcpiTableParser.h"
18 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo
;
20 STATIC CONST UINT32
* IortNodeCount
;
21 STATIC CONST UINT32
* IortNodeOffset
;
23 STATIC CONST UINT8
* IortNodeType
;
24 STATIC CONST UINT16
* IortNodeLength
;
25 STATIC CONST UINT32
* IortIdMappingCount
;
26 STATIC CONST UINT32
* IortIdMappingOffset
;
28 STATIC CONST UINT32
* InterruptContextCount
;
29 STATIC CONST UINT32
* InterruptContextOffset
;
30 STATIC CONST UINT32
* PmuInterruptCount
;
31 STATIC CONST UINT32
* PmuInterruptOffset
;
33 STATIC CONST UINT32
* ItsCount
;
36 This function validates the ID Mapping array count for the ITS node.
38 @param [in] Ptr Pointer to the start of the field data.
39 @param [in] Context Pointer to context specific information e.g. this
40 could be a pointer to the ACPI table header.
45 ValidateItsIdMappingCount (
50 if (*(UINT32
*)Ptr
!= 0) {
51 IncrementErrorCount ();
52 Print (L
"\nERROR: IORT ID Mapping count must be zero.");
57 This function validates the ID Mapping array count for the Performance
58 Monitoring Counter Group (PMCG) node.
60 @param [in] Ptr Pointer to the start of the field data.
61 @param [in] Context Pointer to context specific information e.g. this
62 could be a pointer to the ACPI table header.
67 ValidatePmcgIdMappingCount (
72 if (*(UINT32
*)Ptr
> 1) {
73 IncrementErrorCount ();
74 Print (L
"\nERROR: IORT ID Mapping count must not be greater than 1.");
79 This function validates the ID Mapping array offset for the ITS node.
81 @param [in] Ptr Pointer to the start of the field data.
82 @param [in] Context Pointer to context specific information e.g. this
83 could be a pointer to the ACPI table header.
88 ValidateItsIdArrayReference (
93 if (*(UINT32
*)Ptr
!= 0) {
94 IncrementErrorCount ();
95 Print (L
"\nERROR: IORT ID Mapping offset must be zero.");
100 Helper Macro for populating the IORT Node header in the ACPI_PARSER array.
102 @param [out] ValidateIdMappingCount Optional pointer to a function for
103 validating the ID Mapping count.
104 @param [out] ValidateIdArrayReference Optional pointer to a function for
105 validating the ID Array reference.
107 #define PARSE_IORT_NODE_HEADER(ValidateIdMappingCount, \
108 ValidateIdArrayReference) \
109 { L"Type", 1, 0, L"%d", NULL, (VOID**)&IortNodeType, NULL, NULL }, \
110 { L"Length", 2, 1, L"%d", NULL, (VOID**)&IortNodeLength, NULL, NULL }, \
111 { L"Revision", 1, 3, L"%d", NULL, NULL, NULL, NULL }, \
112 { L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, \
113 { L"Number of ID mappings", 4, 8, L"%d", NULL, \
114 (VOID**)&IortIdMappingCount, ValidateIdMappingCount, NULL }, \
115 { L"Reference to ID Array", 4, 12, L"0x%x", NULL, \
116 (VOID**)&IortIdMappingOffset, ValidateIdArrayReference, NULL }
119 An ACPI_PARSER array describing the ACPI IORT Table
121 STATIC CONST ACPI_PARSER IortParser
[] = {
122 PARSE_ACPI_HEADER (&AcpiHdrInfo
),
123 {L
"Number of IORT Nodes", 4, 36, L
"%d", NULL
,
124 (VOID
**)&IortNodeCount
, NULL
, NULL
},
125 {L
"Offset to Array of IORT Nodes", 4, 40, L
"0x%x", NULL
,
126 (VOID
**)&IortNodeOffset
, NULL
, NULL
},
127 {L
"Reserved", 4, 44, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
131 An ACPI_PARSER array describing the IORT node header structure.
133 STATIC CONST ACPI_PARSER IortNodeHeaderParser
[] = {
134 PARSE_IORT_NODE_HEADER (NULL
, NULL
)
138 An ACPI_PARSER array describing the IORT SMMUv1/2 node.
140 STATIC CONST ACPI_PARSER IortNodeSmmuV1V2Parser
[] = {
141 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
142 {L
"Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
143 {L
"Span", 8, 24, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
144 {L
"Model", 4, 32, L
"%d", NULL
, NULL
, NULL
, NULL
},
145 {L
"Flags", 4, 36, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
146 {L
"Reference to Global Interrupt Array", 4, 40, L
"0x%x", NULL
, NULL
, NULL
,
148 {L
"Number of context interrupts", 4, 44, L
"%d", NULL
,
149 (VOID
**)&InterruptContextCount
, NULL
, NULL
},
150 {L
"Reference to Context Interrupt Array", 4, 48, L
"0x%x", NULL
,
151 (VOID
**)&InterruptContextOffset
, NULL
, NULL
},
152 {L
"Number of PMU Interrupts", 4, 52, L
"%d", NULL
,
153 (VOID
**)&PmuInterruptCount
, NULL
, NULL
},
154 {L
"Reference to PMU Interrupt Array", 4, 56, L
"0x%x", NULL
,
155 (VOID
**)&PmuInterruptOffset
, NULL
, NULL
},
158 {L
"SMMU_NSgIrpt", 4, 60, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
159 {L
"SMMU_NSgIrpt interrupt flags", 4, 64, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
160 {L
"SMMU_NSgCfgIrpt", 4, 68, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
161 {L
"SMMU_NSgCfgIrpt interrupt flags", 4, 72, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
165 An ACPI_PARSER array describing the SMMUv1/2 Node Interrupt Array.
167 STATIC CONST ACPI_PARSER InterruptArrayParser
[] = {
168 {L
"Interrupt GSIV", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
169 {L
"Flags", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
173 An ACPI_PARSER array describing the IORT ID Mapping.
175 STATIC CONST ACPI_PARSER IortNodeIdMappingParser
[] = {
176 {L
"Input base", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
177 {L
"Number of IDs", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
178 {L
"Output base", 4, 8, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
179 {L
"Output reference", 4, 12, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
180 {L
"Flags", 4, 16, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
184 An ACPI_PARSER array describing the IORT SMMUv3 node.
186 STATIC CONST ACPI_PARSER IortNodeSmmuV3Parser
[] = {
187 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
188 {L
"Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
189 {L
"Flags", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
190 {L
"Reserved", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
191 {L
"VATOS Address", 8, 32, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
192 {L
"Model", 4, 40, L
"%d", NULL
, NULL
, NULL
, NULL
},
193 {L
"Event", 4, 44, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
194 {L
"PRI", 4, 48, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
195 {L
"GERR", 4, 52, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
196 {L
"Sync", 4, 56, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
197 {L
"Proximity domain", 4, 60, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
198 {L
"Device ID mapping index", 4, 64, L
"%d", NULL
, NULL
, NULL
, NULL
}
202 An ACPI_PARSER array describing the IORT ITS node.
204 STATIC CONST ACPI_PARSER IortNodeItsParser
[] = {
205 PARSE_IORT_NODE_HEADER (
206 ValidateItsIdMappingCount
,
207 ValidateItsIdArrayReference
209 {L
"Number of ITSs", 4, 16, L
"%d", NULL
, (VOID
**)&ItsCount
, NULL
}
213 An ACPI_PARSER array describing the ITS ID.
215 STATIC CONST ACPI_PARSER ItsIdParser
[] = {
216 { L
"GIC ITS Identifier", 4, 0, L
"%d", NULL
, NULL
, NULL
}
220 An ACPI_PARSER array describing the IORT Names Component node.
222 STATIC CONST ACPI_PARSER IortNodeNamedComponentParser
[] = {
223 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
224 {L
"Node Flags", 4, 16, L
"%d", NULL
, NULL
, NULL
, NULL
},
225 {L
"Memory access properties", 8, 20, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
226 {L
"Device memory address size limit", 1, 28, L
"%d", NULL
, NULL
, NULL
, NULL
}
230 An ACPI_PARSER array describing the IORT Root Complex node.
232 STATIC CONST ACPI_PARSER IortNodeRootComplexParser
[] = {
233 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
234 {L
"Memory access properties", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
235 {L
"ATS Attribute", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
236 {L
"PCI Segment number", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
237 {L
"Memory access size limit", 1, 32, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
238 {L
"Reserved", 3, 33, L
"%x %x %x", Dump3Chars
, NULL
, NULL
, NULL
}
242 An ACPI_PARSER array describing the IORT PMCG node.
244 STATIC CONST ACPI_PARSER IortNodePmcgParser
[] = {
245 PARSE_IORT_NODE_HEADER (ValidatePmcgIdMappingCount
, NULL
),
246 {L
"Page 0 Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
247 {L
"Overflow interrupt GSIV", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
248 {L
"Node reference", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
249 {L
"Page 1 Base Address", 8, 32, L
"0x%lx", NULL
, NULL
, NULL
, NULL
}
253 This function parses the IORT Node Id Mapping array.
255 @param [in] Ptr Pointer to the start of the ID mapping array.
256 @param [in] Length Length of the buffer.
257 @param [in] MappingCount The ID Mapping count.
261 DumpIortNodeIdMappings (
264 IN UINT32 MappingCount
269 CHAR8 Buffer
[40]; // Used for AsciiName param of ParseAcpi
274 while ((Index
< MappingCount
) &&
282 Offset
+= ParseAcpi (
288 PARSER_PARAMS (IortNodeIdMappingParser
)
295 This function parses the IORT SMMUv1/2 node.
297 @param [in] Ptr Pointer to the start of the buffer.
298 @param [in] Length Length of the buffer.
299 @param [in] MappingCount The ID Mapping count.
300 @param [in] MappingOffset The offset of the ID Mapping array
301 from the start of the IORT table.
305 DumpIortNodeSmmuV1V2 (
308 IN UINT32 MappingCount
,
309 IN UINT32 MappingOffset
314 CHAR8 Buffer
[50]; // Used for AsciiName param of ParseAcpi
319 "SMMUv1 or SMMUv2 Node",
322 PARSER_PARAMS (IortNodeSmmuV1V2Parser
)
325 // Check if the values used to control the parsing logic have been
326 // successfully read.
327 if ((InterruptContextCount
== NULL
) ||
328 (InterruptContextOffset
== NULL
) ||
329 (PmuInterruptCount
== NULL
) ||
330 (PmuInterruptOffset
== NULL
)) {
331 IncrementErrorCount ();
333 L
"ERROR: Insufficient SMMUv1/2 node length. Length = %d\n",
339 Offset
= *InterruptContextOffset
;
342 while ((Index
< *InterruptContextCount
) &&
347 "Context Interrupts Array [%d]",
350 Offset
+= ParseAcpi (
356 PARSER_PARAMS (InterruptArrayParser
)
361 Offset
= *PmuInterruptOffset
;
364 while ((Index
< *PmuInterruptCount
) &&
369 "PMU Interrupts Array [%d]",
372 Offset
+= ParseAcpi (
378 PARSER_PARAMS (InterruptArrayParser
)
383 DumpIortNodeIdMappings (
385 Length
- MappingOffset
,
391 This function parses the IORT SMMUv3 node.
393 @param [in] Ptr Pointer to the start of the buffer.
394 @param [in] Length Length of the buffer.
395 @param [in] MappingCount The ID Mapping count.
396 @param [in] MappingOffset The offset of the ID Mapping array
397 from the start of the IORT table.
404 IN UINT32 MappingCount
,
405 IN UINT32 MappingOffset
414 PARSER_PARAMS (IortNodeSmmuV3Parser
)
417 DumpIortNodeIdMappings (
419 Length
- MappingOffset
,
425 This function parses the IORT ITS node.
427 @param [in] Ptr Pointer to the start of the buffer.
428 @param [in] Length Length of the buffer.
439 CHAR8 Buffer
[80]; // Used for AsciiName param of ParseAcpi
447 PARSER_PARAMS (IortNodeItsParser
)
450 // Check if the values used to control the parsing logic have been
451 // successfully read.
452 if (ItsCount
== NULL
) {
453 IncrementErrorCount ();
455 L
"ERROR: Insufficient ITS group length. Length = %d.\n",
463 while ((Index
< *ItsCount
) &&
468 "GIC ITS Identifier Array [%d]",
471 Offset
+= ParseAcpi (
477 PARSER_PARAMS (ItsIdParser
)
482 // Note: ITS does not have the ID Mappings Array
487 This function parses the IORT Named Component node.
489 @param [in] Ptr Pointer to the start of the buffer.
490 @param [in] Length Length of the buffer.
491 @param [in] MappingCount The ID Mapping count.
492 @param [in] MappingOffset The offset of the ID Mapping array
493 from the start of the IORT table.
497 DumpIortNodeNamedComponent (
500 IN UINT32 MappingCount
,
501 IN UINT32 MappingOffset
509 "Named Component Node",
512 PARSER_PARAMS (IortNodeNamedComponentParser
)
515 // Estimate the Device Name length
516 PrintFieldName (2, L
"Device Object Name");
518 while ((*(Ptr
+ Offset
) != 0) &&
520 Print (L
"%c", *(Ptr
+ Offset
));
525 DumpIortNodeIdMappings (
527 Length
- MappingOffset
,
533 This function parses the IORT Root Complex node.
535 @param [in] Ptr Pointer to the start of the buffer.
536 @param [in] Length Length of the buffer.
537 @param [in] MappingCount The ID Mapping count.
538 @param [in] MappingOffset The offset of the ID Mapping array
539 from the start of the IORT table.
543 DumpIortNodeRootComplex (
546 IN UINT32 MappingCount
,
547 IN UINT32 MappingOffset
556 PARSER_PARAMS (IortNodeRootComplexParser
)
559 DumpIortNodeIdMappings (
561 Length
- MappingOffset
,
567 This function parses the IORT PMCG node.
569 @param [in] Ptr Pointer to the start of the buffer.
570 @param [in] Length Length of the buffer.
571 @param [in] MappingCount The ID Mapping count.
572 @param [in] MappingOffset The offset of the ID Mapping array
573 from the start of the IORT table.
580 IN UINT32 MappingCount
,
581 IN UINT32 MappingOffset
590 PARSER_PARAMS (IortNodePmcgParser
)
593 DumpIortNodeIdMappings (
595 Length
- MappingOffset
,
601 This function parses the ACPI IORT table.
602 When trace is enabled this function parses the IORT table and traces the ACPI fields.
604 This function also parses the following nodes:
612 This function also performs validation of the ACPI table fields.
614 @param [in] Trace If TRUE, trace the ACPI fields.
615 @param [in] Ptr Pointer to the start of the buffer.
616 @param [in] AcpiTableLength Length of the ACPI table.
617 @param [in] AcpiTableRevision Revision of the ACPI table.
624 IN UINT32 AcpiTableLength
,
625 IN UINT8 AcpiTableRevision
642 PARSER_PARAMS (IortParser
)
645 // Check if the values used to control the parsing logic have been
646 // successfully read.
647 if ((IortNodeCount
== NULL
) ||
648 (IortNodeOffset
== NULL
)) {
649 IncrementErrorCount ();
651 L
"ERROR: Insufficient table length. AcpiTableLength = %d.\n",
657 Offset
= *IortNodeOffset
;
658 NodePtr
= Ptr
+ Offset
;
661 // Parse the specified number of IORT nodes or the IORT table buffer length.
662 // Whichever is minimum.
663 while ((Index
++ < *IortNodeCount
) &&
664 (Offset
< AcpiTableLength
)) {
665 // Parse the IORT Node Header
671 AcpiTableLength
- Offset
,
672 PARSER_PARAMS (IortNodeHeaderParser
)
675 // Check if the values used to control the parsing logic have been
676 // successfully read.
677 if ((IortNodeType
== NULL
) ||
678 (IortNodeLength
== NULL
) ||
679 (IortIdMappingCount
== NULL
) ||
680 (IortIdMappingOffset
== NULL
)) {
681 IncrementErrorCount ();
683 L
"ERROR: Insufficient remaining table buffer length to read the " \
684 L
"IORT node header. Length = %d.\n",
685 AcpiTableLength
- Offset
690 // Validate IORT Node length
691 if ((*IortNodeLength
== 0) ||
692 ((Offset
+ (*IortNodeLength
)) > AcpiTableLength
)) {
693 IncrementErrorCount ();
695 L
"ERROR: Invalid IORT Node length. " \
696 L
"Length = %d. Offset = %d. AcpiTableLength = %d.\n",
704 PrintFieldName (2, L
"* Node Offset *");
705 Print (L
"0x%x\n", Offset
);
707 switch (*IortNodeType
) {
708 case EFI_ACPI_IORT_TYPE_ITS_GROUP
:
714 case EFI_ACPI_IORT_TYPE_NAMED_COMP
:
715 DumpIortNodeNamedComponent (
722 case EFI_ACPI_IORT_TYPE_ROOT_COMPLEX
:
723 DumpIortNodeRootComplex (
730 case EFI_ACPI_IORT_TYPE_SMMUv1v2
:
731 DumpIortNodeSmmuV1V2 (
738 case EFI_ACPI_IORT_TYPE_SMMUv3
:
746 case EFI_ACPI_IORT_TYPE_PMCG
:
756 IncrementErrorCount ();
757 Print (L
"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType
);
760 NodePtr
+= (*IortNodeLength
);
761 Offset
+= (*IortNodeLength
);