Bugzilla: 3458 - Add support IORT Rev E.d specification updates
          (https://bugzilla.tianocore.org/show_bug.cgi?id=3458)
The IO Remapping Table, Platform Design Document, Revision E.d,
Feb 2022 (https://developer.arm.com/documentation/den0049/)
introduces the following updates, collectively including the
updates and errata fixes to Rev E, Rev E.a, Rev E.b, Rev E.c:
 - increments the IORT table revision to 5.
 - updates the node definition to add an 'Identifier' field.
 - adds definition of node type 6 - Reserved Memory Range node.
 - adds definition for Memory Range Descriptors.
 - adds flag to indicate PRI support for root complexes.
 - adds flag to indicate if the root complex supports forwarding
   of PASID information on translated transactions to the SMMU.
 - adds flag to indicate if the root complex supports PASID.
 - adds flags to define access privilege and attributes for the
   memory ranges.
Therefore, update the IORT parser to:
  - parse the Identifier field.
  - parse Reserved Memory Range node.
  - parse Memory Range Descriptors.
  - add validations to check that the physical range base
    and size of the Memory Range Descriptor is 64KB aligned.
  - add validation to check that the IORT Table Revision is
    not 4 as IORT Rev E.c is deprecated.
  - add validation to check that the IORT RMR node revision
    is not 2 as it breaks backward compatibility and was
    deprecated as part of IORT Rev E.c.
  - skip parsing of IORT Rev E, Rev E.a, Rev E.b, Rev E.c as
    some fields were deprecated in these revisions.
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Zhichao Gao <zhichao.gao@intel.com>
Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
		
	
		
			
				
	
	
		
			972 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			972 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   IORT table parser
 | |
| 
 | |
|   Copyright (c) 2016 - 2022, Arm Limited. All rights reserved.
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
|   @par Reference(s):
 | |
|     - IO Remapping Table, Platform Design Document, Revision E.d, Feb 2022
 | |
|       (https://developer.arm.com/documentation/den0049/)
 | |
| 
 | |
|   @par Glossary:
 | |
|     - Ref  - Reference
 | |
|     - Desc - Descriptor
 | |
| **/
 | |
| 
 | |
| #include <IndustryStandard/IoRemappingTable.h>
 | |
| #include <Library/PrintLib.h>
 | |
| #include <Library/UefiLib.h>
 | |
| #include "AcpiParser.h"
 | |
| #include "AcpiTableParser.h"
 | |
| #include "AcpiViewConfig.h"
 | |
| 
 | |
| // Local variables
 | |
| STATIC ACPI_DESCRIPTION_HEADER_INFO  AcpiHdrInfo;
 | |
| 
 | |
| STATIC CONST UINT32  *IortNodeCount;
 | |
| STATIC CONST UINT32  *IortNodeOffset;
 | |
| 
 | |
| STATIC CONST UINT8   *IortNodeType;
 | |
| STATIC CONST UINT16  *IortNodeLength;
 | |
| STATIC CONST UINT8   *IortNodeRevision;
 | |
| STATIC CONST UINT32  *IortIdMappingCount;
 | |
| STATIC CONST UINT32  *IortIdMappingOffset;
 | |
| 
 | |
| STATIC CONST UINT32  *InterruptContextCount;
 | |
| STATIC CONST UINT32  *InterruptContextOffset;
 | |
| STATIC CONST UINT32  *PmuInterruptCount;
 | |
| STATIC CONST UINT32  *PmuInterruptOffset;
 | |
| 
 | |
| STATIC CONST UINT32  *ItsCount;
 | |
| 
 | |
| STATIC CONST UINT32  *RmrMemDescCount;
 | |
| STATIC CONST UINT32  *RmrMemDescOffset;
 | |
| 
 | |
| /**
 | |
|   This function validates the ID Mapping array count for the ITS node.
 | |
| 
 | |
|   @param [in] Ptr     Pointer to the start of the field data.
 | |
|   @param [in] Context Pointer to context specific information e.g. this
 | |
|                       could be a pointer to the ACPI table header.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| EFIAPI
 | |
| ValidateItsIdMappingCount (
 | |
|   IN UINT8  *Ptr,
 | |
|   IN VOID   *Context
 | |
|   )
 | |
| {
 | |
|   if (*(UINT32 *)Ptr != 0) {
 | |
|     IncrementErrorCount ();
 | |
|     Print (L"\nERROR: IORT ID Mapping count must be zero.");
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function validates the ID Mapping array count for the Performance
 | |
|   Monitoring Counter Group (PMCG) node.
 | |
| 
 | |
|   @param [in] Ptr     Pointer to the start of the field data.
 | |
|   @param [in] Context Pointer to context specific information e.g. this
 | |
|                       could be a pointer to the ACPI table header.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| EFIAPI
 | |
| ValidatePmcgIdMappingCount (
 | |
|   IN UINT8  *Ptr,
 | |
|   IN VOID   *Context
 | |
|   )
 | |
| {
 | |
|   if (*(UINT32 *)Ptr > 1) {
 | |
|     IncrementErrorCount ();
 | |
|     Print (L"\nERROR: IORT ID Mapping count must not be greater than 1.");
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function validates the ID Mapping array offset for the ITS node.
 | |
| 
 | |
|   @param [in] Ptr     Pointer to the start of the field data.
 | |
|   @param [in] Context Pointer to context specific information e.g. this
 | |
|                       could be a pointer to the ACPI table header.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| EFIAPI
 | |
| ValidateItsIdArrayReference (
 | |
|   IN UINT8  *Ptr,
 | |
|   IN VOID   *Context
 | |
|   )
 | |
| {
 | |
|   if (*(UINT32 *)Ptr != 0) {
 | |
|     IncrementErrorCount ();
 | |
|     Print (L"\nERROR: IORT ID Mapping offset must be zero.");
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function validates that the Physical Range address or length is not zero
 | |
|   and is 64K aligned.
 | |
| 
 | |
|   @param [in] Ptr     Pointer to the start of the field data.
 | |
|   @param [in] Context Pointer to context specific information e.g. this
 | |
|                       could be a pointer to the ACPI table header.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| EFIAPI
 | |
| ValidatePhysicalRange (
 | |
|   IN UINT8  *Ptr,
 | |
|   IN VOID   *Context
 | |
|   )
 | |
| {
 | |
|   UINT64  Value;
 | |
| 
 | |
|   Value = *(UINT64 *)Ptr;
 | |
|   if ((Value == 0) || ((Value & (SIZE_64KB - 1)) != 0)) {
 | |
|     IncrementErrorCount ();
 | |
|     Print (L"\nERROR: Physical Range must be 64K aligned and cannot be zero.");
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function validates that the RMR memory range descriptor count.
 | |
| 
 | |
|   @param [in] Ptr     Pointer to the start of the field data.
 | |
|   @param [in] Context Pointer to context specific information e.g. this
 | |
|                       could be a pointer to the ACPI table header.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| EFIAPI
 | |
| ValidateRmrMemDescCount (
 | |
|   IN UINT8  *Ptr,
 | |
|   IN VOID   *Context
 | |
|   )
 | |
| {
 | |
|   if (*(UINT32 *)Ptr == 0) {
 | |
|     IncrementErrorCount ();
 | |
|     Print (L"\nERROR: Memory Range Descriptor count must be >=1.");
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Helper Macro for populating the IORT Node header in the ACPI_PARSER array.
 | |
| 
 | |
|   @param [out] ValidateIdMappingCount    Optional pointer to a function for
 | |
|                                          validating the ID Mapping count.
 | |
|   @param [out] ValidateIdArrayReference  Optional pointer to a function for
 | |
|                                          validating the ID Array reference.
 | |
| **/
 | |
| #define PARSE_IORT_NODE_HEADER(ValidateIdMappingCount,                        \
 | |
|                                ValidateIdArrayReference)                      \
 | |
|   { L"Type", 1, 0, L"%d", NULL, (VOID**)&IortNodeType, NULL, NULL },          \
 | |
|   { L"Length", 2, 1, L"%d", NULL, (VOID**)&IortNodeLength, NULL, NULL },      \
 | |
|   { L"Revision", 1, 3, L"%d", NULL, (VOID**)&IortNodeRevision, NULL, NULL },  \
 | |
|   { L"Identifier", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },                   \
 | |
|   { L"Number of ID mappings", 4, 8, L"%d", NULL,                              \
 | |
|     (VOID**)&IortIdMappingCount, ValidateIdMappingCount, NULL },              \
 | |
|   { L"Reference to ID Array", 4, 12, L"0x%x", NULL,                           \
 | |
|     (VOID**)&IortIdMappingOffset, ValidateIdArrayReference, NULL }
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the ACPI IORT Table
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortParser[] = {
 | |
|   PARSE_ACPI_HEADER (&AcpiHdrInfo),
 | |
|   { L"Number of IORT Nodes",       4,     36, L"%d",   NULL,
 | |
|     (VOID **)&IortNodeCount,       NULL,  NULL },
 | |
|   { L"Offset to Array of IORT Nodes",4,     40, L"0x%x", NULL,
 | |
|     (VOID **)&IortNodeOffset,      NULL,  NULL },
 | |
|   { L"Reserved",                   4,     44, L"0x%x", NULL,NULL,NULL, NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the IORT node header structure.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortNodeHeaderParser[] = {
 | |
|   PARSE_IORT_NODE_HEADER (NULL, NULL)
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the IORT SMMUv1/2 node.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortNodeSmmuV1V2Parser[] = {
 | |
|   PARSE_IORT_NODE_HEADER (NULL,       NULL),
 | |
|   { L"Base Address",                  8,    16,  L"0x%lx", NULL, NULL, NULL, NULL },
 | |
|   { L"Span",                          8,    24,  L"0x%lx", NULL, NULL, NULL, NULL },
 | |
|   { L"Model",                         4,    32,  L"%d",    NULL, NULL, NULL, NULL },
 | |
|   { L"Flags",                         4,    36,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"Global Interrupt Array Ref",    4,    40,  L"0x%x",  NULL, NULL, NULL,
 | |
|     NULL },
 | |
|   { L"Number of context interrupts",  4,    44,  L"%d",    NULL,
 | |
|     (VOID **)&InterruptContextCount,  NULL, NULL },
 | |
|   { L"Context Interrupt Array Ref",   4,    48,  L"0x%x",  NULL,
 | |
|     (VOID **)&InterruptContextOffset, NULL, NULL },
 | |
|   { L"Number of PMU Interrupts",      4,    52,  L"%d",    NULL,
 | |
|     (VOID **)&PmuInterruptCount,      NULL, NULL },
 | |
|   { L"PMU Interrupt Array Ref",       4,    56,  L"0x%x",  NULL,
 | |
|     (VOID **)&PmuInterruptOffset,     NULL, NULL },
 | |
| 
 | |
|   // Interrupt Array
 | |
|   { L"SMMU_NSgIrpt",                  4,    60,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"SMMU_NSgIrpt interrupt flags",  4,    64,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"SMMU_NSgCfgIrpt",               4,    68,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"SMMU_NSgCfgIrpt interrupt flags",4,    72,  L"0x%x",  NULL, NULL, NULL, NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the SMMUv1/2 Node Interrupt Array.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  InterruptArrayParser[] = {
 | |
|   { L"Interrupt GSIV", 4, 0, L"0x%x", NULL, NULL, NULL, NULL },
 | |
|   { L"Flags",          4, 4, L"0x%x", NULL, NULL, NULL, NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the IORT ID Mapping.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortNodeIdMappingParser[] = {
 | |
|   { L"Input base",       4, 0,  L"0x%x", NULL, NULL, NULL, NULL },
 | |
|   { L"Number of IDs",    4, 4,  L"0x%x", NULL, NULL, NULL, NULL },
 | |
|   { L"Output base",      4, 8,  L"0x%x", NULL, NULL, NULL, NULL },
 | |
|   { L"Output reference", 4, 12, L"0x%x", NULL, NULL, NULL, NULL },
 | |
|   { L"Flags",            4, 16, L"0x%x", NULL, NULL, NULL, NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the IORT SMMUv3 node.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortNodeSmmuV3Parser[] = {
 | |
|   PARSE_IORT_NODE_HEADER (NULL, NULL),
 | |
|   { L"Base Address",            8,    16,  L"0x%lx", NULL, NULL, NULL, NULL },
 | |
|   { L"Flags",                   4,    24,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"Reserved",                4,    28,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"VATOS Address",           8,    32,  L"0x%lx", NULL, NULL, NULL, NULL },
 | |
|   { L"Model",                   4,    40,  L"%d",    NULL, NULL, NULL, NULL },
 | |
|   { L"Event",                   4,    44,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"PRI",                     4,    48,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"GERR",                    4,    52,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"Sync",                    4,    56,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"Proximity domain",        4,    60,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"Device ID mapping index", 4,    64,  L"%d",    NULL, NULL, NULL, NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the IORT ITS node.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortNodeItsParser[] = {
 | |
|   PARSE_IORT_NODE_HEADER (
 | |
|     ValidateItsIdMappingCount,
 | |
|     ValidateItsIdArrayReference
 | |
|     ),
 | |
|   { L"Number of ITSs",        4,16, L"%d", NULL, (VOID **)&ItsCount, NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the ITS ID.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  ItsIdParser[] = {
 | |
|   { L"GIC ITS Identifier", 4, 0, L"%d", NULL, NULL, NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the IORT Names Component node.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortNodeNamedComponentParser[] = {
 | |
|   PARSE_IORT_NODE_HEADER (NULL, NULL),
 | |
|   { L"Node Flags",              4,    16,  L"%d",    NULL, NULL, NULL, NULL },
 | |
|   { L"Memory access properties",8,    20,  L"0x%lx", NULL, NULL, NULL, NULL },
 | |
|   { L"Device memory address size limit",1,    28,  L"%d",    NULL, NULL, NULL, NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the IORT Root Complex node.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortNodeRootComplexParser[] = {
 | |
|   PARSE_IORT_NODE_HEADER (NULL, NULL),
 | |
|   { L"Memory access properties",8,    16,  L"0x%lx", NULL, NULL, NULL, NULL },
 | |
|   { L"ATS Attribute",           4,    24,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"PCI Segment number",      4,    28,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"Memory access size limit",1,    32,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"PASID capabilities",      2,    33,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"Reserved",                1,    35,  L"%x",    NULL, NULL, NULL, NULL },
 | |
|   { L"Flags",                   4,    36,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the IORT PMCG node.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortNodePmcgParser[] = {
 | |
|   PARSE_IORT_NODE_HEADER (ValidatePmcgIdMappingCount, NULL),
 | |
|   { L"Page 0 Base Address",                           8,    16,  L"0x%lx", NULL, NULL, NULL, NULL },
 | |
|   { L"Overflow interrupt GSIV",                       4,    24,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"Node reference",                                4,    28,  L"0x%x",  NULL, NULL, NULL, NULL },
 | |
|   { L"Page 1 Base Address",                           8,    32,  L"0x%lx", NULL, NULL, NULL, NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the IORT RMR node.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortNodeRmrParser[] = {
 | |
|   PARSE_IORT_NODE_HEADER (NULL, NULL),
 | |
|   { L"Flags",                   4,                      16,  L"0x%x", NULL, NULL, NULL, NULL },
 | |
|   { L"Memory Range Desc count", 4,                      20,  L"%d",   NULL,
 | |
|     (VOID **)&RmrMemDescCount,  ValidateRmrMemDescCount,NULL },
 | |
|   { L"Memory Range Desc Ref",   4,                      24,  L"0x%x", NULL,
 | |
|     (VOID **)&RmrMemDescOffset, NULL,                   NULL }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An ACPI_PARSER array describing the IORT RMR Memory Range Descriptor.
 | |
| **/
 | |
| STATIC CONST ACPI_PARSER  IortNodeRmrMemRangeDescParser[] = {
 | |
|   { L"Physical Range offset", 8, 0,  L"0x%lx", NULL, NULL, ValidatePhysicalRange,
 | |
|     NULL },
 | |
|   { L"Physical Range length", 8, 8,  L"0x%lx", NULL, NULL, ValidatePhysicalRange,
 | |
|     NULL },
 | |
|   { L"Reserved",              4, 16, L"0x%x",  NULL, NULL, NULL,                 NULL}
 | |
| };
 | |
| 
 | |
| /**
 | |
|   This function parses the IORT Node Id Mapping array.
 | |
| 
 | |
|   @param [in] Ptr            Pointer to the start of the ID mapping array.
 | |
|   @param [in] Length         Length of the buffer.
 | |
|   @param [in] MappingCount   The ID Mapping count.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| DumpIortNodeIdMappings (
 | |
|   IN UINT8   *Ptr,
 | |
|   IN UINT32  Length,
 | |
|   IN UINT32  MappingCount
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
|   UINT32  Offset;
 | |
|   CHAR8   Buffer[40]; // Used for AsciiName param of ParseAcpi
 | |
| 
 | |
|   Index  = 0;
 | |
|   Offset = 0;
 | |
| 
 | |
|   while ((Index < MappingCount) &&
 | |
|          (Offset < Length))
 | |
|   {
 | |
|     AsciiSPrint (
 | |
|       Buffer,
 | |
|       sizeof (Buffer),
 | |
|       "ID Mapping [%d]",
 | |
|       Index
 | |
|       );
 | |
|     Offset += ParseAcpi (
 | |
|                 TRUE,
 | |
|                 4,
 | |
|                 Buffer,
 | |
|                 Ptr + Offset,
 | |
|                 Length - Offset,
 | |
|                 PARSER_PARAMS (IortNodeIdMappingParser)
 | |
|                 );
 | |
|     Index++;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function parses the IORT SMMUv1/2 node.
 | |
| 
 | |
|   @param [in] Ptr            Pointer to the start of the buffer.
 | |
|   @param [in] Length         Length of the buffer.
 | |
|   @param [in] MappingCount   The ID Mapping count.
 | |
|   @param [in] MappingOffset  The offset of the ID Mapping array
 | |
|                              from the start of the IORT table.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| DumpIortNodeSmmuV1V2 (
 | |
|   IN UINT8   *Ptr,
 | |
|   IN UINT16  Length,
 | |
|   IN UINT32  MappingCount,
 | |
|   IN UINT32  MappingOffset
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
|   UINT32  Offset;
 | |
|   CHAR8   Buffer[50]; // Used for AsciiName param of ParseAcpi
 | |
| 
 | |
|   ParseAcpi (
 | |
|     TRUE,
 | |
|     2,
 | |
|     "SMMUv1 or SMMUv2 Node",
 | |
|     Ptr,
 | |
|     Length,
 | |
|     PARSER_PARAMS (IortNodeSmmuV1V2Parser)
 | |
|     );
 | |
| 
 | |
|   // Check if the values used to control the parsing logic have been
 | |
|   // successfully read.
 | |
|   if ((InterruptContextCount == NULL)   ||
 | |
|       (InterruptContextOffset == NULL)  ||
 | |
|       (PmuInterruptCount == NULL)       ||
 | |
|       (PmuInterruptOffset == NULL))
 | |
|   {
 | |
|     IncrementErrorCount ();
 | |
|     Print (
 | |
|       L"ERROR: Insufficient SMMUv1/2 node length. Length = %d\n",
 | |
|       Length
 | |
|       );
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Offset = *InterruptContextOffset;
 | |
|   Index  = 0;
 | |
| 
 | |
|   while ((Index < *InterruptContextCount) &&
 | |
|          (Offset < Length))
 | |
|   {
 | |
|     AsciiSPrint (
 | |
|       Buffer,
 | |
|       sizeof (Buffer),
 | |
|       "Context Interrupts Array [%d]",
 | |
|       Index
 | |
|       );
 | |
|     Offset += ParseAcpi (
 | |
|                 TRUE,
 | |
|                 4,
 | |
|                 Buffer,
 | |
|                 Ptr + Offset,
 | |
|                 Length - Offset,
 | |
|                 PARSER_PARAMS (InterruptArrayParser)
 | |
|                 );
 | |
|     Index++;
 | |
|   }
 | |
| 
 | |
|   Offset = *PmuInterruptOffset;
 | |
|   Index  = 0;
 | |
| 
 | |
|   while ((Index < *PmuInterruptCount) &&
 | |
|          (Offset < Length))
 | |
|   {
 | |
|     AsciiSPrint (
 | |
|       Buffer,
 | |
|       sizeof (Buffer),
 | |
|       "PMU Interrupts Array [%d]",
 | |
|       Index
 | |
|       );
 | |
|     Offset += ParseAcpi (
 | |
|                 TRUE,
 | |
|                 4,
 | |
|                 Buffer,
 | |
|                 Ptr + Offset,
 | |
|                 Length - Offset,
 | |
|                 PARSER_PARAMS (InterruptArrayParser)
 | |
|                 );
 | |
|     Index++;
 | |
|   }
 | |
| 
 | |
|   DumpIortNodeIdMappings (
 | |
|     Ptr + MappingOffset,
 | |
|     Length - MappingOffset,
 | |
|     MappingCount
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function parses the IORT SMMUv3 node.
 | |
| 
 | |
|   @param [in] Ptr            Pointer to the start of the buffer.
 | |
|   @param [in] Length         Length of the buffer.
 | |
|   @param [in] MappingCount   The ID Mapping count.
 | |
|   @param [in] MappingOffset  The offset of the ID Mapping array
 | |
|                              from the start of the IORT table.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| DumpIortNodeSmmuV3 (
 | |
|   IN UINT8   *Ptr,
 | |
|   IN UINT16  Length,
 | |
|   IN UINT32  MappingCount,
 | |
|   IN UINT32  MappingOffset
 | |
|   )
 | |
| {
 | |
|   ParseAcpi (
 | |
|     TRUE,
 | |
|     2,
 | |
|     "SMMUV3 Node",
 | |
|     Ptr,
 | |
|     Length,
 | |
|     PARSER_PARAMS (IortNodeSmmuV3Parser)
 | |
|     );
 | |
| 
 | |
|   DumpIortNodeIdMappings (
 | |
|     Ptr + MappingOffset,
 | |
|     Length - MappingOffset,
 | |
|     MappingCount
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function parses the IORT ITS node.
 | |
| 
 | |
|   @param [in] Ptr            Pointer to the start of the buffer.
 | |
|   @param [in] Length         Length of the buffer.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| DumpIortNodeIts (
 | |
|   IN UINT8   *Ptr,
 | |
|   IN UINT16  Length
 | |
|   )
 | |
| {
 | |
|   UINT32  Offset;
 | |
|   UINT32  Index;
 | |
|   CHAR8   Buffer[80]; // Used for AsciiName param of ParseAcpi
 | |
| 
 | |
|   Offset = ParseAcpi (
 | |
|              TRUE,
 | |
|              2,
 | |
|              "ITS Node",
 | |
|              Ptr,
 | |
|              Length,
 | |
|              PARSER_PARAMS (IortNodeItsParser)
 | |
|              );
 | |
| 
 | |
|   // Check if the values used to control the parsing logic have been
 | |
|   // successfully read.
 | |
|   if (ItsCount == NULL) {
 | |
|     IncrementErrorCount ();
 | |
|     Print (
 | |
|       L"ERROR: Insufficient ITS group length. Length = %d.\n",
 | |
|       Length
 | |
|       );
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Index = 0;
 | |
| 
 | |
|   while ((Index < *ItsCount) &&
 | |
|          (Offset < Length))
 | |
|   {
 | |
|     AsciiSPrint (
 | |
|       Buffer,
 | |
|       sizeof (Buffer),
 | |
|       "GIC ITS Identifier Array [%d]",
 | |
|       Index
 | |
|       );
 | |
|     Offset += ParseAcpi (
 | |
|                 TRUE,
 | |
|                 4,
 | |
|                 Buffer,
 | |
|                 Ptr + Offset,
 | |
|                 Length - Offset,
 | |
|                 PARSER_PARAMS (ItsIdParser)
 | |
|                 );
 | |
|     Index++;
 | |
|   }
 | |
| 
 | |
|   // Note: ITS does not have the ID Mappings Array
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function parses the IORT Named Component node.
 | |
| 
 | |
|   @param [in] Ptr            Pointer to the start of the buffer.
 | |
|   @param [in] Length         Length of the buffer.
 | |
|   @param [in] MappingCount   The ID Mapping count.
 | |
|   @param [in] MappingOffset  The offset of the ID Mapping array
 | |
|                              from the start of the IORT table.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| DumpIortNodeNamedComponent (
 | |
|   IN UINT8   *Ptr,
 | |
|   IN UINT16  Length,
 | |
|   IN UINT32  MappingCount,
 | |
|   IN UINT32  MappingOffset
 | |
|   )
 | |
| {
 | |
|   UINT32  Offset;
 | |
| 
 | |
|   Offset = ParseAcpi (
 | |
|              TRUE,
 | |
|              2,
 | |
|              "Named Component Node",
 | |
|              Ptr,
 | |
|              Length,
 | |
|              PARSER_PARAMS (IortNodeNamedComponentParser)
 | |
|              );
 | |
| 
 | |
|   // Estimate the Device Name length
 | |
|   PrintFieldName (2, L"Device Object Name");
 | |
| 
 | |
|   while ((*(Ptr + Offset) != 0) &&
 | |
|          (Offset < Length))
 | |
|   {
 | |
|     Print (L"%c", *(Ptr + Offset));
 | |
|     Offset++;
 | |
|   }
 | |
| 
 | |
|   Print (L"\n");
 | |
| 
 | |
|   DumpIortNodeIdMappings (
 | |
|     Ptr + MappingOffset,
 | |
|     Length - MappingOffset,
 | |
|     MappingCount
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function parses the IORT Root Complex node.
 | |
| 
 | |
|   @param [in] Ptr            Pointer to the start of the buffer.
 | |
|   @param [in] Length         Length of the buffer.
 | |
|   @param [in] MappingCount   The ID Mapping count.
 | |
|   @param [in] MappingOffset  The offset of the ID Mapping array
 | |
|                              from the start of the IORT table.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| DumpIortNodeRootComplex (
 | |
|   IN UINT8   *Ptr,
 | |
|   IN UINT16  Length,
 | |
|   IN UINT32  MappingCount,
 | |
|   IN UINT32  MappingOffset
 | |
|   )
 | |
| {
 | |
|   ParseAcpi (
 | |
|     TRUE,
 | |
|     2,
 | |
|     "Root Complex Node",
 | |
|     Ptr,
 | |
|     Length,
 | |
|     PARSER_PARAMS (IortNodeRootComplexParser)
 | |
|     );
 | |
| 
 | |
|   DumpIortNodeIdMappings (
 | |
|     Ptr + MappingOffset,
 | |
|     Length - MappingOffset,
 | |
|     MappingCount
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function parses the IORT PMCG node.
 | |
| 
 | |
|   @param [in] Ptr            Pointer to the start of the buffer.
 | |
|   @param [in] Length         Length of the buffer.
 | |
|   @param [in] MappingCount   The ID Mapping count.
 | |
|   @param [in] MappingOffset  The offset of the ID Mapping array
 | |
|                              from the start of the IORT table.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| DumpIortNodePmcg (
 | |
|   IN UINT8   *Ptr,
 | |
|   IN UINT16  Length,
 | |
|   IN UINT32  MappingCount,
 | |
|   IN UINT32  MappingOffset
 | |
|   )
 | |
| {
 | |
|   ParseAcpi (
 | |
|     TRUE,
 | |
|     2,
 | |
|     "PMCG Node",
 | |
|     Ptr,
 | |
|     Length,
 | |
|     PARSER_PARAMS (IortNodePmcgParser)
 | |
|     );
 | |
| 
 | |
|   DumpIortNodeIdMappings (
 | |
|     Ptr + MappingOffset,
 | |
|     Length - MappingOffset,
 | |
|     MappingCount
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function parses the IORT RMR Node Memory Range Descriptor array.
 | |
| 
 | |
|   @param [in] Ptr         Pointer to the start of the Memory Range Descriptor
 | |
|                           array.
 | |
|   @param [in] Length      Length of the buffer.
 | |
|   @param [in] DescCount   Memory Range Descriptor count.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| DumpIortNodeRmrMemRangeDesc (
 | |
|   IN UINT8   *Ptr,
 | |
|   IN UINT32  Length,
 | |
|   IN UINT32  DescCount
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
|   UINT32  Offset;
 | |
|   CHAR8   Buffer[40]; // Used for AsciiName param of ParseAcpi
 | |
| 
 | |
|   Index  = 0;
 | |
|   Offset = 0;
 | |
| 
 | |
|   while ((Index < DescCount) &&
 | |
|          (Offset < Length))
 | |
|   {
 | |
|     AsciiSPrint (
 | |
|       Buffer,
 | |
|       sizeof (Buffer),
 | |
|       "Mem range Descriptor [%d]",
 | |
|       Index
 | |
|       );
 | |
|     Offset += ParseAcpi (
 | |
|                 TRUE,
 | |
|                 4,
 | |
|                 Buffer,
 | |
|                 Ptr + Offset,
 | |
|                 Length - Offset,
 | |
|                 PARSER_PARAMS (IortNodeRmrMemRangeDescParser)
 | |
|                 );
 | |
|     Index++;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function parses the IORT RMR node.
 | |
| 
 | |
|   @param [in] Ptr            Pointer to the start of the buffer.
 | |
|   @param [in] Length         Length of the buffer.
 | |
|   @param [in] MappingCount   The ID Mapping count.
 | |
|   @param [in] MappingOffset  The offset of the ID Mapping array
 | |
|                              from the start of the IORT table.
 | |
| **/
 | |
| STATIC
 | |
| VOID
 | |
| DumpIortNodeRmr (
 | |
|   IN UINT8   *Ptr,
 | |
|   IN UINT16  Length,
 | |
|   IN UINT32  MappingCount,
 | |
|   IN UINT32  MappingOffset
 | |
|   )
 | |
| {
 | |
|   ParseAcpi (
 | |
|     TRUE,
 | |
|     2,
 | |
|     "RMR Node",
 | |
|     Ptr,
 | |
|     Length,
 | |
|     PARSER_PARAMS (IortNodeRmrParser)
 | |
|     );
 | |
| 
 | |
|   if (*IortNodeRevision == EFI_ACPI_IORT_RMR_NODE_REVISION_02) {
 | |
|     IncrementErrorCount ();
 | |
|     Print (
 | |
|       L"ERROR: RMR node Rev 2 (defined in IORT Rev E.c) must not be used."
 | |
|       L" IORT tabe Revision E.c is deprecated and must not be used.\n"
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   DumpIortNodeIdMappings (
 | |
|     Ptr + MappingOffset,
 | |
|     Length - MappingOffset,
 | |
|     MappingCount
 | |
|     );
 | |
| 
 | |
|   DumpIortNodeRmrMemRangeDesc (
 | |
|     Ptr + (*RmrMemDescOffset),
 | |
|     Length - (*RmrMemDescOffset),
 | |
|     *RmrMemDescCount
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function parses the ACPI IORT table.
 | |
|   When trace is enabled this function parses the IORT table and traces the ACPI
 | |
|   fields.
 | |
| 
 | |
|   This function also parses the following nodes:
 | |
|     - ITS Group
 | |
|     - Named Component
 | |
|     - Root Complex
 | |
|     - SMMUv1/2
 | |
|     - SMMUv3
 | |
|     - PMCG
 | |
|     - RMR
 | |
| 
 | |
|   This function also performs validation of the ACPI table fields.
 | |
| 
 | |
|   @param [in] Trace              If TRUE, trace the ACPI fields.
 | |
|   @param [in] Ptr                Pointer to the start of the buffer.
 | |
|   @param [in] AcpiTableLength    Length of the ACPI table.
 | |
|   @param [in] AcpiTableRevision  Revision of the ACPI table.
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ParseAcpiIort (
 | |
|   IN BOOLEAN  Trace,
 | |
|   IN UINT8    *Ptr,
 | |
|   IN UINT32   AcpiTableLength,
 | |
|   IN UINT8    AcpiTableRevision
 | |
|   )
 | |
| {
 | |
|   UINT32  Offset;
 | |
|   UINT32  Index;
 | |
|   UINT8   *NodePtr;
 | |
| 
 | |
|   if (!Trace) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if ((AcpiTableRevision > EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00) &&
 | |
|       (AcpiTableRevision < EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05))
 | |
|   {
 | |
|     Print (
 | |
|       L"ERROR: Parsing not supported for IORT tabe Revision E, E.<a,b,c>.\n"
 | |
|       );
 | |
|     if (AcpiTableRevision == EFI_ACPI_IO_REMAPPING_TABLE_REVISION_04) {
 | |
|       IncrementErrorCount ();
 | |
|       Print (
 | |
|         L"ERROR: IORT tabe Revision E.c is deprecated and must not be used.\n"
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   ParseAcpi (
 | |
|     TRUE,
 | |
|     0,
 | |
|     "IORT",
 | |
|     Ptr,
 | |
|     AcpiTableLength,
 | |
|     PARSER_PARAMS (IortParser)
 | |
|     );
 | |
| 
 | |
|   // Check if the values used to control the parsing logic have been
 | |
|   // successfully read.
 | |
|   if ((IortNodeCount == NULL) ||
 | |
|       (IortNodeOffset == NULL))
 | |
|   {
 | |
|     IncrementErrorCount ();
 | |
|     Print (
 | |
|       L"ERROR: Insufficient table length. AcpiTableLength = %d.\n",
 | |
|       AcpiTableLength
 | |
|       );
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Offset  = *IortNodeOffset;
 | |
|   NodePtr = Ptr + Offset;
 | |
|   Index   = 0;
 | |
| 
 | |
|   // Parse the specified number of IORT nodes or the IORT table buffer length.
 | |
|   // Whichever is minimum.
 | |
|   while ((Index++ < *IortNodeCount) &&
 | |
|          (Offset < AcpiTableLength))
 | |
|   {
 | |
|     // Parse the IORT Node Header
 | |
|     ParseAcpi (
 | |
|       FALSE,
 | |
|       0,
 | |
|       "IORT Node Header",
 | |
|       NodePtr,
 | |
|       AcpiTableLength - Offset,
 | |
|       PARSER_PARAMS (IortNodeHeaderParser)
 | |
|       );
 | |
| 
 | |
|     // Check if the values used to control the parsing logic have been
 | |
|     // successfully read.
 | |
|     if ((IortNodeType == NULL)        ||
 | |
|         (IortNodeLength == NULL)      ||
 | |
|         (IortIdMappingCount == NULL)  ||
 | |
|         (IortIdMappingOffset == NULL))
 | |
|     {
 | |
|       IncrementErrorCount ();
 | |
|       Print (
 | |
|         L"ERROR: Insufficient remaining table buffer length to read the " \
 | |
|         L"IORT node header. Length = %d.\n",
 | |
|         AcpiTableLength - Offset
 | |
|         );
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // Validate IORT Node length
 | |
|     if ((*IortNodeLength == 0) ||
 | |
|         ((Offset + (*IortNodeLength)) > AcpiTableLength))
 | |
|     {
 | |
|       IncrementErrorCount ();
 | |
|       Print (
 | |
|         L"ERROR: Invalid IORT Node length. " \
 | |
|         L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",
 | |
|         *IortNodeLength,
 | |
|         Offset,
 | |
|         AcpiTableLength
 | |
|         );
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     PrintFieldName (2, L"* Node Offset *");
 | |
|     Print (L"0x%x\n", Offset);
 | |
| 
 | |
|     switch (*IortNodeType) {
 | |
|       case EFI_ACPI_IORT_TYPE_ITS_GROUP:
 | |
|         DumpIortNodeIts (
 | |
|           NodePtr,
 | |
|           *IortNodeLength
 | |
|           );
 | |
|         break;
 | |
|       case EFI_ACPI_IORT_TYPE_NAMED_COMP:
 | |
|         DumpIortNodeNamedComponent (
 | |
|           NodePtr,
 | |
|           *IortNodeLength,
 | |
|           *IortIdMappingCount,
 | |
|           *IortIdMappingOffset
 | |
|           );
 | |
|         break;
 | |
|       case EFI_ACPI_IORT_TYPE_ROOT_COMPLEX:
 | |
|         DumpIortNodeRootComplex (
 | |
|           NodePtr,
 | |
|           *IortNodeLength,
 | |
|           *IortIdMappingCount,
 | |
|           *IortIdMappingOffset
 | |
|           );
 | |
|         break;
 | |
|       case EFI_ACPI_IORT_TYPE_SMMUv1v2:
 | |
|         DumpIortNodeSmmuV1V2 (
 | |
|           NodePtr,
 | |
|           *IortNodeLength,
 | |
|           *IortIdMappingCount,
 | |
|           *IortIdMappingOffset
 | |
|           );
 | |
|         break;
 | |
|       case EFI_ACPI_IORT_TYPE_SMMUv3:
 | |
|         DumpIortNodeSmmuV3 (
 | |
|           NodePtr,
 | |
|           *IortNodeLength,
 | |
|           *IortIdMappingCount,
 | |
|           *IortIdMappingOffset
 | |
|           );
 | |
|         break;
 | |
|       case EFI_ACPI_IORT_TYPE_PMCG:
 | |
|         DumpIortNodePmcg (
 | |
|           NodePtr,
 | |
|           *IortNodeLength,
 | |
|           *IortIdMappingCount,
 | |
|           *IortIdMappingOffset
 | |
|           );
 | |
|         break;
 | |
|       case EFI_ACPI_IORT_TYPE_RMR:
 | |
|         DumpIortNodeRmr (
 | |
|           NodePtr,
 | |
|           *IortNodeLength,
 | |
|           *IortIdMappingCount,
 | |
|           *IortIdMappingOffset
 | |
|           );
 | |
|         break;
 | |
|       default:
 | |
|         IncrementErrorCount ();
 | |
|         Print (L"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType);
 | |
|     } // switch
 | |
| 
 | |
|     NodePtr += (*IortNodeLength);
 | |
|     Offset  += (*IortNodeLength);
 | |
|   } // while
 | |
| }
 |