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
 | 
						|
}
 |