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"
16 #include "AcpiViewConfig.h"
19 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo
;
21 STATIC CONST UINT32
* IortNodeCount
;
22 STATIC CONST UINT32
* IortNodeOffset
;
24 STATIC CONST UINT8
* IortNodeType
;
25 STATIC CONST UINT16
* IortNodeLength
;
26 STATIC CONST UINT32
* IortIdMappingCount
;
27 STATIC CONST UINT32
* IortIdMappingOffset
;
29 STATIC CONST UINT32
* InterruptContextCount
;
30 STATIC CONST UINT32
* InterruptContextOffset
;
31 STATIC CONST UINT32
* PmuInterruptCount
;
32 STATIC CONST UINT32
* PmuInterruptOffset
;
34 STATIC CONST UINT32
* ItsCount
;
37 This function validates the ID Mapping array count for the ITS node.
39 @param [in] Ptr Pointer to the start of the field data.
40 @param [in] Context Pointer to context specific information e.g. this
41 could be a pointer to the ACPI table header.
46 ValidateItsIdMappingCount (
51 if (*(UINT32
*)Ptr
!= 0) {
52 IncrementErrorCount ();
53 Print (L
"\nERROR: IORT ID Mapping count must be zero.");
58 This function validates the ID Mapping array count for the Performance
59 Monitoring Counter Group (PMCG) node.
61 @param [in] Ptr Pointer to the start of the field data.
62 @param [in] Context Pointer to context specific information e.g. this
63 could be a pointer to the ACPI table header.
68 ValidatePmcgIdMappingCount (
73 if (*(UINT32
*)Ptr
> 1) {
74 IncrementErrorCount ();
75 Print (L
"\nERROR: IORT ID Mapping count must not be greater than 1.");
80 This function validates the ID Mapping array offset for the ITS node.
82 @param [in] Ptr Pointer to the start of the field data.
83 @param [in] Context Pointer to context specific information e.g. this
84 could be a pointer to the ACPI table header.
89 ValidateItsIdArrayReference (
94 if (*(UINT32
*)Ptr
!= 0) {
95 IncrementErrorCount ();
96 Print (L
"\nERROR: IORT ID Mapping offset must be zero.");
101 Helper Macro for populating the IORT Node header in the ACPI_PARSER array.
103 @param [out] ValidateIdMappingCount Optional pointer to a function for
104 validating the ID Mapping count.
105 @param [out] ValidateIdArrayReference Optional pointer to a function for
106 validating the ID Array reference.
108 #define PARSE_IORT_NODE_HEADER(ValidateIdMappingCount, \
109 ValidateIdArrayReference) \
110 { L"Type", 1, 0, L"%d", NULL, (VOID**)&IortNodeType, NULL, NULL }, \
111 { L"Length", 2, 1, L"%d", NULL, (VOID**)&IortNodeLength, NULL, NULL }, \
112 { L"Revision", 1, 3, L"%d", NULL, NULL, NULL, NULL }, \
113 { L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, \
114 { L"Number of ID mappings", 4, 8, L"%d", NULL, \
115 (VOID**)&IortIdMappingCount, ValidateIdMappingCount, NULL }, \
116 { L"Reference to ID Array", 4, 12, L"0x%x", NULL, \
117 (VOID**)&IortIdMappingOffset, ValidateIdArrayReference, NULL }
120 An ACPI_PARSER array describing the ACPI IORT Table
122 STATIC CONST ACPI_PARSER IortParser
[] = {
123 PARSE_ACPI_HEADER (&AcpiHdrInfo
),
124 {L
"Number of IORT Nodes", 4, 36, L
"%d", NULL
,
125 (VOID
**)&IortNodeCount
, NULL
, NULL
},
126 {L
"Offset to Array of IORT Nodes", 4, 40, L
"0x%x", NULL
,
127 (VOID
**)&IortNodeOffset
, NULL
, NULL
},
128 {L
"Reserved", 4, 44, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
132 An ACPI_PARSER array describing the IORT node header structure.
134 STATIC CONST ACPI_PARSER IortNodeHeaderParser
[] = {
135 PARSE_IORT_NODE_HEADER (NULL
, NULL
)
139 An ACPI_PARSER array describing the IORT SMMUv1/2 node.
141 STATIC CONST ACPI_PARSER IortNodeSmmuV1V2Parser
[] = {
142 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
143 {L
"Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
144 {L
"Span", 8, 24, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
145 {L
"Model", 4, 32, L
"%d", NULL
, NULL
, NULL
, NULL
},
146 {L
"Flags", 4, 36, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
147 {L
"Reference to Global Interrupt Array", 4, 40, L
"0x%x", NULL
, NULL
, NULL
,
149 {L
"Number of context interrupts", 4, 44, L
"%d", NULL
,
150 (VOID
**)&InterruptContextCount
, NULL
, NULL
},
151 {L
"Reference to Context Interrupt Array", 4, 48, L
"0x%x", NULL
,
152 (VOID
**)&InterruptContextOffset
, NULL
, NULL
},
153 {L
"Number of PMU Interrupts", 4, 52, L
"%d", NULL
,
154 (VOID
**)&PmuInterruptCount
, NULL
, NULL
},
155 {L
"Reference to PMU Interrupt Array", 4, 56, L
"0x%x", NULL
,
156 (VOID
**)&PmuInterruptOffset
, NULL
, NULL
},
159 {L
"SMMU_NSgIrpt", 4, 60, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
160 {L
"SMMU_NSgIrpt interrupt flags", 4, 64, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
161 {L
"SMMU_NSgCfgIrpt", 4, 68, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
162 {L
"SMMU_NSgCfgIrpt interrupt flags", 4, 72, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
166 An ACPI_PARSER array describing the SMMUv1/2 Node Interrupt Array.
168 STATIC CONST ACPI_PARSER InterruptArrayParser
[] = {
169 {L
"Interrupt GSIV", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
170 {L
"Flags", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
174 An ACPI_PARSER array describing the IORT ID Mapping.
176 STATIC CONST ACPI_PARSER IortNodeIdMappingParser
[] = {
177 {L
"Input base", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
178 {L
"Number of IDs", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
179 {L
"Output base", 4, 8, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
180 {L
"Output reference", 4, 12, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
181 {L
"Flags", 4, 16, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
185 An ACPI_PARSER array describing the IORT SMMUv3 node.
187 STATIC CONST ACPI_PARSER IortNodeSmmuV3Parser
[] = {
188 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
189 {L
"Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
190 {L
"Flags", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
191 {L
"Reserved", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
192 {L
"VATOS Address", 8, 32, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
193 {L
"Model", 4, 40, L
"%d", NULL
, NULL
, NULL
, NULL
},
194 {L
"Event", 4, 44, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
195 {L
"PRI", 4, 48, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
196 {L
"GERR", 4, 52, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
197 {L
"Sync", 4, 56, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
198 {L
"Proximity domain", 4, 60, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
199 {L
"Device ID mapping index", 4, 64, L
"%d", NULL
, NULL
, NULL
, NULL
}
203 An ACPI_PARSER array describing the IORT ITS node.
205 STATIC CONST ACPI_PARSER IortNodeItsParser
[] = {
206 PARSE_IORT_NODE_HEADER (
207 ValidateItsIdMappingCount
,
208 ValidateItsIdArrayReference
210 {L
"Number of ITSs", 4, 16, L
"%d", NULL
, (VOID
**)&ItsCount
, NULL
}
214 An ACPI_PARSER array describing the ITS ID.
216 STATIC CONST ACPI_PARSER ItsIdParser
[] = {
217 { L
"GIC ITS Identifier", 4, 0, L
"%d", NULL
, NULL
, NULL
}
221 An ACPI_PARSER array describing the IORT Names Component node.
223 STATIC CONST ACPI_PARSER IortNodeNamedComponentParser
[] = {
224 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
225 {L
"Node Flags", 4, 16, L
"%d", NULL
, NULL
, NULL
, NULL
},
226 {L
"Memory access properties", 8, 20, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
227 {L
"Device memory address size limit", 1, 28, L
"%d", NULL
, NULL
, NULL
, NULL
}
231 An ACPI_PARSER array describing the IORT Root Complex node.
233 STATIC CONST ACPI_PARSER IortNodeRootComplexParser
[] = {
234 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
235 {L
"Memory access properties", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
236 {L
"ATS Attribute", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
237 {L
"PCI Segment number", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
238 {L
"Memory access size limit", 1, 32, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
239 {L
"Reserved", 3, 33, L
"%x %x %x", Dump3Chars
, NULL
, NULL
, NULL
}
243 An ACPI_PARSER array describing the IORT PMCG node.
245 STATIC CONST ACPI_PARSER IortNodePmcgParser
[] = {
246 PARSE_IORT_NODE_HEADER (ValidatePmcgIdMappingCount
, NULL
),
247 {L
"Page 0 Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
248 {L
"Overflow interrupt GSIV", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
249 {L
"Node reference", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
250 {L
"Page 1 Base Address", 8, 32, L
"0x%lx", NULL
, NULL
, NULL
, NULL
}
254 This function parses the IORT Node Id Mapping array.
256 @param [in] Ptr Pointer to the start of the ID mapping array.
257 @param [in] Length Length of the buffer.
258 @param [in] MappingCount The ID Mapping count.
262 DumpIortNodeIdMappings (
265 IN UINT32 MappingCount
270 CHAR8 Buffer
[40]; // Used for AsciiName param of ParseAcpi
275 while ((Index
< MappingCount
) &&
283 Offset
+= ParseAcpi (
289 PARSER_PARAMS (IortNodeIdMappingParser
)
296 This function parses the IORT SMMUv1/2 node.
298 @param [in] Ptr Pointer to the start of the buffer.
299 @param [in] Length Length of the buffer.
300 @param [in] MappingCount The ID Mapping count.
301 @param [in] MappingOffset The offset of the ID Mapping array
302 from the start of the IORT table.
306 DumpIortNodeSmmuV1V2 (
309 IN UINT32 MappingCount
,
310 IN UINT32 MappingOffset
315 CHAR8 Buffer
[50]; // Used for AsciiName param of ParseAcpi
320 "SMMUv1 or SMMUv2 Node",
323 PARSER_PARAMS (IortNodeSmmuV1V2Parser
)
326 // Check if the values used to control the parsing logic have been
327 // successfully read.
328 if ((InterruptContextCount
== NULL
) ||
329 (InterruptContextOffset
== NULL
) ||
330 (PmuInterruptCount
== NULL
) ||
331 (PmuInterruptOffset
== NULL
)) {
332 IncrementErrorCount ();
334 L
"ERROR: Insufficient SMMUv1/2 node length. Length = %d\n",
340 Offset
= *InterruptContextOffset
;
343 while ((Index
< *InterruptContextCount
) &&
348 "Context Interrupts Array [%d]",
351 Offset
+= ParseAcpi (
357 PARSER_PARAMS (InterruptArrayParser
)
362 Offset
= *PmuInterruptOffset
;
365 while ((Index
< *PmuInterruptCount
) &&
370 "PMU Interrupts Array [%d]",
373 Offset
+= ParseAcpi (
379 PARSER_PARAMS (InterruptArrayParser
)
384 DumpIortNodeIdMappings (
386 Length
- MappingOffset
,
392 This function parses the IORT SMMUv3 node.
394 @param [in] Ptr Pointer to the start of the buffer.
395 @param [in] Length Length of the buffer.
396 @param [in] MappingCount The ID Mapping count.
397 @param [in] MappingOffset The offset of the ID Mapping array
398 from the start of the IORT table.
405 IN UINT32 MappingCount
,
406 IN UINT32 MappingOffset
415 PARSER_PARAMS (IortNodeSmmuV3Parser
)
418 DumpIortNodeIdMappings (
420 Length
- MappingOffset
,
426 This function parses the IORT ITS node.
428 @param [in] Ptr Pointer to the start of the buffer.
429 @param [in] Length Length of the buffer.
440 CHAR8 Buffer
[80]; // Used for AsciiName param of ParseAcpi
448 PARSER_PARAMS (IortNodeItsParser
)
451 // Check if the values used to control the parsing logic have been
452 // successfully read.
453 if (ItsCount
== NULL
) {
454 IncrementErrorCount ();
456 L
"ERROR: Insufficient ITS group length. Length = %d.\n",
464 while ((Index
< *ItsCount
) &&
469 "GIC ITS Identifier Array [%d]",
472 Offset
+= ParseAcpi (
478 PARSER_PARAMS (ItsIdParser
)
483 // Note: ITS does not have the ID Mappings Array
488 This function parses the IORT Named Component node.
490 @param [in] Ptr Pointer to the start of the buffer.
491 @param [in] Length Length of the buffer.
492 @param [in] MappingCount The ID Mapping count.
493 @param [in] MappingOffset The offset of the ID Mapping array
494 from the start of the IORT table.
498 DumpIortNodeNamedComponent (
501 IN UINT32 MappingCount
,
502 IN UINT32 MappingOffset
510 "Named Component Node",
513 PARSER_PARAMS (IortNodeNamedComponentParser
)
516 // Estimate the Device Name length
517 PrintFieldName (2, L
"Device Object Name");
519 while ((*(Ptr
+ Offset
) != 0) &&
521 Print (L
"%c", *(Ptr
+ Offset
));
526 DumpIortNodeIdMappings (
528 Length
- MappingOffset
,
534 This function parses the IORT Root Complex node.
536 @param [in] Ptr Pointer to the start of the buffer.
537 @param [in] Length Length of the buffer.
538 @param [in] MappingCount The ID Mapping count.
539 @param [in] MappingOffset The offset of the ID Mapping array
540 from the start of the IORT table.
544 DumpIortNodeRootComplex (
547 IN UINT32 MappingCount
,
548 IN UINT32 MappingOffset
557 PARSER_PARAMS (IortNodeRootComplexParser
)
560 DumpIortNodeIdMappings (
562 Length
- MappingOffset
,
568 This function parses the IORT PMCG node.
570 @param [in] Ptr Pointer to the start of the buffer.
571 @param [in] Length Length of the buffer.
572 @param [in] MappingCount The ID Mapping count.
573 @param [in] MappingOffset The offset of the ID Mapping array
574 from the start of the IORT table.
581 IN UINT32 MappingCount
,
582 IN UINT32 MappingOffset
591 PARSER_PARAMS (IortNodePmcgParser
)
594 DumpIortNodeIdMappings (
596 Length
- MappingOffset
,
602 This function parses the ACPI IORT table.
603 When trace is enabled this function parses the IORT table and traces the ACPI fields.
605 This function also parses the following nodes:
613 This function also performs validation of the ACPI table fields.
615 @param [in] Trace If TRUE, trace the ACPI fields.
616 @param [in] Ptr Pointer to the start of the buffer.
617 @param [in] AcpiTableLength Length of the ACPI table.
618 @param [in] AcpiTableRevision Revision of the ACPI table.
625 IN UINT32 AcpiTableLength
,
626 IN UINT8 AcpiTableRevision
643 PARSER_PARAMS (IortParser
)
646 // Check if the values used to control the parsing logic have been
647 // successfully read.
648 if ((IortNodeCount
== NULL
) ||
649 (IortNodeOffset
== NULL
)) {
650 IncrementErrorCount ();
652 L
"ERROR: Insufficient table length. AcpiTableLength = %d.\n",
658 Offset
= *IortNodeOffset
;
659 NodePtr
= Ptr
+ Offset
;
662 // Parse the specified number of IORT nodes or the IORT table buffer length.
663 // Whichever is minimum.
664 while ((Index
++ < *IortNodeCount
) &&
665 (Offset
< AcpiTableLength
)) {
666 // Parse the IORT Node Header
672 AcpiTableLength
- Offset
,
673 PARSER_PARAMS (IortNodeHeaderParser
)
676 // Check if the values used to control the parsing logic have been
677 // successfully read.
678 if ((IortNodeType
== NULL
) ||
679 (IortNodeLength
== NULL
) ||
680 (IortIdMappingCount
== NULL
) ||
681 (IortIdMappingOffset
== NULL
)) {
682 IncrementErrorCount ();
684 L
"ERROR: Insufficient remaining table buffer length to read the " \
685 L
"IORT node header. Length = %d.\n",
686 AcpiTableLength
- Offset
691 // Validate IORT Node length
692 if ((*IortNodeLength
== 0) ||
693 ((Offset
+ (*IortNodeLength
)) > AcpiTableLength
)) {
694 IncrementErrorCount ();
696 L
"ERROR: Invalid IORT Node length. " \
697 L
"Length = %d. Offset = %d. AcpiTableLength = %d.\n",
705 PrintFieldName (2, L
"* Node Offset *");
706 Print (L
"0x%x\n", Offset
);
708 switch (*IortNodeType
) {
709 case EFI_ACPI_IORT_TYPE_ITS_GROUP
:
715 case EFI_ACPI_IORT_TYPE_NAMED_COMP
:
716 DumpIortNodeNamedComponent (
723 case EFI_ACPI_IORT_TYPE_ROOT_COMPLEX
:
724 DumpIortNodeRootComplex (
731 case EFI_ACPI_IORT_TYPE_SMMUv1v2
:
732 DumpIortNodeSmmuV1V2 (
739 case EFI_ACPI_IORT_TYPE_SMMUv3
:
747 case EFI_ACPI_IORT_TYPE_PMCG
:
757 IncrementErrorCount ();
758 Print (L
"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType
);
761 NodePtr
+= (*IortNodeLength
);
762 Offset
+= (*IortNodeLength
);