4 Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
8 - IO Remapping Table, Platform Design Document, Revision D, March 2018
14 #include <IndustryStandard/IoRemappingTable.h>
15 #include <Library/PrintLib.h>
16 #include <Library/UefiLib.h>
17 #include "AcpiParser.h"
18 #include "AcpiTableParser.h"
19 #include "AcpiViewConfig.h"
22 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo
;
24 STATIC CONST UINT32
*IortNodeCount
;
25 STATIC CONST UINT32
*IortNodeOffset
;
27 STATIC CONST UINT8
*IortNodeType
;
28 STATIC CONST UINT16
*IortNodeLength
;
29 STATIC CONST UINT32
*IortIdMappingCount
;
30 STATIC CONST UINT32
*IortIdMappingOffset
;
32 STATIC CONST UINT32
*InterruptContextCount
;
33 STATIC CONST UINT32
*InterruptContextOffset
;
34 STATIC CONST UINT32
*PmuInterruptCount
;
35 STATIC CONST UINT32
*PmuInterruptOffset
;
37 STATIC CONST UINT32
*ItsCount
;
40 This function validates the ID Mapping array count for the ITS node.
42 @param [in] Ptr Pointer to the start of the field data.
43 @param [in] Context Pointer to context specific information e.g. this
44 could be a pointer to the ACPI table header.
49 ValidateItsIdMappingCount (
54 if (*(UINT32
*)Ptr
!= 0) {
55 IncrementErrorCount ();
56 Print (L
"\nERROR: IORT ID Mapping count must be zero.");
61 This function validates the ID Mapping array count for the Performance
62 Monitoring Counter Group (PMCG) node.
64 @param [in] Ptr Pointer to the start of the field data.
65 @param [in] Context Pointer to context specific information e.g. this
66 could be a pointer to the ACPI table header.
71 ValidatePmcgIdMappingCount (
76 if (*(UINT32
*)Ptr
> 1) {
77 IncrementErrorCount ();
78 Print (L
"\nERROR: IORT ID Mapping count must not be greater than 1.");
83 This function validates the ID Mapping array offset for the ITS node.
85 @param [in] Ptr Pointer to the start of the field data.
86 @param [in] Context Pointer to context specific information e.g. this
87 could be a pointer to the ACPI table header.
92 ValidateItsIdArrayReference (
97 if (*(UINT32
*)Ptr
!= 0) {
98 IncrementErrorCount ();
99 Print (L
"\nERROR: IORT ID Mapping offset must be zero.");
104 Helper Macro for populating the IORT Node header in the ACPI_PARSER array.
106 @param [out] ValidateIdMappingCount Optional pointer to a function for
107 validating the ID Mapping count.
108 @param [out] ValidateIdArrayReference Optional pointer to a function for
109 validating the ID Array reference.
111 #define PARSE_IORT_NODE_HEADER(ValidateIdMappingCount, \
112 ValidateIdArrayReference) \
113 { L"Type", 1, 0, L"%d", NULL, (VOID**)&IortNodeType, NULL, NULL }, \
114 { L"Length", 2, 1, L"%d", NULL, (VOID**)&IortNodeLength, NULL, NULL }, \
115 { L"Revision", 1, 3, L"%d", NULL, NULL, NULL, NULL }, \
116 { L"Reserved", 4, 4, L"0x%x", NULL, NULL, NULL, NULL }, \
117 { L"Number of ID mappings", 4, 8, L"%d", NULL, \
118 (VOID**)&IortIdMappingCount, ValidateIdMappingCount, NULL }, \
119 { L"Reference to ID Array", 4, 12, L"0x%x", NULL, \
120 (VOID**)&IortIdMappingOffset, ValidateIdArrayReference, NULL }
123 An ACPI_PARSER array describing the ACPI IORT Table
125 STATIC CONST ACPI_PARSER IortParser
[] = {
126 PARSE_ACPI_HEADER (&AcpiHdrInfo
),
127 { L
"Number of IORT Nodes", 4, 36, L
"%d", NULL
,
128 (VOID
**)&IortNodeCount
, NULL
, NULL
},
129 { L
"Offset to Array of IORT Nodes",4, 40, L
"0x%x", NULL
,
130 (VOID
**)&IortNodeOffset
, NULL
, NULL
},
131 { L
"Reserved", 4, 44, L
"0x%x", NULL
,NULL
,NULL
, NULL
}
135 An ACPI_PARSER array describing the IORT node header structure.
137 STATIC CONST ACPI_PARSER IortNodeHeaderParser
[] = {
138 PARSE_IORT_NODE_HEADER (NULL
, NULL
)
142 An ACPI_PARSER array describing the IORT SMMUv1/2 node.
144 STATIC CONST ACPI_PARSER IortNodeSmmuV1V2Parser
[] = {
145 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
146 { L
"Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
147 { L
"Span", 8, 24, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
148 { L
"Model", 4, 32, L
"%d", NULL
, NULL
, NULL
, NULL
},
149 { L
"Flags", 4, 36, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
150 { L
"Global Interrupt Array Ref", 4, 40, L
"0x%x", NULL
, NULL
, NULL
,
152 { L
"Number of context interrupts", 4, 44, L
"%d", NULL
,
153 (VOID
**)&InterruptContextCount
, NULL
, NULL
},
154 { L
"Context Interrupt Array Ref", 4, 48, L
"0x%x", NULL
,
155 (VOID
**)&InterruptContextOffset
, NULL
, NULL
},
156 { L
"Number of PMU Interrupts", 4, 52, L
"%d", NULL
,
157 (VOID
**)&PmuInterruptCount
, NULL
, NULL
},
158 { L
"PMU Interrupt Array Ref", 4, 56, L
"0x%x", NULL
,
159 (VOID
**)&PmuInterruptOffset
, NULL
, NULL
},
162 { L
"SMMU_NSgIrpt", 4, 60, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
163 { L
"SMMU_NSgIrpt interrupt flags", 4, 64, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
164 { L
"SMMU_NSgCfgIrpt", 4, 68, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
165 { L
"SMMU_NSgCfgIrpt interrupt flags",4, 72, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
169 An ACPI_PARSER array describing the SMMUv1/2 Node Interrupt Array.
171 STATIC CONST ACPI_PARSER InterruptArrayParser
[] = {
172 { L
"Interrupt GSIV", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
173 { L
"Flags", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
177 An ACPI_PARSER array describing the IORT ID Mapping.
179 STATIC CONST ACPI_PARSER IortNodeIdMappingParser
[] = {
180 { L
"Input base", 4, 0, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
181 { L
"Number of IDs", 4, 4, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
182 { L
"Output base", 4, 8, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
183 { L
"Output reference", 4, 12, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
184 { L
"Flags", 4, 16, L
"0x%x", NULL
, NULL
, NULL
, NULL
}
188 An ACPI_PARSER array describing the IORT SMMUv3 node.
190 STATIC CONST ACPI_PARSER IortNodeSmmuV3Parser
[] = {
191 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
192 { L
"Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
193 { L
"Flags", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
194 { L
"Reserved", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
195 { L
"VATOS Address", 8, 32, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
196 { L
"Model", 4, 40, L
"%d", NULL
, NULL
, NULL
, NULL
},
197 { L
"Event", 4, 44, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
198 { L
"PRI", 4, 48, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
199 { L
"GERR", 4, 52, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
200 { L
"Sync", 4, 56, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
201 { L
"Proximity domain", 4, 60, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
202 { L
"Device ID mapping index", 4, 64, L
"%d", NULL
, NULL
, NULL
, NULL
}
206 An ACPI_PARSER array describing the IORT ITS node.
208 STATIC CONST ACPI_PARSER IortNodeItsParser
[] = {
209 PARSE_IORT_NODE_HEADER (
210 ValidateItsIdMappingCount
,
211 ValidateItsIdArrayReference
213 { L
"Number of ITSs", 4,16, L
"%d", NULL
, (VOID
**)&ItsCount
, NULL
}
217 An ACPI_PARSER array describing the ITS ID.
219 STATIC CONST ACPI_PARSER ItsIdParser
[] = {
220 { L
"GIC ITS Identifier", 4, 0, L
"%d", NULL
, NULL
, NULL
}
224 An ACPI_PARSER array describing the IORT Names Component node.
226 STATIC CONST ACPI_PARSER IortNodeNamedComponentParser
[] = {
227 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
228 { L
"Node Flags", 4, 16, L
"%d", NULL
, NULL
, NULL
, NULL
},
229 { L
"Memory access properties",8, 20, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
230 { L
"Device memory address size limit",1, 28, L
"%d", NULL
, NULL
, NULL
, NULL
}
234 An ACPI_PARSER array describing the IORT Root Complex node.
236 STATIC CONST ACPI_PARSER IortNodeRootComplexParser
[] = {
237 PARSE_IORT_NODE_HEADER (NULL
, NULL
),
238 { L
"Memory access properties",8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
239 { L
"ATS Attribute", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
240 { L
"PCI Segment number", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
241 { L
"Memory access size limit",1, 32, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
242 { L
"Reserved", 3, 33, L
"%x %x %x", Dump3Chars
, NULL
, NULL
, NULL
}
246 An ACPI_PARSER array describing the IORT PMCG node.
248 STATIC CONST ACPI_PARSER IortNodePmcgParser
[] = {
249 PARSE_IORT_NODE_HEADER (ValidatePmcgIdMappingCount
, NULL
),
250 { L
"Page 0 Base Address", 8, 16, L
"0x%lx", NULL
, NULL
, NULL
, NULL
},
251 { L
"Overflow interrupt GSIV", 4, 24, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
252 { L
"Node reference", 4, 28, L
"0x%x", NULL
, NULL
, NULL
, NULL
},
253 { L
"Page 1 Base Address", 8, 32, L
"0x%lx", NULL
, NULL
, NULL
, NULL
}
257 This function parses the IORT Node Id Mapping array.
259 @param [in] Ptr Pointer to the start of the ID mapping array.
260 @param [in] Length Length of the buffer.
261 @param [in] MappingCount The ID Mapping count.
265 DumpIortNodeIdMappings (
268 IN UINT32 MappingCount
273 CHAR8 Buffer
[40]; // Used for AsciiName param of ParseAcpi
278 while ((Index
< MappingCount
) &&
287 Offset
+= ParseAcpi (
293 PARSER_PARAMS (IortNodeIdMappingParser
)
300 This function parses the IORT SMMUv1/2 node.
302 @param [in] Ptr Pointer to the start of the buffer.
303 @param [in] Length Length of the buffer.
304 @param [in] MappingCount The ID Mapping count.
305 @param [in] MappingOffset The offset of the ID Mapping array
306 from the start of the IORT table.
310 DumpIortNodeSmmuV1V2 (
313 IN UINT32 MappingCount
,
314 IN UINT32 MappingOffset
319 CHAR8 Buffer
[50]; // Used for AsciiName param of ParseAcpi
324 "SMMUv1 or SMMUv2 Node",
327 PARSER_PARAMS (IortNodeSmmuV1V2Parser
)
330 // Check if the values used to control the parsing logic have been
331 // successfully read.
332 if ((InterruptContextCount
== NULL
) ||
333 (InterruptContextOffset
== NULL
) ||
334 (PmuInterruptCount
== NULL
) ||
335 (PmuInterruptOffset
== NULL
))
337 IncrementErrorCount ();
339 L
"ERROR: Insufficient SMMUv1/2 node length. Length = %d\n",
345 Offset
= *InterruptContextOffset
;
348 while ((Index
< *InterruptContextCount
) &&
354 "Context Interrupts Array [%d]",
357 Offset
+= ParseAcpi (
363 PARSER_PARAMS (InterruptArrayParser
)
368 Offset
= *PmuInterruptOffset
;
371 while ((Index
< *PmuInterruptCount
) &&
377 "PMU Interrupts Array [%d]",
380 Offset
+= ParseAcpi (
386 PARSER_PARAMS (InterruptArrayParser
)
391 DumpIortNodeIdMappings (
393 Length
- MappingOffset
,
399 This function parses the IORT SMMUv3 node.
401 @param [in] Ptr Pointer to the start of the buffer.
402 @param [in] Length Length of the buffer.
403 @param [in] MappingCount The ID Mapping count.
404 @param [in] MappingOffset The offset of the ID Mapping array
405 from the start of the IORT table.
412 IN UINT32 MappingCount
,
413 IN UINT32 MappingOffset
422 PARSER_PARAMS (IortNodeSmmuV3Parser
)
425 DumpIortNodeIdMappings (
427 Length
- MappingOffset
,
433 This function parses the IORT ITS node.
435 @param [in] Ptr Pointer to the start of the buffer.
436 @param [in] Length Length of the buffer.
447 CHAR8 Buffer
[80]; // Used for AsciiName param of ParseAcpi
455 PARSER_PARAMS (IortNodeItsParser
)
458 // Check if the values used to control the parsing logic have been
459 // successfully read.
460 if (ItsCount
== NULL
) {
461 IncrementErrorCount ();
463 L
"ERROR: Insufficient ITS group length. Length = %d.\n",
471 while ((Index
< *ItsCount
) &&
477 "GIC ITS Identifier Array [%d]",
480 Offset
+= ParseAcpi (
486 PARSER_PARAMS (ItsIdParser
)
491 // Note: ITS does not have the ID Mappings Array
495 This function parses the IORT Named Component node.
497 @param [in] Ptr Pointer to the start of the buffer.
498 @param [in] Length Length of the buffer.
499 @param [in] MappingCount The ID Mapping count.
500 @param [in] MappingOffset The offset of the ID Mapping array
501 from the start of the IORT table.
505 DumpIortNodeNamedComponent (
508 IN UINT32 MappingCount
,
509 IN UINT32 MappingOffset
517 "Named Component Node",
520 PARSER_PARAMS (IortNodeNamedComponentParser
)
523 // Estimate the Device Name length
524 PrintFieldName (2, L
"Device Object Name");
526 while ((*(Ptr
+ Offset
) != 0) &&
529 Print (L
"%c", *(Ptr
+ Offset
));
535 DumpIortNodeIdMappings (
537 Length
- MappingOffset
,
543 This function parses the IORT Root Complex node.
545 @param [in] Ptr Pointer to the start of the buffer.
546 @param [in] Length Length of the buffer.
547 @param [in] MappingCount The ID Mapping count.
548 @param [in] MappingOffset The offset of the ID Mapping array
549 from the start of the IORT table.
553 DumpIortNodeRootComplex (
556 IN UINT32 MappingCount
,
557 IN UINT32 MappingOffset
566 PARSER_PARAMS (IortNodeRootComplexParser
)
569 DumpIortNodeIdMappings (
571 Length
- MappingOffset
,
577 This function parses the IORT PMCG node.
579 @param [in] Ptr Pointer to the start of the buffer.
580 @param [in] Length Length of the buffer.
581 @param [in] MappingCount The ID Mapping count.
582 @param [in] MappingOffset The offset of the ID Mapping array
583 from the start of the IORT table.
590 IN UINT32 MappingCount
,
591 IN UINT32 MappingOffset
600 PARSER_PARAMS (IortNodePmcgParser
)
603 DumpIortNodeIdMappings (
605 Length
- MappingOffset
,
611 This function parses the ACPI IORT table.
612 When trace is enabled this function parses the IORT table and traces the ACPI fields.
614 This function also parses the following nodes:
622 This function also performs validation of the ACPI table fields.
624 @param [in] Trace If TRUE, trace the ACPI fields.
625 @param [in] Ptr Pointer to the start of the buffer.
626 @param [in] AcpiTableLength Length of the ACPI table.
627 @param [in] AcpiTableRevision Revision of the ACPI table.
634 IN UINT32 AcpiTableLength
,
635 IN UINT8 AcpiTableRevision
652 PARSER_PARAMS (IortParser
)
655 // Check if the values used to control the parsing logic have been
656 // successfully read.
657 if ((IortNodeCount
== NULL
) ||
658 (IortNodeOffset
== NULL
))
660 IncrementErrorCount ();
662 L
"ERROR: Insufficient table length. AcpiTableLength = %d.\n",
668 Offset
= *IortNodeOffset
;
669 NodePtr
= Ptr
+ Offset
;
672 // Parse the specified number of IORT nodes or the IORT table buffer length.
673 // Whichever is minimum.
674 while ((Index
++ < *IortNodeCount
) &&
675 (Offset
< AcpiTableLength
))
677 // Parse the IORT Node Header
683 AcpiTableLength
- Offset
,
684 PARSER_PARAMS (IortNodeHeaderParser
)
687 // Check if the values used to control the parsing logic have been
688 // successfully read.
689 if ((IortNodeType
== NULL
) ||
690 (IortNodeLength
== NULL
) ||
691 (IortIdMappingCount
== NULL
) ||
692 (IortIdMappingOffset
== NULL
))
694 IncrementErrorCount ();
696 L
"ERROR: Insufficient remaining table buffer length to read the " \
697 L
"IORT node header. Length = %d.\n",
698 AcpiTableLength
- Offset
703 // Validate IORT Node length
704 if ((*IortNodeLength
== 0) ||
705 ((Offset
+ (*IortNodeLength
)) > AcpiTableLength
))
707 IncrementErrorCount ();
709 L
"ERROR: Invalid IORT Node length. " \
710 L
"Length = %d. Offset = %d. AcpiTableLength = %d.\n",
718 PrintFieldName (2, L
"* Node Offset *");
719 Print (L
"0x%x\n", Offset
);
721 switch (*IortNodeType
) {
722 case EFI_ACPI_IORT_TYPE_ITS_GROUP
:
728 case EFI_ACPI_IORT_TYPE_NAMED_COMP
:
729 DumpIortNodeNamedComponent (
736 case EFI_ACPI_IORT_TYPE_ROOT_COMPLEX
:
737 DumpIortNodeRootComplex (
744 case EFI_ACPI_IORT_TYPE_SMMUv1v2
:
745 DumpIortNodeSmmuV1V2 (
752 case EFI_ACPI_IORT_TYPE_SMMUv3
:
760 case EFI_ACPI_IORT_TYPE_PMCG
:
770 IncrementErrorCount ();
771 Print (L
"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType
);
774 NodePtr
+= (*IortNodeLength
);
775 Offset
+= (*IortNodeLength
);