4 Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 - IO Remapping Table, Platform Design Document, Revision C, 15 May 2017
17 #include <IndustryStandard/IoRemappingTable.h>
18 #include <Library/PrintLib.h>
19 #include <Library/UefiLib.h>
20 #include "AcpiParser.h"
21 #include "AcpiTableParser.h"
24 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo
;
26 /** The EIORT_NODE enum describes the IORT Node types.
28 typedef enum IortNode
{
29 EIORT_NODE_ITS_GROUP
, ///< ITS Group node
30 EIORT_NODE_NAMED_COMPONENT
, ///< Named Component node
31 EIORT_NODE_ROOT_COMPLEX
, ///< Root Complex node
32 EIORT_NODE_SMMUV1_V2
, ///< SMMU v1/v2 node
33 EIORT_NODE_SMMUV3
, ///< SMMU v3 node
34 EIORT_NODE_PMCG
, ///< PMC group node
39 STATIC CONST UINT32
* IortNodeCount
;
40 STATIC CONST UINT32
* IortNodeOffset
;
42 STATIC CONST UINT8
* IortNodeType
;
43 STATIC CONST UINT16
* IortNodeLength
;
44 STATIC CONST UINT32
* IortIdMappingCount
;
45 STATIC CONST UINT32
* IortIdMappingOffset
;
47 STATIC CONST UINT32
* InterruptContextCount
;
48 STATIC CONST UINT32
* InterruptContextOffset
;
49 STATIC CONST UINT32
* PmuInterruptCount
;
50 STATIC CONST UINT32
* PmuInterruptOffset
;
52 STATIC CONST UINT32
* ItsCount
;
54 /** This function validates the ID Mapping array count for the ITS node.
56 @param [in] Ptr Pointer to the start of the field data.
57 @param [in] Context Pointer to context specific information e.g. this
58 could be a pointer to the ACPI table header.
63 ValidateItsIdMappingCount (
68 /** This function validates the ID Mapping array offset for the ITS node.
70 @param [in] Ptr Pointer to the start of the field data.
71 @param [in] Context Pointer to context specific information e.g. this
72 could be a pointer to the ACPI table header.
77 ValidateItsIdArrayReference (
82 /** Helper Macro for populating the IORT Node header in the ACPI_PARSER
85 @param [out] ValidateIdMappingCount Optional pointer to a function for
86 validating the ID Mapping count.
87 @param [out] ValidateIdArrayReference Optional pointer to a function for
88 validating the ID Array reference.
90 #define PARSE_IORT_NODE_HEADER(ValidateIdMappingCount, \
91 ValidateIdArrayReference) \
92 { L"Type", 1, 0, L"%d", NULL, (VOID**)&IortNodeType, NULL, NULL }, \
93 { L"Length", 2, 1, L"%d", NULL, (VOID**)&IortNodeLength, NULL, NULL }, \
94 { L"Revision", 1, 3, L"%d", NULL, NULL, NULL, NULL }, \
95 { L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, \
96 { L"Number of ID mappings", 4, 8, L"%d", NULL, \
97 (VOID**)&IortIdMappingCount, ValidateIdMappingCount, NULL }, \
98 { L"Reference to ID Array", 4, 12, L"0x%x", NULL, \
99 (VOID**)&IortIdMappingOffset, ValidateIdArrayReference, NULL }
101 /** An ACPI_PARSER array describing the ACPI IORT Table
103 STATIC CONST ACPI_PARSER IortParser
[] = {
104 PARSE_ACPI_HEADER (&AcpiHdrInfo
),
105 {L
"Number of IORT Nodes", 4, 36, L
"%d", NULL
,
106 (VOID
**)&IortNodeCount
, NULL
, NULL
},
107 {L
"Offset to Array of IORT Nodes", 4, 40, L
"0x%x", NULL
,
108 (VOID
**)&IortNodeOffset
, NULL
, NULL
},
109 {L
"Reserved", 4, 44, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
112 /** An ACPI_PARSER array describing the IORT node header structure.
114 STATIC CONST ACPI_PARSER IortNodeHeaderParser
[] = {
115 PARSE_IORT_NODE_HEADER (NULL
, NULL
)
118 /** An ACPI_PARSER array describing the IORT SMMUv1/2 node.
120 STATIC CONST ACPI_PARSER IortNodeSmmuV1V2Parser
[] = {
121 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
122 {L
"Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
123 {L
"Span", 8, 24, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
124 {L
"Model", 4, 32, L
"%d", NULL
, NULL
, NULL
, NULL
},
125 {L
"Flags", 4, 36, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
126 {L
"Reference to Global Interrupt Array", 4, 40, L
"0x%x", NULL
, NULL
, NULL
,
128 {L
"Number of context interrupts", 4, 44, L
"%d", NULL
,
129 (VOID
**)&InterruptContextCount
, NULL
, NULL
},
130 {L
"Reference to Context Interrupt Array", 4, 48, L
"0x%x", NULL
,
131 (VOID
**)&InterruptContextOffset
, NULL
, NULL
},
132 {L
"Number of PMU Interrupts", 4, 52, L
"%d", NULL
,
133 (VOID
**)&PmuInterruptCount
, NULL
, NULL
},
134 {L
"Reference to PMU Interrupt Array", 4, 56, L
"0x%x", NULL
,
135 (VOID
**)&PmuInterruptOffset
, NULL
, NULL
},
138 {L
"SMMU_NSgIrpt", 4, 60, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
139 {L
"SMMU_NSgIrpt interrupt flags", 4, 64, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
140 {L
"SMMU_NSgCfgIrpt", 4, 68, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
141 {L
"SMMU_NSgCfgIrpt interrupt flags", 4, 72, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
144 /** An ACPI_PARSER array describing the SMMUv1/2 Node Interrupt Array.
146 STATIC CONST ACPI_PARSER InterruptArrayParser
[] = {
147 {L
" Interrupt GSIV", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
148 {L
" Flags", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
151 /** An ACPI_PARSER array describing the IORT ID Mapping.
153 STATIC CONST ACPI_PARSER IortNodeIdMappingParser
[] = {
154 {L
" Input base", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
155 {L
" Number of IDs", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
156 {L
" Output base", 4, 8, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
157 {L
" Output reference", 4, 12, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
158 {L
" Flags", 4, 16, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
161 /** An ACPI_PARSER array describing the IORT SMMUv3 node.
163 STATIC CONST ACPI_PARSER IortNodeSmmuV3Parser
[] = {
164 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
165 {L
"Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
166 {L
"Flags", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
167 {L
"Reserved", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
168 {L
"VATOS Address", 8, 32, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
169 {L
"Model", 4, 40, L
"%d", NULL
, NULL
, NULL
, NULL
},
170 {L
"Event", 4, 44, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
171 {L
"PRI", 4, 48, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
172 {L
"GERR", 4, 52, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
173 {L
"Sync", 4, 56, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
176 /** An ACPI_PARSER array describing the IORT ITS node.
178 STATIC CONST ACPI_PARSER IortNodeItsParser
[] = {
179 PARSE_IORT_NODE_HEADER (
180 ValidateItsIdMappingCount
,
181 ValidateItsIdArrayReference
183 {L
" Number of ITSs", 4, 16, L
"%d", NULL
, (VOID
**)&ItsCount
, NULL
}
186 /** An ACPI_PARSER array describing the ITS ID.
188 STATIC CONST ACPI_PARSER ItsIdParser
[] = {
189 { L
" GIC ITS Identifier", 4, 0, L
"%d", NULL
, NULL
, NULL
}
192 /** An ACPI_PARSER array describing the IORT Names Component node.
194 STATIC CONST ACPI_PARSER IortNodeNamedComponentParser
[] = {
195 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
196 {L
"Node Flags", 4, 16, L
"%d", NULL
, NULL
, NULL
, NULL
},
197 {L
"Memory access properties", 8, 20, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
198 {L
"Device memory address size limit", 1, 28, L
"%d", NULL
, NULL
, NULL
, NULL
}
201 /** An ACPI_PARSER array describing the IORT Root Complex node.
203 STATIC CONST ACPI_PARSER IortNodeRootComplexParser
[] = {
204 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
205 {L
"Memory access properties", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
206 {L
"ATS Attribute", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
207 {L
"PCI Segment number", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
210 /** An ACPI_PARSER array describing the IORT PMCG node.
212 STATIC CONST ACPI_PARSER IortNodePmcgParser
[] = {
213 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
214 {L
"Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
215 {L
"Overflow interrupt GSIV", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
216 {L
"Node reference", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
219 /** This function validates the ID Mapping array count for the ITS node.
221 @param [in] Ptr Pointer to the start of the field data.
222 @param [in] Context Pointer to context specific information e.g. this
223 could be a pointer to the ACPI table header.
228 ValidateItsIdMappingCount (
233 if (*(UINT32
*)Ptr
!= 0) {
234 IncrementErrorCount ();
235 Print (L
"\nERROR: IORT ID Mapping count must be zero.");
239 /** This function validates the ID Mapping array offset for the ITS node.
241 @param [in] Ptr Pointer to the start of the field data.
242 @param [in] Context Pointer to context specific information e.g. this
243 could be a pointer to the ACPI table header.
248 ValidateItsIdArrayReference (
253 if (*(UINT32
*)Ptr
!= 0) {
254 IncrementErrorCount ();
255 Print (L
"\nERROR: IORT ID Mapping offset must be zero.");
259 /** This function parses the IORT Node Id Mapping array.
261 @param [in] Ptr Pointer to the start of the IORT Table.
262 @param [in] MappingCount The ID Mapping count.
263 @param [in] MappingOffset The offset of the ID Mapping array
264 from the start of the IORT table.
268 DumpIortNodeIdMappings (
270 IN UINT32 MappingCount
,
271 IN UINT32 MappingOffset
277 CHAR8 Buffer
[40]; // Used for AsciiName param of ParseAcpi
279 IdMappingPtr
= Ptr
+ MappingOffset
;
281 while (Index
< MappingCount
) {
294 PARSER_PARAMS (IortNodeIdMappingParser
)
296 IdMappingPtr
+= Offset
;
301 /** This function parses the IORT SMMUv1/2 node.
303 @param [in] Ptr Pointer to the start of the buffer.
304 @param [in] Length Length of the buffer.
305 @param [in] MappingCount The ID Mapping count.
306 @param [in] MappingOffset The offset of the ID Mapping array
307 from the start of the IORT table.
311 DumpIortNodeSmmuV1V2 (
314 IN UINT32 MappingCount
,
315 IN UINT32 MappingOffset
320 CHAR8 Buffer
[50]; // Used for AsciiName param of ParseAcpi
327 "SMMUv1 or SMMUv2 Node",
330 PARSER_PARAMS (IortNodeSmmuV1V2Parser
)
333 ArrayPtr
= Ptr
+ *InterruptContextOffset
;
335 while (Index
< *InterruptContextCount
) {
339 "Context Interrupts Array [%d]",
348 PARSER_PARAMS (InterruptArrayParser
)
354 ArrayPtr
= Ptr
+ *PmuInterruptOffset
;
356 while (Index
< *PmuInterruptCount
) {
360 "PMU Interrupts Array [%d]",
369 PARSER_PARAMS (InterruptArrayParser
)
375 if (*IortIdMappingCount
!= 0) {
376 DumpIortNodeIdMappings (Ptr
, MappingCount
, MappingOffset
);
380 /** This function parses the IORT SMMUv3 node.
382 @param [in] Ptr Pointer to the start of the buffer.
383 @param [in] Length Length of the buffer.
384 @param [in] MappingCount The ID Mapping count.
385 @param [in] MappingOffset The offset of the ID Mapping array
386 from the start of the IORT table.
393 IN UINT32 MappingCount
,
394 IN UINT32 MappingOffset
403 PARSER_PARAMS (IortNodeSmmuV3Parser
)
406 if (*IortIdMappingCount
!= 0) {
407 DumpIortNodeIdMappings (Ptr
, MappingCount
, MappingOffset
);
411 /** This function parses the IORT ITS node.
413 @param [in] Ptr Pointer to the start of the buffer.
414 @param [in] Length Length of the buffer.
426 CHAR8 Buffer
[80]; // Used for AsciiName param of ParseAcpi
434 PARSER_PARAMS (IortNodeItsParser
)
437 ItsIdPtr
= Ptr
+ Offset
;
439 while (Index
< *ItsCount
) {
443 "GIC ITS Identifier Array [%d]",
452 PARSER_PARAMS (ItsIdParser
)
458 // Note: ITS does not have the ID Mappings Array
461 /** This function parses the IORT Named Component node.
463 @param [in] Ptr Pointer to the start of the buffer.
464 @param [in] Length Length of the buffer.
465 @param [in] MappingCount The ID Mapping count.
466 @param [in] MappingOffset The offset of the ID Mapping array
467 from the start of the IORT table.
471 DumpIortNodeNamedComponent (
474 IN UINT32 MappingCount
,
475 IN UINT32 MappingOffset
480 UINT8
* DeviceNamePtr
;
481 UINT32 DeviceNameLength
;
486 "Named Component Node",
489 PARSER_PARAMS (IortNodeNamedComponentParser
)
492 DeviceNamePtr
= Ptr
+ Offset
;
493 // Estimate the Device Name length
494 DeviceNameLength
= Length
- Offset
- (MappingCount
* 20);
495 PrintFieldName (2, L
"Device Object Name");
497 while ((Index
< DeviceNameLength
) && (DeviceNamePtr
[Index
] != 0)) {
498 Print (L
"%c", DeviceNamePtr
[Index
++]);
502 if (*IortIdMappingCount
!= 0) {
503 DumpIortNodeIdMappings (Ptr
, MappingCount
, MappingOffset
);
507 /** This function parses the IORT Root Complex node.
509 @param [in] Ptr Pointer to the start of the buffer.
510 @param [in] Length Length of the buffer.
511 @param [in] MappingCount The ID Mapping count.
512 @param [in] MappingOffset The offset of the ID Mapping array
513 from the start of the IORT table.
517 DumpIortNodeRootComplex (
520 IN UINT32 MappingCount
,
521 IN UINT32 MappingOffset
530 PARSER_PARAMS (IortNodeRootComplexParser
)
533 if (*IortIdMappingCount
!= 0) {
534 DumpIortNodeIdMappings (Ptr
, MappingCount
, MappingOffset
);
538 /** This function parses the IORT PMCG node.
540 @param [in] Ptr Pointer to the start of the buffer.
541 @param [in] Length Length of the buffer.
542 @param [in] MappingCount The ID Mapping count.
543 @param [in] MappingOffset The offset of the ID Mapping array
544 from the start of the IORT table.
551 IN UINT32 MappingCount
,
552 IN UINT32 MappingOffset
561 PARSER_PARAMS (IortNodePmcgParser
)
564 if (*IortIdMappingCount
!= 0) {
565 DumpIortNodeIdMappings (Ptr
, MappingCount
, MappingOffset
);
568 if (*IortIdMappingCount
> 1) {
569 IncrementErrorCount ();
571 L
"ERROR: ID mapping must not be greater than 1. Id Mapping Count =%d\n",
577 /** This function parses the ACPI IORT table.
578 When trace is enabled this function parses the IORT table and
579 traces the ACPI fields.
581 This function also parses the following nodes:
589 This function also performs validation of the ACPI table fields.
591 @param [in] Trace If TRUE, trace the ACPI fields.
592 @param [in] Ptr Pointer to the start of the buffer.
593 @param [in] AcpiTableLength Length of the ACPI table.
594 @param [in] AcpiTableRevision Revision of the ACPI table.
601 IN UINT32 AcpiTableLength
,
602 IN UINT8 AcpiTableRevision
619 PARSER_PARAMS (IortParser
)
621 Offset
= *IortNodeOffset
;
622 NodePtr
= Ptr
+ Offset
;
625 while ((Index
< *IortNodeCount
) && (Offset
< AcpiTableLength
)) {
626 // Parse the IORT Node Header
633 PARSER_PARAMS (IortNodeHeaderParser
)
635 if (*IortNodeLength
== 0) {
636 IncrementErrorCount ();
637 Print (L
"ERROR: Parser error. Invalid table data.\n");
641 PrintFieldName (2, L
"* Node Offset *");
642 Print (L
"0x%x\n", Offset
);
644 switch (*IortNodeType
) {
645 case EIORT_NODE_ITS_GROUP
:
651 case EIORT_NODE_NAMED_COMPONENT
:
652 DumpIortNodeNamedComponent (
659 case EIORT_NODE_ROOT_COMPLEX
:
660 DumpIortNodeRootComplex (
667 case EIORT_NODE_SMMUV1_V2
:
668 DumpIortNodeSmmuV1V2 (
675 case EIORT_NODE_SMMUV3
:
683 case EIORT_NODE_PMCG
:
693 IncrementErrorCount ();
694 Print (L
"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType
);
697 NodePtr
+= (*IortNodeLength
);
698 Offset
+= (*IortNodeLength
);