public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Evan Lloyd <Evan.Lloyd@arm.com>
To: Sami Mujawar <Sami.Mujawar@arm.com>,
	"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: "leif.lindholm@linaro.org" <leif.lindholm@linaro.org>,
	Matteo Carlini <Matteo.Carlini@arm.com>,
	Stephanie Hughes-Fitt <Stephanie.Hughes-Fitt@arm.com>,
	nd <nd@arm.com>
Subject: Re: [staging/dynamictables PATCH 2/2] DynamicTablesPkg: Dynamic Tables Framework
Date: Mon, 19 Mar 2018 16:16:35 +0000	[thread overview]
Message-ID: <HE1PR0801MB17717C3E7021546A0FE652248BD40@HE1PR0801MB1771.eurprd08.prod.outlook.com> (raw)
In-Reply-To: <20180319151847.85204-3-sami.mujawar@arm.com>



> -----Original Message-----
> From: Sami Mujawar [mailto:sami.mujawar@arm.com]
> Sent: 19 March 2018 15:19
> To: edk2-devel@lists.01.org
> Cc: Evan Lloyd <Evan.Lloyd@arm.com>; leif.lindholm@linaro.org; Matteo
> Carlini <Matteo.Carlini@arm.com>; Stephanie Hughes-Fitt
> <Stephanie.Hughes-Fitt@arm.com>; nd <nd@arm.com>
> Subject: [staging/dynamictables PATCH 2/2] DynamicTablesPkg: Dynamic
> Tables Framework
> 
> The dynamic tables framework is designed to generate standardised
> firmware tables that describe the hardware information at
> run-time. A goal of standardised firmware is to have a common
> firmware for a platform capable of booting both Windows and Linux
> operating systems.
> 
> Traditionally the firmware tables are handcrafted using ACPI
> Source Language (ASL), Table Definition Language (TDL) and
> C-code. This approach can be error prone and involves time
> consuming debugging. In addition, it may be desirable to configure
> platform hardware at runtime such as: configuring the number of
> cores available for use by the OS, or turning SoC features ON or
> OFF.
> 
> The dynamic tables framework simplifies this by providing a set
> of standard table generators, that are implemented as libraries.
> These generators query a platform specific component, the
> 'Configuration Manager', to collate the information required
> for generating the tables at run-time.
> 
> The framework also provides the ability to implement custom/OEM
> generators; thereby facilitating support for custom tables. The
> custom generators can also utilize the existing standard generators
> and override any functionality if needed.
> 
> The framework currently implements a set of standard ACPI table
> generators for ARM architecture, that can generate Server Base Boot
> Requirement (SBBR) compliant tables. Support for generating SMBIOS
> tables is planned to be added subsequently. Although, the set
> of standard generators implement the functionality required for ARM
> architecture; the framework is extensible, and support for other
> architectures can be added easily.
> 
> Contributions from the community are invited.
> 
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Evan Lloyd <evan.lloyd@arm.com>
> ---
> 
> DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/AcpiTableFactory/Acpi
> TableFactory.c             |  226 +++
> 
> DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DeviceTreeTableFactor
> y/DeviceTreeTableFactory.c |  225 +++
> 
> DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFactory.
> h                           |  125 ++
> 
> DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFactory
> Dxe.c                        |   84 +
> 
> DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFactory
> Dxe.inf                      |   59 +
> 
> DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/SmbiosTableFactory/S
> mbiosTableFactory.c         |  226 +++
> 
> DynamicTablesPkg/Drivers/DynamicTableManagerDxe/DynamicTableManag
> erDxe.c                        |  533 +++++
> 
> DynamicTablesPkg/Drivers/DynamicTableManagerDxe/DynamicTableManag
> erDxe.inf                      |   48 +
>  DynamicTablesPkg/DynamicTables.dsc.inc
> |   46 +
>  DynamicTablesPkg/DynamicTables.fdf.inc
> |   35 +
>  DynamicTablesPkg/DynamicTablesPkg.dec
> |   42 +
>  DynamicTablesPkg/Include/AcpiTableGenerator.h
> |  282 +++
>  DynamicTablesPkg/Include/ArmNameSpaceObjects.h
> |  587 ++++++
>  DynamicTablesPkg/Include/ConfigurationManagerHelper.h
> |  119 ++
>  DynamicTablesPkg/Include/ConfigurationManagerObject.h
> |  176 ++
>  DynamicTablesPkg/Include/DeviceTreeTableGenerator.h
> |  182 ++
>  DynamicTablesPkg/Include/Library/TableHelperLib.h
> |   70 +
>  DynamicTablesPkg/Include/Protocol/ConfigurationManagerProtocol.h
> |  128 ++
>  DynamicTablesPkg/Include/Protocol/DynamicTableFactoryProtocol.h
> |  140 ++
>  DynamicTablesPkg/Include/SmbiosTableGenerator.h
> |  240 +++
>  DynamicTablesPkg/Include/StandardNameSpaceObjects.h
> |  116 ++
>  DynamicTablesPkg/Include/TableGenerator.h
> |  252 +++
> 
> DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/AcpiDbg2LibArm.inf
> |   47 +
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/Dbg2Generator.c
> |  440 +++++
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/AcpiFadtLibArm.inf
> |   41 +
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/FadtGenerator.c
> |  666 +++++++
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/AcpiGtdtLibArm.inf
> |   41 +
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
> |  670 +++++++
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf
> |   41 +
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
> | 2046 ++++++++++++++++++++
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h
> |   50 +
> 
> DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/AcpiMadtLibArm.in
> f                             |   41 +
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c
> |  717 +++++++
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/AcpiMcfgLibArm.inf
> |   41 +
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/McfgGenerator.c
> |  342 ++++
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibArm.inf
> |   41 +
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/RawGenerator.c
> |  142 ++
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibArm.inf
> |   41 +
>  DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/SpcrGenerator.c
> |  324 ++++
>  DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c
> |  164 ++
>  DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf
> |   35 +
>  41 files changed, 9871 insertions(+)
> 
> diff --git
> a/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/AcpiTableFactory/A
> cpiTableFactory.c
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/AcpiTableFactory/A
> cpiTableFactory.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..425b2f2d8feb959493
> 214d545aaa9b59a0fbeba2
> --- /dev/null
> +++
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/AcpiTableFactory/A
> cpiTableFactory.c
> @@ -0,0 +1,226 @@
> +/** @file
> +  ACPI Table Factory
> +
> +  Copyright (c) 2017, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Std - Standard
> +**/
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +#include <Protocol/DynamicTableFactoryProtocol.h>
> +
> +#include "DynamicTableFactory.h"
> +
> +extern EFI_DYNAMIC_TABLE_FACTORY_INFO TableFactoryInfo;
> +
> +/** Return a pointer to the ACPI table generator.
> +
> +  @param [in]  This         Pointer to the Dynamic Table Factory Protocol.
> +  @param [in]  GeneratorId  The ACPI table generator ID for the
> +                            requested generator.
> +  @param [out] Generator    Pointer to the requested ACPI table
> +                            generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +GetAcpiTableGenerator (
> +  IN  CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST This,
> +  IN  CONST ACPI_TABLE_GENERATOR_ID                     GeneratorId,
> +  OUT CONST ACPI_TABLE_GENERATOR               ** CONST Generator
> +  )
> +{
> +  UINT16                           TableId;
> +  EFI_DYNAMIC_TABLE_FACTORY_INFO * FactoryInfo;
> +
> +  ASSERT (This != NULL);
> +
> +  FactoryInfo = This->TableFactoryInfo;
> +
> +  if (Generator == NULL) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: Invalid Generator pointer\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_GENERATOR_TYPE_ACPI (GeneratorId)) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: Generator Type is not ACPI\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *Generator = NULL;
> +  TableId = GET_TABLE_ID (GeneratorId);
> +  if (IS_GENERATOR_NAMESPACE_STD (GeneratorId)) {
> +    if (TableId >= (ESTD_ACPI_TABLE_ID_MAX)) {
> +      ASSERT (TableId < (ESTD_ACPI_TABLE_ID_MAX));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (FactoryInfo->StdAcpiTableGeneratorList[TableId] != NULL) {
> +      *Generator = FactoryInfo->StdAcpiTableGeneratorList[TableId];
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  } else {
> +    if (TableId >= FixedPcdGet16 (PcdMaxCustomACPIGenerators)) {
> +      ASSERT (TableId < FixedPcdGet16 (PcdMaxCustomACPIGenerators));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (FactoryInfo->CustomAcpiTableGeneratorList[TableId] != NULL) {
> +      *Generator = FactoryInfo->CustomAcpiTableGeneratorList[TableId];
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/** Register ACPI table factory generator.
> +
> +  The ACPI table factory maintains a list of the Standard and OEM ACPI
> +  table generators.
> +
> +  @param [in]  Generator       Pointer to the ACPI table generator.
> +
> +  @retval EFI_SUCCESS           The Generator was registered
> +                                successfully.
> +  @retval EFI_INVALID_PARAMETER The Generator ID is invalid or
> +                                the Generator pointer is NULL.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID is
> +                                already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +RegisterAcpiTableGenerator (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST Generator
> +  )
> +{
> +  UINT16  TableId;
> +
> +  if (Generator == NULL) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: ACPI register - Invalid Generator\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_GENERATOR_TYPE_ACPI (Generator->GeneratorID)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: ACPI register - Generator" \
> +      " Type is not ACPI\n"
> +      ));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "Registering %s\n", Generator->Description));
> +
> +  TableId = GET_TABLE_ID (Generator->GeneratorID);
> +  if (IS_GENERATOR_NAMESPACE_STD (Generator->GeneratorID)) {
> +    if (TableId >= (ESTD_ACPI_TABLE_ID_MAX)) {
> +      ASSERT (TableId < (ESTD_ACPI_TABLE_ID_MAX));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.StdAcpiTableGeneratorList[TableId] == NULL) {
> +      TableFactoryInfo.StdAcpiTableGeneratorList[TableId] = Generator;
> +    } else {
> +      return EFI_ALREADY_STARTED;
> +    }
> +  } else {
> +    if (TableId >= FixedPcdGet16 (PcdMaxCustomACPIGenerators)) {
> +      ASSERT (TableId < FixedPcdGet16 (PcdMaxCustomACPIGenerators));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.CustomAcpiTableGeneratorList[TableId] == NULL) {
> +      TableFactoryInfo.CustomAcpiTableGeneratorList[TableId] = Generator;
> +    } else {
> +      return EFI_ALREADY_STARTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/** Deregister ACPI generator.
> +
> +  This function is called by the ACPI table generator to deregister itself
> +  from the ACPI table factory.
> +
> +  @param [in]  Generator       Pointer to the ACPI table generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER The generator is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +DeregisterAcpiTableGenerator (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST Generator
> +  )
> +{
> +  UINT16  TableId;
> +
> +  if (Generator == NULL) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: ACPI deregister - Invalid
> Generator\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_GENERATOR_TYPE_ACPI (Generator->GeneratorID)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: ACPI deregister - Generator" \
> +      " Type is not ACPI\n"
> +      ));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  TableId = GET_TABLE_ID (Generator->GeneratorID);
> +  if (IS_GENERATOR_NAMESPACE_STD (Generator->GeneratorID)) {
> +    if (TableId >= (ESTD_ACPI_TABLE_ID_MAX)) {
> +      ASSERT (TableId < (ESTD_ACPI_TABLE_ID_MAX));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.StdAcpiTableGeneratorList[TableId] != NULL) {
> +      if (Generator != TableFactoryInfo.StdAcpiTableGeneratorList[TableId]) {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +      TableFactoryInfo.StdAcpiTableGeneratorList[TableId] = NULL;
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  } else {
> +    if (TableId >= FixedPcdGet16 (PcdMaxCustomACPIGenerators)) {
> +      ASSERT (TableId < FixedPcdGet16 (PcdMaxCustomACPIGenerators));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.CustomAcpiTableGeneratorList[TableId] != NULL) {
> +      if (Generator !=
> +          TableFactoryInfo.CustomAcpiTableGeneratorList[TableId]) {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +      TableFactoryInfo.CustomAcpiTableGeneratorList[TableId] = NULL;
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "Deregistering %s\n", Generator->Description));
> +  return EFI_SUCCESS;
> +}
> diff --git
> a/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DeviceTreeTableFact
> ory/DeviceTreeTableFactory.c
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DeviceTreeTableFac
> tory/DeviceTreeTableFactory.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..9e4fa3f8ffce390f3aa8
> 5136f3508e139cca3326
> --- /dev/null
> +++
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DeviceTreeTableFac
> tory/DeviceTreeTableFactory.c
> @@ -0,0 +1,225 @@
> +/** @file
> +  Device Tree Table Factory
> +
> +  Copyright (c) 2017, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Std - Standard
> +**/
> +
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +
> +// Module specific include files.
> +#include <DeviceTreeTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +#include <Protocol/DynamicTableFactoryProtocol.h>
> +
> +#include "DynamicTableFactory.h"
> +
> +extern EFI_DYNAMIC_TABLE_FACTORY_INFO TableFactoryInfo;
> +
> +/** Return a pointer to the DT table generator.
> +
> +  @param [in]  This         Pointer to the Dynamic Table Factory Protocol.
> +  @param [in]  GeneratorId  The DT table generator ID for the
> +                            requested generator.
> +  @param [out] Generator    Pointer to the requested DT table
> +                            generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +GetDtTableGenerator (
> +  IN  CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST This,
> +  IN  CONST DT_TABLE_GENERATOR_ID                       GeneratorId,
> +  OUT CONST DT_TABLE_GENERATOR                 ** CONST Generator
> +  )
> +{
> +  UINT16                           TableId;
> +  EFI_DYNAMIC_TABLE_FACTORY_INFO * FactoryInfo;
> +
> +  ASSERT (This != NULL);
> +
> +  FactoryInfo = This->TableFactoryInfo;
> +
> +  if (Generator == NULL) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: Invalid Generator pointer\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_GENERATOR_TYPE_DT (GeneratorId)) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: Generator Type is not DT\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *Generator = NULL;
> +  TableId = GET_TABLE_ID (GeneratorId);
> +  if (IS_GENERATOR_NAMESPACE_STD (GeneratorId)) {
> +    if (TableId >= (ESTD_DT_TABLE_ID_MAX)) {
> +      ASSERT (TableId < (ESTD_DT_TABLE_ID_MAX));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (FactoryInfo->StdDtTableGeneratorList[TableId] != NULL) {
> +      *Generator = FactoryInfo->StdDtTableGeneratorList[TableId];
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  } else {
> +    if (TableId >= FixedPcdGet16 (PcdMaxCustomDTGenerators)) {
> +      ASSERT (TableId < FixedPcdGet16 (PcdMaxCustomDTGenerators));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (FactoryInfo->CustomDtTableGeneratorList[TableId] != NULL) {
> +      *Generator = FactoryInfo->CustomDtTableGeneratorList[TableId];
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/** Register DT table factory generator.
> +
> +  The DT table factory maintains a list of the Standard and OEM DT
> +  table generators.
> +
> +  @param [in]  Generator       Pointer to the DT table generator.
> +
> +  @retval EFI_SUCCESS           The Generator was registered
> +                                successfully.
> +  @retval EFI_INVALID_PARAMETER The Generator ID is invalid or
> +                                the Generator pointer is NULL.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID is
> +                                already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +RegisterDtTableGenerator (
> +  IN  CONST DT_TABLE_GENERATOR                * CONST Generator
> +  )
> +{
> +  UINT16  TableId;
> +
> +  if (Generator == NULL) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: DT register - Invalid Generator\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_GENERATOR_TYPE_DT (Generator->GeneratorID)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: DT register - Generator" \
> +      " Type is not DT\n"
> +      ));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "Registering %s\n", Generator->Description));
> +
> +  TableId = GET_TABLE_ID (Generator->GeneratorID);
> +  if (IS_GENERATOR_NAMESPACE_STD (Generator->GeneratorID)) {
> +    if (TableId >= (ESTD_DT_TABLE_ID_MAX)) {
> +      ASSERT (TableId < (ESTD_DT_TABLE_ID_MAX));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.StdDtTableGeneratorList[TableId] == NULL) {
> +      TableFactoryInfo.StdDtTableGeneratorList[TableId] = Generator;
> +    } else {
> +      return EFI_ALREADY_STARTED;
> +    }
> +  } else {
> +    if (TableId >= FixedPcdGet16 (PcdMaxCustomDTGenerators)) {
> +      ASSERT (TableId < FixedPcdGet16 (PcdMaxCustomDTGenerators));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.CustomDtTableGeneratorList[TableId] == NULL) {
> +      TableFactoryInfo.CustomDtTableGeneratorList[TableId] = Generator;
> +    } else {
> +      return EFI_ALREADY_STARTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/** Deregister DT generator.
> +
> +  This function is called by the DT table generator to deregister itself
> +  from the DT table factory.
> +
> +  @param [in]  Generator       Pointer to the DT table generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER The generator is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +DeregisterDtTableGenerator (
> +  IN  CONST DT_TABLE_GENERATOR                * CONST Generator
> +  )
> +{
> +  UINT16  TableId;
> +
> +  if (Generator == NULL) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: DT deregister - Invalid Generator\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_GENERATOR_TYPE_DT (Generator->GeneratorID)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: DT deregister - Generator" \
> +      " Type is not DT\n"
> +      ));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  TableId = GET_TABLE_ID (Generator->GeneratorID);
> +  if (IS_GENERATOR_NAMESPACE_STD (Generator->GeneratorID)) {
> +    if (TableId >= (ESTD_DT_TABLE_ID_MAX)) {
> +      ASSERT (TableId < (ESTD_DT_TABLE_ID_MAX));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.StdDtTableGeneratorList[TableId] != NULL) {
> +      if (Generator != TableFactoryInfo.StdDtTableGeneratorList[TableId]) {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +      TableFactoryInfo.StdDtTableGeneratorList[TableId] = NULL;
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  } else {
> +    if (TableId >= FixedPcdGet16 (PcdMaxCustomDTGenerators)) {
> +      ASSERT (TableId < FixedPcdGet16 (PcdMaxCustomDTGenerators));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.CustomDtTableGeneratorList[TableId] != NULL) {
> +      if (Generator !=
> +          TableFactoryInfo.CustomDtTableGeneratorList[TableId]) {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +      TableFactoryInfo.CustomDtTableGeneratorList[TableId] = NULL;
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "Deregistering %s\n", Generator->Description));
> +  return EFI_SUCCESS;
> +}
> diff --git
> a/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFactor
> y.h
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFacto
> ry.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..c0b4a2a11457933b1c
> 86950338f5619111747dc3
> --- /dev/null
> +++
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFacto
> ry.h
> @@ -0,0 +1,125 @@
> +/** @file
> +
> +  Copyright (c) 2017, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Std    - Standard
> +    - ACPI   - Advanced Configuration and Power Interface
> +    - SMBIOS - System Management BIOS
> +    - DT     - Device Tree
> +**/
> +
> +#ifndef DYNAMIC_TABLE_FACTORY_H_
> +#define DYNAMIC_TABLE_FACTORY_H_
> +
> +#pragma pack(1)
> +
> +/** A structure that holds the list of registered ACPI and
> +    SMBIOS table generators.
> +*/
> +typedef struct DynamicTableFactoryInfo {
> +  /// An array for holding the list of Standard ACPI Table  Generators.
> +  CONST ACPI_TABLE_GENERATOR *
> +          StdAcpiTableGeneratorList[ESTD_ACPI_TABLE_ID_MAX];
> +
> +  /// An array for holding the list of Custom ACPI Table Generators.
> +  CONST ACPI_TABLE_GENERATOR *
> +          CustomAcpiTableGeneratorList[FixedPcdGet16 (
> +                                         PcdMaxCustomACPIGenerators
> +                                         )];
> +
> +  /// An array for holding the list of Standard SMBIOS Table Generators.
> +  CONST SMBIOS_TABLE_GENERATOR *
> +          StdSmbiosTableGeneratorList[ESTD_SMBIOS_TABLE_ID_MAX];
> +
> +  /// An array for holding the list of Custom SMBIOS Table Generators.
> +  CONST SMBIOS_TABLE_GENERATOR *
> +          CustomSmbiosTableGeneratorList[FixedPcdGet16 (
> +                                           PcdMaxCustomSMBIOSGenerators
> +                                           )];
> +
> +  /// An array for holding the list of Standard DT Table Generators.
> +  CONST DT_TABLE_GENERATOR *
> +          StdDtTableGeneratorList[ESTD_DT_TABLE_ID_MAX];
> +
> +  /// An array for holding the list of Custom DT Table Generators.
> +  CONST DT_TABLE_GENERATOR *
> +          CustomDtTableGeneratorList[FixedPcdGet16 (
> +                                       PcdMaxCustomDTGenerators
> +                                       )];
> +} EFI_DYNAMIC_TABLE_FACTORY_INFO;
> +
> +/** Return a pointer to the ACPI table generator.
> +
> +  @param [in]  This         Pointer to the Dynamic Table Factory Protocol.
> +  @param [in]  GeneratorId  The ACPI table generator ID for the
> +                            requested generator.
> +  @param [out] Generator    Pointer to the requested ACPI table
> +                            generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +GetAcpiTableGenerator (
> +  IN  CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST This,
> +  IN  CONST ACPI_TABLE_GENERATOR_ID                     GeneratorId,
> +  OUT CONST ACPI_TABLE_GENERATOR               ** CONST Generator
> +  );
> +
> +/** Return a pointer to the SMBIOS table generator.
> +
> +  @param [in]  This         Pointer to the Dynamic Table Factory Protocol.
> +  @param [in]  GeneratorId  The SMBIOS table generator ID for the
> +                            requested generator.
> +  @param [out] Generator    Pointer to the requested SMBIOS table
> +                            generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +GetSmbiosTableGenerator (
> +  IN  CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST This,
> +  IN  CONST SMBIOS_TABLE_GENERATOR_ID                   GeneratorId,
> +  OUT CONST SMBIOS_TABLE_GENERATOR             ** CONST Generator
> +  );
> +
> +/** Return a pointer to the DT table generator.
> +
> +  @param [in]  This         Pointer to the Dynamic Table Factory Protocol.
> +  @param [in]  GeneratorId  The DT table generator ID for the
> +                            requested generator.
> +  @param [out] Generator    Pointer to the requested DT table
> +                            generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +GetDtTableGenerator (
> +  IN  CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST This,
> +  IN  CONST DT_TABLE_GENERATOR_ID                       GeneratorId,
> +  OUT CONST DT_TABLE_GENERATOR                 ** CONST Generator
> +  );
> +
> +#pragma pack()
> +
> +#endif // DYNAMIC_TABLE_FACTORY_H_
> diff --git
> a/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFactor
> yDxe.c
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFacto
> ryDxe.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..6ac291ab29a8f44ed91
> 845f5e6f65e0e5248f80b
> --- /dev/null
> +++
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFacto
> ryDxe.c
> @@ -0,0 +1,84 @@
> +/** @file
> +  Dynamic Table Factory Dxe
> +
> +  Copyright (c) 2017, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <Library/DebugLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <DeviceTreeTableGenerator.h>
> +#include <Library/TableHelperLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +#include <Protocol/DynamicTableFactoryProtocol.h>
> +#include <SmbiosTableGenerator.h>
> +
> +#include "DynamicTableFactory.h"
> +
> +/** The Dynamic Table Factory protocol structure that holds the
> +    list of registered ACPI and SMBIOS table generators.
> +*/
> +EFI_DYNAMIC_TABLE_FACTORY_INFO TableFactoryInfo;
> +
> +/** A structure describing the Dynamic Table Factory protocol.
> +*/
> +STATIC
> +CONST
> +EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL DynamicTableFactoryProtocol
> = {
> +  CREATE_REVISION (1, 0),
> +  GetAcpiTableGenerator,
> +  GetSmbiosTableGenerator,
> +  GetDtTableGenerator,
> +  &TableFactoryInfo
> +};
> +
> +/** Entrypoint for Dynamic Table Factory Dxe.
> +
> +  @param  ImageHandle
> +  @param  SystemTable
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
> +  @retval EFI_NOT_FOUND         Required interface/object was not found.
> +  @retval EFI_INVALID_PARAMETER Some parameter is incorrect/invalid.
> +*/
> +EFI_STATUS
> +EFIAPI
> +DynamicTableFactoryDxeInitialize (
> +  IN  EFI_HANDLE                 ImageHandle,
> +  IN  EFI_SYSTEM_TABLE   * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  Status = gBS->InstallProtocolInterface (
> +                  &ImageHandle,
> +                  &gEfiDynamicTableFactoryProtocolGuid,
> +                  EFI_NATIVE_INTERFACE,
> +                  (VOID*)&DynamicTableFactoryProtocol
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to install the Dynamic Table Factory Protocol." \
> +      " Status = %r\n",
> +      Status
> +      ));
> +  }
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFactor
> yDxe.inf
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFacto
> ryDxe.inf
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..346168d6b1496eb180
> 8565f830b9c0eae4b06f79
> --- /dev/null
> +++
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFacto
> ryDxe.inf
> @@ -0,0 +1,59 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010019
> +  BASE_NAME                      = DynamicTableFactoryDxe
> +  FILE_GUID                      = FE846898-7403-4932-B8AD-A0491F0C2CBA
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = DynamicTableFactoryDxeInitialize
> +
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = ARM AARCH64
> +#
> +
> +[Sources]
> +  AcpiTableFactory/AcpiTableFactory.c
> +  DeviceTreeTableFactory/DeviceTreeTableFactory.c
> +  DynamicTableFactoryDxe.c
> +  SmbiosTableFactory/SmbiosTableFactory.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  MemoryAllocationLib
> +  PrintLib
> +  TableHelperLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +
> +[FixedPcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxCustomACPIGenerators
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxCustomSMBIOSGenerators
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxCustomDTGenerators
> +
> +[Protocols]
> +  gEfiAcpiTableProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED
> +  gEfiSmbiosProtocolGuid                        # PROTOCOL ALWAYS_CONSUMED
> +  gEfiConfigurationManagerProtocolGuid
> +  gEfiDynamicTableFactoryProtocolGuid
> +
> +[Depex]
> +  TRUE
> diff --git
> a/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/SmbiosTableFactory
> /SmbiosTableFactory.c
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/SmbiosTableFactory
> /SmbiosTableFactory.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..01be8cd1ca5371770d
> 179ca1ec12de387bd49cd7
> --- /dev/null
> +++
> b/DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/SmbiosTableFactory
> /SmbiosTableFactory.c
> @@ -0,0 +1,226 @@
> +/** @file
> +  SMBIOS Table Factory
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Std - Standard
> +**/
> +
> +#include <IndustryStandard/SmBios.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +
> +// Module specific include files.
> +#include <SmbiosTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +#include <Protocol/DynamicTableFactoryProtocol.h>
> +
> +#include "DynamicTableFactory.h"
> +
> +extern EFI_DYNAMIC_TABLE_FACTORY_INFO TableFactoryInfo;
> +
> +/** Return a pointer to the SMBIOS table generator.
> +
> +  @param [in]  This         Pointer to the Dynamic Table Factory Protocol.
> +  @param [in]  GeneratorId  The SMBIOS table generator ID for the
> +                            requested generator.
> +  @param [out] Generator    Pointer to the requested SMBIOS table
> +                            generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +GetSmbiosTableGenerator (
> +  IN  CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST This,
> +  IN  CONST SMBIOS_TABLE_GENERATOR_ID                   GeneratorId,
> +  OUT CONST SMBIOS_TABLE_GENERATOR             ** CONST Generator
> +  )
> +{
> +  UINT16                           TableId;
> +  EFI_DYNAMIC_TABLE_FACTORY_INFO * FactoryInfo;
> +
> +  ASSERT (This != NULL);
> +
> +  FactoryInfo = This->TableFactoryInfo;
> +
> +  if (Generator == NULL) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: Invalid Generator pointer\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_GENERATOR_TYPE_SMBIOS (GeneratorId)) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: Generator Type is not SMBIOS\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *Generator = NULL;
> +  TableId = GET_TABLE_ID (GeneratorId);
> +  if (IS_GENERATOR_NAMESPACE_STD (GeneratorId)) {
> +    if (TableId >= (ESTD_SMBIOS_TABLE_ID_MAX)) {
> +      ASSERT (TableId < (ESTD_SMBIOS_TABLE_ID_MAX));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (FactoryInfo->StdSmbiosTableGeneratorList[TableId] != NULL) {
> +      *Generator = FactoryInfo->StdSmbiosTableGeneratorList[TableId];
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  } else {
> +    if (TableId >= FixedPcdGet16 (PcdMaxCustomSMBIOSGenerators)) {
> +      ASSERT (TableId < FixedPcdGet16 (PcdMaxCustomSMBIOSGenerators));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (FactoryInfo->CustomSmbiosTableGeneratorList[TableId] != NULL) {
> +      *Generator = FactoryInfo->CustomSmbiosTableGeneratorList[TableId];
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/** Register SMBIOS table factory generator.
> +
> +  The SMBIOS table factory maintains a list of the Standard and OEM
> SMBIOS
> +  table generators.
> +
> +  @param [in]  Generator       Pointer to the SMBIOS table generator.
> +
> +  @retval EFI_SUCCESS           The Generator was registered
> +                                successfully.
> +  @retval EFI_INVALID_PARAMETER The Generator ID is invalid or
> +                                the Generator pointer is NULL.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID is
> +                                already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +RegisterSmbiosTableGenerator (
> +  IN  CONST SMBIOS_TABLE_GENERATOR              * CONST Generator
> +  )
> +{
> +  UINT16  TableId;
> +
> +  if (Generator == NULL) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: SMBIOS register - Invalid
> Generator\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_GENERATOR_TYPE_SMBIOS (Generator->GeneratorID)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: SMBIOS register - Generator" \
> +      " Type is not SMBIOS\n"
> +      ));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "Registering %s\n", Generator->Description));
> +
> +  TableId = GET_TABLE_ID (Generator->GeneratorID);
> +  if (IS_GENERATOR_NAMESPACE_STD (Generator->GeneratorID)) {
> +    if (TableId >= (ESTD_SMBIOS_TABLE_ID_MAX)) {
> +      ASSERT (TableId < (ESTD_SMBIOS_TABLE_ID_MAX));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.StdSmbiosTableGeneratorList[TableId] == NULL) {
> +      TableFactoryInfo.StdSmbiosTableGeneratorList[TableId] = Generator;
> +    } else {
> +      return EFI_ALREADY_STARTED;
> +    }
> +  } else {
> +    if (TableId >= FixedPcdGet16 (PcdMaxCustomSMBIOSGenerators)) {
> +      ASSERT (TableId < FixedPcdGet16 (PcdMaxCustomSMBIOSGenerators));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.CustomSmbiosTableGeneratorList[TableId] == NULL)
> {
> +      TableFactoryInfo.CustomSmbiosTableGeneratorList[TableId] =
> Generator;
> +    } else {
> +      return EFI_ALREADY_STARTED;
> +    }
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +/** Deregister SMBIOS generator.
> +
> +  This function is called by the SMBIOS table generator to deregister itself
> +  from the SMBIOS table factory.
> +
> +  @param [in]  Generator       Pointer to the SMBIOS table generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER The generator is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +DeregisterSmbiosTableGenerator (
> +  IN  CONST SMBIOS_TABLE_GENERATOR              * CONST Generator
> +  )
> +{
> +  UINT16  TableId;
> +
> +  if (Generator == NULL) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: SMBIOS deregister - Invalid
> Generator\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (!IS_GENERATOR_TYPE_SMBIOS (Generator->GeneratorID)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: SMBIOS deregister - Generator" \
> +      " Type is not SMBIOS\n"
> +      ));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  TableId = GET_TABLE_ID (Generator->GeneratorID);
> +  if (IS_GENERATOR_NAMESPACE_STD (Generator->GeneratorID)) {
> +    if (TableId >= (ESTD_SMBIOS_TABLE_ID_MAX)) {
> +      ASSERT (TableId < (ESTD_SMBIOS_TABLE_ID_MAX));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.StdSmbiosTableGeneratorList[TableId] != NULL) {
> +      if (Generator !=
> TableFactoryInfo.StdSmbiosTableGeneratorList[TableId]) {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +      TableFactoryInfo.StdSmbiosTableGeneratorList[TableId] = NULL;
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  } else {
> +    if (TableId >= FixedPcdGet16 (PcdMaxCustomSMBIOSGenerators)) {
> +      ASSERT (TableId < FixedPcdGet16 (PcdMaxCustomSMBIOSGenerators));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    if (TableFactoryInfo.CustomSmbiosTableGeneratorList[TableId] != NULL)
> {
> +      if (Generator !=
> +          TableFactoryInfo.CustomSmbiosTableGeneratorList[TableId]) {
> +        return EFI_INVALID_PARAMETER;
> +      }
> +      TableFactoryInfo.CustomSmbiosTableGeneratorList[TableId] = NULL;
> +    } else {
> +      return EFI_NOT_FOUND;
> +    }
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "Deregistering %s\n", Generator->Description));
> +  return EFI_SUCCESS;
> +}
> diff --git
> a/DynamicTablesPkg/Drivers/DynamicTableManagerDxe/DynamicTableMan
> agerDxe.c
> b/DynamicTablesPkg/Drivers/DynamicTableManagerDxe/DynamicTableMan
> agerDxe.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..5a3ad21220bd924bab
> ab3ca2a28c87c5a91efa0c
> --- /dev/null
> +++
> b/DynamicTablesPkg/Drivers/DynamicTableManagerDxe/DynamicTableMan
> agerDxe.c
> @@ -0,0 +1,533 @@
> +/** @file
> +  Dynamic Table Manager Dxe
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <Library/DebugLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <DeviceTreeTableGenerator.h>
> +#include <Library/TableHelperLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +#include <Protocol/DynamicTableFactoryProtocol.h>
> +#include <SmbiosTableGenerator.h>
> +
> +/** This macro expands to a function that retrieves the ACPI Table
> +    List from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceStandard,
> +  EStdObjAcpiTableList,
> +  CM_STD_OBJ_ACPI_TABLE_INFO
> +  )
> +
> +/** A helper function to invoke a Table generator
> +
> +  This is a helper function that invokes the Table generator interface
> +  for building an ACPI table. It uses the AcpiTableProtocol to install the
> +  table, then frees the resources allocated for generating it.
> +
> +  @param [in]  TableFactoryProtocol Pointer to the Table Factory Protocol
> +                                    interface.
> +  @param [in]  CfgMgrProtocol       Pointer to the Configuration Manager
> +                                    Protocol Interface.
> +  @param [in]  AcpiTableProtocol    Pointer to the AcpiTable protocol.
> +  @param [in]  AcpiTableInfo        Pointer to the ACPI table Info.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         Required object is not found.
> +  @retval EFI_BAD_BUFFER_SIZE   Size returned by the Configuration
> Manager
> +                                is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildAndInstallAcpiTable (
> +  IN CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST
> TableFactoryProtocol,
> +  IN CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN       EFI_ACPI_TABLE_PROTOCOL             *       AcpiTableProtocol,
> +  IN CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST AcpiTableInfo
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  EFI_STATUS                    Status1;
> +  CONST ACPI_TABLE_GENERATOR  * Generator = NULL;
> +  EFI_ACPI_DESCRIPTION_HEADER * AcpiTable = NULL;
> +  UINTN                         TableHandle;
> +
> +  ASSERT (TableFactoryProtocol != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (AcpiTableProtocol != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "INFO: EStdObjAcpiTableList: Address = 0x%p," \
> +    " TableGeneratorId = 0x%x\n",
> +    AcpiTableInfo,
> +    AcpiTableInfo->TableGeneratorId
> +    ));
> +
> +  Status = TableFactoryProtocol->GetAcpiTableGenerator (
> +                                   TableFactoryProtocol,
> +                                   AcpiTableInfo->TableGeneratorId,
> +                                   &Generator
> +                                   );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Table Generator not found." \
> +      " TableGeneratorId = 0x%x. Status = %r\n",
> +      AcpiTableInfo->TableGeneratorId,
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  ASSERT (Generator != NULL);
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "INFO: Generator found : %s\n",
> +    Generator->Description
> +    ));
> +
> +  if (Generator->BuildAcpiTable == NULL) {
> +    Status = EFI_INVALID_PARAMETER;
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Table Generator does not implement the" \
> +      " ACPI_TABLE_GENERATOR_BUILD_TABLE interface." \
> +      " TableGeneratorId = 0x%x. Status = %r\n",
> +      AcpiTableInfo->TableGeneratorId,
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  Status = Generator->BuildAcpiTable (
> +                        Generator,
> +                        AcpiTableInfo,
> +                        CfgMgrProtocol,
> +                        &AcpiTable
> +                        );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to Build Table." \
> +      " TableGeneratorId = 0x%x. Status = %r\n",
> +      AcpiTableInfo->TableGeneratorId,
> +      Status
> +      ));
> +    // Free any allocated resources.
> +    goto exit_handler;
> +  }
> +
> +  ASSERT (AcpiTable != NULL);
> +
> +  // Dump ACPI Table Header
> +  DUMP_ACPI_TABLE_HEADER (AcpiTable);
> +
> +  // Install ACPI table
> +  Status = AcpiTableProtocol->InstallAcpiTable (
> +                                AcpiTableProtocol,
> +                                AcpiTable,
> +                                AcpiTable->Length,
> +                                &TableHandle
> +                                );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to Install ACPI Table. Status = %r\n",
> +      Status
> +      ));
> +    // Free any allocated resources.
> +    goto exit_handler;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "INFO: ACPI Table installed. Status = %r\n",
> +    Status
> +    ));
> +
> +exit_handler:
> +  // Free any resources allocated for generating the tables.
> +  if (Generator->FreeTableResources != NULL) {
> +    Status1 = Generator->FreeTableResources (
> +                          Generator,
> +                          AcpiTableInfo,
> +                          CfgMgrProtocol,
> +                          &AcpiTable
> +                          );
> +    if (EFI_ERROR (Status1)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: Failed to Free Table Resources." \
> +        "TableGeneratorId = 0x%x. Status = %r\n",
> +        AcpiTableInfo->TableGeneratorId,
> +        Status
> +        ));
> +    }
> +
> +    // Return the first error status in case of failure
> +    if (!EFI_ERROR (Status)) {
> +      Status = Status1;
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/** The function checks if the Configuration Manager has provided the
> +    mandatory ACPI tables for installation.
> +
> +  @param [in]  AcpiTableInfo      Pointer to the ACPI Table Info list.
> +  @param [in]  AcpiTableCount     Count of ACPI Table Info.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_NOT_FOUND         If mandatory table is not found.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +VerifyMandatoryTablesArePresent (
> +  IN CONST CM_STD_OBJ_ACPI_TABLE_INFO  * CONST AcpiTableInfo,
> +  IN       UINT32                              AcpiTableCount
> +  )
> +{
> +  EFI_STATUS  Status = EFI_SUCCESS;
> +  BOOLEAN     FadtFound = FALSE;
> +  BOOLEAN     MadtFound = FALSE;
> +  BOOLEAN     GtdtFound = FALSE;
> +  BOOLEAN     DsdtFound = FALSE;
> +  BOOLEAN     Dbg2Found = FALSE;
> +  BOOLEAN     SpcrFound = FALSE;
> +
> +  ASSERT (AcpiTableInfo != NULL);
> +
> +  while (AcpiTableCount-- != 0) {
> +    switch (AcpiTableInfo[AcpiTableCount].AcpiTableSignature) {
> +      case EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
> +        FadtFound = TRUE;
> +        break;
> +      case EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
> +        MadtFound = TRUE;
> +        break;
> +      case EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE:
> +        GtdtFound = TRUE;
> +        break;
> +      case
> EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
> +        DsdtFound = TRUE;
> +        break;
> +      case EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE:
> +        Dbg2Found = TRUE;
> +        break;
> +      case
> EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE:
> +        SpcrFound = TRUE;
> +        break;
> +      default:
> +        break;
> +    }
> +  }
> +
> +  // We need at least the FADT, MADT, GTDT and the DSDT tables to boot
> +  if (!FadtFound) {
> +    DEBUG ((DEBUG_ERROR,"ERROR: FADT Table not found\n"));
> +    Status = EFI_NOT_FOUND;
> +  }
> +  if (!MadtFound) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: MADT Table not found.\n"));
> +    Status = EFI_NOT_FOUND;
> +  }
> +  if (!GtdtFound) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: GTDT Table not found.\n"));
> +    Status = EFI_NOT_FOUND;
> +  }
> +  if (!DsdtFound) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: DSDT Table not found.\n"));
> +    Status = EFI_NOT_FOUND;
> +  }
> +  if (!Dbg2Found) {
> +    DEBUG ((DEBUG_WARN, "WARNING: DBG2 Table not found.\n"));
> +  }
> +  if (!SpcrFound) {
> +    DEBUG ((DEBUG_WARN, "WARNING: SPCR Table not found.\n"));
> +  }
> +  return Status;
> +}
> +
> +/** Generate and install ACPI tables.
> +
> +  The function gathers the information necessary for installing the
> +  ACPI tables from the Configuration Manager, invokes the generators
> +  and installs them (via BuildAndInstallAcpiTable).
> +
> +  @param [in]  TableFactoryProtocol Pointer to the Table Factory Protocol
> +                                    interface.
> +  @param [in]  CfgMgrProtocol       Pointer to the Configuration Manager
> +                                    Protocol Interface.
> +
> +  @retval EFI_SUCCESS   Success.
> +  @retval EFI_NOT_FOUND If a mandatory table or a generator is not
> found.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +ProcessAcpiTables (
> +  IN CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST
> TableFactoryProtocol,
> +  IN CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  EFI_ACPI_TABLE_PROTOCOL     * AcpiTableProtocol;
> +  CM_STD_OBJ_ACPI_TABLE_INFO  * AcpiTableInfo;
> +  UINT32                        AcpiTableCount;
> +  UINT32                        idx;
> +
> +  ASSERT (TableFactoryProtocol != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +
> +  // Find the AcpiTable protocol
> +  Status = gBS->LocateProtocol (
> +                  &gEfiAcpiTableProtocolGuid,
> +                  NULL,
> +                  (VOID**)&AcpiTableProtocol
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to find AcpiTable protocol. Status = %r\n",
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  Status = GetEStdObjAcpiTableList (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &AcpiTableInfo,
> +             &AcpiTableCount
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to get ACPI Table List. Status = %r\n",
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  if (0 == AcpiTableCount) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: EStdObjAcpiTableList: AcpiTableCount = %d\n",
> +      AcpiTableCount
> +      ));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "INFO: EStdObjAcpiTableList: AcpiTableCount = %d\n",
> +    AcpiTableCount
> +    ));
> +
> +  // Check if mandatory ACPI tables are present.
> +  Status = VerifyMandatoryTablesArePresent (
> +             AcpiTableInfo,
> +             AcpiTableCount
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to find mandatory ACPI Table(s)."
> +      " Status = %r\n",
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  // Add the FADT Table first.
> +  for (idx = 0; idx < AcpiTableCount; idx++) {
> +    if (CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_FADT) ==
> +        AcpiTableInfo[idx].TableGeneratorId) {
> +      Status = BuildAndInstallAcpiTable (
> +                 TableFactoryProtocol,
> +                 CfgMgrProtocol,
> +                 AcpiTableProtocol,
> +                 &AcpiTableInfo[idx]
> +                 );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "ERROR: Failed to find build and install ACPI FADT Table." \
> +          " Status = %r\n",
> +          Status
> +          ));
> +        return Status;
> +      }
> +      break;
> +    }
> +  } // for
> +
> +  // Add remaining ACPI Tables
> +  for (idx = 0; idx < AcpiTableCount; idx++) {
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "INFO: AcpiTableInfo[%d].TableGeneratorId = 0x%x\n",
> +      idx,
> +      AcpiTableInfo[idx].TableGeneratorId
> +      ));
> +
> +    // Skip FADT Table since we have already added
> +    if (CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_FADT) ==
> +        AcpiTableInfo[idx].TableGeneratorId) {
> +      continue;
> +    }
> +
> +    // Skip the Reserved table Generator ID
> +    if ((CREATE_STD_ACPI_TABLE_GEN_ID
> (ESTD_ACPI_TABLE_ID_RESERVED) >=
> +           AcpiTableInfo[idx].TableGeneratorId)                     ||
> +        (CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_MAX)
> <=
> +           AcpiTableInfo[idx].TableGeneratorId)) {
> +      DEBUG ((
> +        DEBUG_WARN,
> +        "WARNING: Invalid ACPI Generator table ID = 0x%x, Skipping...\n",
> +        AcpiTableInfo[idx].TableGeneratorId
> +        ));
> +      continue;
> +    }
> +
> +    Status = BuildAndInstallAcpiTable (
> +               TableFactoryProtocol,
> +               CfgMgrProtocol,
> +               AcpiTableProtocol,
> +               &AcpiTableInfo[idx]
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: Failed to find, build, and install ACPI Table." \
> +        " Status = %r\n",
> +        Status
> +        ));
> +      return Status;
> +    }
> +  } // for
> +
> +  return Status;
> +}
> +
> +/** Entrypoint of Dynamic Table Manager Dxe.
> +
> +  The Dynamic Table Manager uses the Configuration Manager Protocol
> +  to get the list of ACPI and SMBIOS tables to install. For each table
> +  in the list it requests the corresponding ACPI/SMBIOS table factory for
> +  a generator capable of building the ACPI/SMBIOS table.
> +  If a suitable table generator is found, it invokes the generator interface
> +  to build the table. The Dynamic Table Manager then installs the
> +  table and invokes another generator interface to free any resources
> +  allocated for building the table.
> +
> +  @param  ImageHandle
> +  @param  SystemTable
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
> +  @retval EFI_NOT_FOUND         Required interface/object was not found.
> +  @retval EFI_INVALID_PARAMETER Some parameter is incorrect/invalid.
> +*/
> +EFI_STATUS
> +EFIAPI
> +DynamicTableManagerDxeInitialize (
> +  IN CONST EFI_HANDLE                 ImageHandle,
> +  IN       EFI_SYSTEM_TABLE   * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS                               Status;
> +  EFI_CONFIGURATION_MANAGER_PROTOCOL     * CfgMgrProtocol;
> +  CM_STD_OBJ_CONFIGURATION_MANAGER_INFO  * CfgMfrInfo;
> +  EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL     * TableFactoryProtocol;
> +
> +  // Locate the Dynamic Table Factory
> +  Status = gBS->LocateProtocol (
> +                  &gEfiDynamicTableFactoryProtocolGuid,
> +                  NULL,
> +                  (VOID**)&TableFactoryProtocol
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to find Dynamic Table Factory protocol." \
> +      " Status = %r\n",
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  // Locate the Configuration Manager for the Platform
> +  Status = gBS->LocateProtocol (
> +                  &gEfiConfigurationManagerProtocolGuid,
> +                  NULL,
> +                  (VOID**)&CfgMgrProtocol
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to find Configuration Manager protocol. Status = %r\n",
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  Status = GetCgfMgrInfo (CfgMgrProtocol, &CfgMfrInfo);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to get Configuration Manager info. Status = %r\n",
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "INFO: Configuration Manager Version = 0x%x, OemID
> = %c%c%c%c%c%c\n",
> +    CfgMfrInfo->Revision,
> +    CfgMfrInfo->OemId[0],
> +    CfgMfrInfo->OemId[1],
> +    CfgMfrInfo->OemId[2],
> +    CfgMfrInfo->OemId[3],
> +    CfgMfrInfo->OemId[4],
> +    CfgMfrInfo->OemId[5]
> +    ));
> +
> +  Status = ProcessAcpiTables (TableFactoryProtocol, CfgMgrProtocol);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: ACPI Table processing failure. Status = %r\n",
> +      Status
> +      ));
> +  }
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Drivers/DynamicTableManagerDxe/DynamicTableMan
> agerDxe.inf
> b/DynamicTablesPkg/Drivers/DynamicTableManagerDxe/DynamicTableMan
> agerDxe.inf
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..d006587a0119a8d5b4
> 33e3c651320d1c6e86f0f9
> --- /dev/null
> +++
> b/DynamicTablesPkg/Drivers/DynamicTableManagerDxe/DynamicTableMan
> agerDxe.inf
> @@ -0,0 +1,48 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010019
> +  BASE_NAME                      = DynamicTableManagerDxe
> +  FILE_GUID                      = 89122868-BCFD-49E8-88A3-06635CB7B3CF
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = DynamicTableManagerDxeInitialize
> +
> +#
> +# The following information is for reference only and not required by the
> build tools.
> +#
> +#  VALID_ARCHITECTURES           = ARM AARCH64
> +#
> +
> +[Sources]
> +  DynamicTableManagerDxe.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  PrintLib
> +  TableHelperLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +
> +[Protocols]
> +  gEfiAcpiTableProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED
> +  gEfiConfigurationManagerProtocolGuid
> +  gEfiDynamicTableFactoryProtocolGuid
> +
> +[Depex]
> +  TRUE
> diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc
> b/DynamicTablesPkg/DynamicTables.dsc.inc
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..b89ea0c004710ebe98
> 34ac94a459bc98f9e1b5af
> --- /dev/null
> +++ b/DynamicTablesPkg/DynamicTables.dsc.inc
> @@ -0,0 +1,46 @@
> +## @file
> +#  Dsc include file for Dynamic Tables Framework.
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +##
> +
> +[Defines]
> +
> +[BuildOptions]
> +  *_*_*_ASL_FLAGS          = -tc -li
> +
> +[LibraryClasses.common]
> +
> +[Components.common]
> +  #
> +  # Dynamic Table Factory Dxe
> +  #
> +
> DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFactory
> Dxe.inf {
> +    <LibraryClasses>
> +
> TableHelperLib|DynamicTablesPkg/Library/Common/TableHelperLib/Table
> HelperLib.inf
> +
> NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibAr
> m.inf
> +
> NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/AcpiFadtLibAr
> m.inf
> +
> NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/AcpiMadtLib
> Arm.inf
> +
> NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/AcpiGtdtLibAr
> m.inf
> +
> NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibAr
> m.inf
> +
> NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/AcpiDbg2LibA
> rm.inf
> +
> NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/AcpiMcfgLibA
> rm.inf
> +
> NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm
> .inf
> +  }
> +
> +  #
> +  # Dynamic Tables Manager Dxe
> +  #
> +
> DynamicTablesPkg/Drivers/DynamicTableManagerDxe/DynamicTableManag
> erDxe.inf {
> +    <LibraryClasses>
> +
> TableHelperLib|DynamicTablesPkg/Library/Common/TableHelperLib/Table
> HelperLib.inf
> +  }
> diff --git a/DynamicTablesPkg/DynamicTables.fdf.inc
> b/DynamicTablesPkg/DynamicTables.fdf.inc
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..51229c1cbfecae3ba14
> 0f38a43fa67f11d716c58
> --- /dev/null
> +++ b/DynamicTablesPkg/DynamicTables.fdf.inc
> @@ -0,0 +1,35 @@
> +## @file
> +#  fdf include file for Dynamic Tables Framework.
> +#
> +#  Copyright (c) 2017, ARM Limited. All rights reserved.<BR>
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +##
> +
> +#########################################################
> #######################
> +#
> +# FV Section
> +#
> +# [FV] section is used to define what components or modules are placed
> within a flash
> +# device file.  This section also defines order the components and modules
> are positioned
> +# within the image.  The [FV] section consists of define statements, set
> statements and
> +# module statements.
> +#
> +#########################################################
> #######################
> +
> +  #
> +  # Dynamic Table Factory Dxe
> +  #
> +  INF
> DynamicTablesPkg/Drivers/DynamicTableFactoryDxe/DynamicTableFactory
> Dxe.inf
> +
> +  #
> +  # Dynamic Tables Dxe
> +  #
> +  INF
> DynamicTablesPkg/Drivers/DynamicTableManagerDxe/DynamicTableManag
> erDxe.inf
> diff --git a/DynamicTablesPkg/DynamicTablesPkg.dec
> b/DynamicTablesPkg/DynamicTablesPkg.dec
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..4ac88d12aa47f6a22f2
> c2b0e2d8dc64e28cff1fd
> --- /dev/null
> +++ b/DynamicTablesPkg/DynamicTablesPkg.dec
> @@ -0,0 +1,42 @@
> +## @file  DynamicTablesPkg.dec
> +#
> +# Copyright (c) 2017, ARM Limited. All rights reserved.<BR>
> +#
> +# This program and the accompanying materials are licensed and made
> available under
> +# the terms and conditions of the BSD License that accompanies this
> distribution.
> +# The full text of the license may be found at
> +# http://opensource.org/licenses/bsd-license.php.
> +#
> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +#
> +##
> +
> +[Defines]
> +  DEC_SPECIFICATION              = 0x00010005
> +  PACKAGE_NAME                   = DynamicTablesPkg
> +  PACKAGE_GUID                   = 188EB346-8ABA-460E-A105-0F9D76F7324A
> +  PACKAGE_VERSION                = 1.0
> +
> +[Includes]
> +  Include
> +
> +[Protocols]
> +
> +  # Configuration Manager Protocol GUID
> +  gEfiConfigurationManagerProtocolGuid = { 0xd85a4835, 0x5a82, 0x4894,
> { 0xac, 0x2, 0x70, 0x6f, 0x43, 0xd5, 0x97, 0x8e } }
> +
> +  # Dynamic Table Factory Protocol GUID
> +  gEfiDynamicTableFactoryProtocolGuid = { 0x91d1e327, 0xfe5a, 0x49b8,
> { 0xab, 0x65, 0xe, 0xce, 0x2d, 0xdb, 0x45, 0xec } }
> +
> +[PcdsFixedAtBuild]
> +
> +  # Maximum number of Custom ACPI Generators
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdMaxCustomACPIGenerators|1|UIN
> T16|0xC0000001
> +
> +  # Maximum number of Custom SMBIOS Generators
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdMaxCustomSMBIOSGenerators|1|
> UINT16|0xC0000002
> +
> +  # Maximum number of Custom DT Generators
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdMaxCustomDTGenerators|1|UINT1
> 6|0xC0000003
> +
> diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h
> b/DynamicTablesPkg/Include/AcpiTableGenerator.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..89fa713134857e2264
> 0b7a6f1f63a485048b7a72
> --- /dev/null
> +++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h
> @@ -0,0 +1,282 @@
> +/** @file
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Cm or CM   - Configuration Manager
> +    - Obj or OBJ - Object
> +    - Std or STD - Standard
> +**/
> +
> +#ifndef ACPI_TABLE_GENERATOR_H_
> +#define ACPI_TABLE_GENERATOR_H_
> +
> +#include <IndustryStandard/Acpi.h>
> +
> +// Module specific include files.
> +#include <TableGenerator.h>
> +
> +#pragma pack(1)
> +
> +/**
> +The Dynamic Tables Framework provisions two classes of ACPI table
> +generators.
> + - Standard generators: The ACPI table generators implemented by the
> +                        Dynamic Tables Framework.
> + - OEM generators:      The ACPI table generators customized by the OEM.
> +
> +The Dynamic Tables Framework implements the following ACPI table
> generators:
> +  - RAW   : This is the simplest ACPI table generator. It simply installs
> +            the ACPI table provided in the AcpiTableData member of the
> +            CM_STD_OBJ_ACPI_TABLE_INFO. The ACPI table data is provided
> by
> +            the Configuration Manager and is generated using an
> implementation
> +            defined mechanism.
> +  - DSDT  : The DSDT generator is a clone of the RAW generator. The
> difference
> +            is in the way the ACPI Table Data is generated from an AML file.
> +  - SSDT  : The SSDT generator is a clone of the RAW generator. The
> difference
> +            is in the way the ACPI Table Data is generated from an AML file.
> +  - FADT  : The FADT generator collates the required platform information
> from
> +            the Configuration Manager and builds the FADT table.
> +  - MADT  : The MADT generator collates the GIC information  from the
> +            Configuration Manager and builds the MADT table.
> +  - GTDT  : The GTDT generator collates the Timer information from the
> +            Configuration Manager and builds the GTDT table.
> +  - DBG2  : The DBG2 generator collates the debug serial port information
> from
> +            the Configuration Manager and builds the DBG2 table.
> +  - SPCR  : The SPCR generator collates the serial port information from the
> +            Configuration Manager and builds the SPCR table.
> +  - MCFG  : The MCFG generator collates the PCI configuration space
> information
> +            from the Configuration Manager and builds the MCFG table.
> +  - IORT  : The IORT generator collates the IO Topology information from
> the
> +            Configuration Manager and builds the IORT table.
> +*/
> +
> +/** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator
> ID.
> +*/
> +typedef TABLE_GENERATOR_ID ACPI_TABLE_GENERATOR_ID;
> +
> +/** The ESTD_ACPI_TABLE_ID enum describes the ACPI table IDs reserved
> for
> +  the standard generators.
> +*/
> +typedef enum StdAcpiTableId {
> +  ESTD_ACPI_TABLE_ID_RESERVED = 0x0000,             ///< Reserved
> +  ESTD_ACPI_TABLE_ID_RAW,                           ///< RAW Generator
> +  ESTD_ACPI_TABLE_ID_DSDT = ESTD_ACPI_TABLE_ID_RAW, ///< DSDT
> Generator
> +  ESTD_ACPI_TABLE_ID_SSDT = ESTD_ACPI_TABLE_ID_RAW, ///< SSDT
> Generator
> +  ESTD_ACPI_TABLE_ID_FADT,                          ///< FADT Generator
> +  ESTD_ACPI_TABLE_ID_MADT,                          ///< MADT Generator
> +  ESTD_ACPI_TABLE_ID_GTDT,                          ///< GTDT Generator
> +  ESTD_ACPI_TABLE_ID_DBG2,                          ///< DBG2 Generator
> +  ESTD_ACPI_TABLE_ID_SPCR,                          ///< SPCR Generator
> +  ESTD_ACPI_TABLE_ID_MCFG,                          ///< MCFG Generator
> +  ESTD_ACPI_TABLE_ID_IORT,                          ///< IORT Generator
> +  ESTD_ACPI_TABLE_ID_MAX
> +} ESTD_ACPI_TABLE_ID;
> +
> +/** This macro checks if the Table Generator ID is for an ACPI Table
> Generator.
> +
> +  @param [in] TableGeneratorId  The table generator ID.
> +
> +  @returns TRUE if the table generator ID is for an ACPI Table
> +        Generator.
> +*/
> +#define IS_GENERATOR_TYPE_ACPI(TableGeneratorId) \
> +          (GET_TABLE_TYPE (TableGeneratorId) == ETableGeneratorTypeAcpi)
> +
> +/** This macro checks if the Table Generator ID is for a standard ACPI
> +    Table Generator.
> +
> +  @param [in] TableGeneratorId  The table generator ID.
> +
> +  @returns TRUE if the table generator ID is for a standard ACPI
> +          Table Generator.
> +*/
> +#define IS_VALID_STD_ACPI_GENERATOR_ID(TableGeneratorId)               \
> +          (                                                            \
> +          IS_GENERATOR_NAMESPACE_STD (TableGeneratorId) &&             \
> +          IS_GENERATOR_TYPE_ACPI (TableGeneratorId)     &&             \
> +          ((GET_TABLE_ID (GeneratorId) >= ESTD_ACPI_TABLE_ID_RAW) &&   \
> +           (GET_TABLE_ID (GeneratorId) < ESTD_ACPI_TABLE_ID_MAX))      \
> +          )
> +
> +/** This macro creates a standard ACPI Table Generator ID.
> +
> +  @param [in] TableId  The table generator ID.
> +
> +  @returns a standard ACPI table generator ID.
> +*/
> +#define CREATE_STD_ACPI_TABLE_GEN_ID(TableId) \
> +          CREATE_TABLE_GEN_ID (               \
> +            ETableGeneratorTypeAcpi,          \
> +            ETableGeneratorNameSpaceStd,      \
> +            TableId                           \
> +            )
> +
> +/** The Creator ID for the ACPI tables generated using
> +  the standard ACPI table generators.
> +*/
> +#define TABLE_GENERATOR_CREATOR_ID_ARM  SIGNATURE_32('A', 'R',
> 'M', 'H')
> +
> +/** A macro to initialise the common header part of EFI ACPI tables as
> +    defined by the EFI_ACPI_DESCRIPTION_HEADER structure.
> +
> +  @param [in] Signature The ACPI table signature.
> +  @param [in] Type      The ACPI table structure.
> +  @param [in] Revision  The ACPI table revision.
> +*/
> +#define ACPI_HEADER(Signature, Type, Revision) {              \
> +          Signature,             /* UINT32  Signature */      \
> +          sizeof (Type),         /* UINT32  Length */         \
> +          Revision,              /* UINT8   Revision */       \
> +          0,                     /* UINT8   Checksum */       \
> +          { 0, 0, 0, 0, 0, 0 },  /* UINT8   OemId[6] */       \
> +          0,                     /* UINT64  OemTableId */     \
> +          0,                     /* UINT32  OemRevision */    \
> +          0,                     /* UINT32  CreatorId */      \
> +          0                      /* UINT32  CreatorRevision */\
> +          }
> +
> +/** A macro to dump the common header part of EFI ACPI tables as
> +    defined by the EFI_ACPI_DESCRIPTION_HEADER structure.
> +
> +  @param [in] AcpiHeader The pointer to the ACPI table header.
> +*/
> +#define DUMP_ACPI_TABLE_HEADER(AcpiHeader)                        \
> +          DEBUG ((                                                \
> +            DEBUG_INFO,                                           \
> +            "ACPI TABLE %c%c%c%c : Rev 0x%x : Length : 0x%x\n",   \
> +            (AcpiHeader->Signature & 0xFF),                       \
> +            ((AcpiHeader->Signature >> 8) & 0xFF),                \
> +            ((AcpiHeader->Signature >> 16) & 0xFF),               \
> +            ((AcpiHeader->Signature >> 24) & 0xFF),               \
> +            AcpiHeader->Revision,                                 \
> +            AcpiHeader->Length                                    \
> +            ));
> +
> +/** Forward declarations.
> +*/
> +typedef struct ConfigurationManagerProtocol
> EFI_CONFIGURATION_MANAGER_PROTOCOL;
> +typedef struct CmAStdObjAcpiTableInfo
> CM_STD_OBJ_ACPI_TABLE_INFO;
> +typedef struct AcpiTableGenerator           ACPI_TABLE_GENERATOR;
> +
> +/** This function pointer describes the interface to ACPI table build
> +    functions provided by the ACPI table generator and called by the
> +    Table Manager to build an ACPI table.
> +
> +  @param [in]  This            Pointer to the ACPI table generator.
> +  @param [in]  AcpiTableInfo   Pointer to the ACPI table information.
> +  @param [in]  CfgMgrProtocol  Pointer to the Configuration Manager
> +                               Protocol interface.
> +  @param [out] Table           Pointer to the generated ACPI table.
> +
> +  @returns  EFI_SUCCESS If the table is generated successfully or other
> +                        failure codes as returned by the generator.
> +*/
> +typedef EFI_STATUS (*ACPI_TABLE_GENERATOR_BUILD_TABLE) (
> +  IN  CONST ACPI_TABLE_GENERATOR                *       This,
> +  IN  CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST AcpiTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       EFI_ACPI_DESCRIPTION_HEADER        **       Table
> +  );
> +
> +/** This function pointer describes the interface used by the
> +    Table Manager to give the generator an opportunity to free
> +    any resources allocated for building the ACPI table.
> +
> +  @param [in]      This           Pointer to the ACPI table generator.
> +  @param [in]      AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]      CfgMgrProtocol Pointer to the Configuration Manager
> +                                  Protocol Interface.
> +  @param [in, out] Table          Pointer to the ACPI Table.
> +
> +  @returns EFI_SUCCESS  If freed successfully or other failure codes
> +                        as returned by the generator.
> +*/
> +typedef EFI_STATUS (*ACPI_TABLE_GENERATOR_FREE_TABLE) (
> +  IN      CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN      CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST
> AcpiTableInfo,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN OUT        EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  );
> +
> +/** The ACPI_TABLE_GENERATOR structure provides an interface that the
> +    Table Manager can use to invoke the functions to build ACPI tables.
> +*/
> +typedef struct AcpiTableGenerator {
> +  /// The ACPI table generator ID.
> +  ACPI_TABLE_GENERATOR_ID                GeneratorID;
> +
> +  /// String describing the ACPI table generator.
> +  CONST CHAR16                         * Description;
> +
> +  /// The ACPI table signature.
> +  UINT32                                 AcpiTableSignature;
> +
> +  /// The ACPI table revision.
> +  UINT32                                 AcpiTableRevision;
> +
> +  /// The ACPI table creator ID.
> +  UINT32                                 CreatorId;
> +
> +  /// The ACPI table creator revision.
> +  UINT32                                 CreatorRevision;
> +
> +  /// ACPI table build function pointer.
> +  ACPI_TABLE_GENERATOR_BUILD_TABLE       BuildAcpiTable;
> +
> +  /** The function to free any resources
> +      allocated for building the ACPI table.
> +  */
> +  ACPI_TABLE_GENERATOR_FREE_TABLE        FreeTableResources;
> +} ACPI_TABLE_GENERATOR;
> +
> +/** Register ACPI table factory generator.
> +
> +  The ACPI table factory maintains a list of the Standard and OEM ACPI
> +  table generators.
> +
> +  @param [in]  Generator       Pointer to the ACPI table generator.
> +
> +  @retval EFI_SUCCESS           The Generator was registered
> +                                successfully.
> +  @retval EFI_INVALID_PARAMETER The Generator ID is invalid or
> +                                the Generator pointer is NULL.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID is
> +                                already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +RegisterAcpiTableGenerator (
> +  IN CONST ACPI_TABLE_GENERATOR                 * CONST Generator
> +  );
> +
> +/** Deregister ACPI generator.
> +
> +  This function is called by the ACPI table generator to deregister itself
> +  from the ACPI table factory.
> +
> +  @param [in]  Generator       Pointer to the ACPI table generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER The generator is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +DeregisterAcpiTableGenerator (
> +  IN CONST ACPI_TABLE_GENERATOR                 * CONST Generator
> +  );
> +
> +#pragma pack()
> +
> +#endif // ACPI_TABLE_GENERATOR_H_
> +
> diff --git a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
> b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..abbd624eb026d14d22
> 80d766bf68633c60436829
> --- /dev/null
> +++ b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
> @@ -0,0 +1,587 @@
> +/** @file
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Cm or CM   - Configuration Manager
> +    - Obj or OBJ - Object
> +    - Std or STD - Standard
> +**/
> +
> +#ifndef ARM_NAMESPACE_OBJECTS_H_
> +#define ARM_NAMESPACE_OBJECTS_H_
> +
> +#include <StandardNameSpaceObjects.h>
> +
> +#pragma pack(1)
> +
> +/** The EARM_OBJECT_ID enum describes the Object IDs
> +    in the ARM Namespace
> +*/
> +typedef enum ArmObjectID {
> +  EArmObjReserved,                    ///<  0 - Reserved
> +  EArmObjBootArchInfo,                ///<  1 - Boot Architecture Info
> +  EArmObjCpuInfo,                     ///<  2 - CPU Info
> +  EArmObjPowerManagementProfileInfo,  ///<  3 - Power Management
> Profile Info
> +  EArmObjGicCInfo,                    ///<  4 - GIC CPU Interface Info
> +  EArmObjGicDInfo,                    ///<  5 - GIC Distributor Info
> +  EArmObjGicMsiFrameInfo,             ///<  6 - GIC MSI Frame Info
> +  EArmObjGicRedistributorInfo,        ///<  7 - GIC Redistributor Info
> +  EArmObjGicItsInfo,                  ///<  8 - GIC ITS Info
> +  EArmObjSerialConsolePortInfo,       ///<  9 - Serial Console Port Info
> +  EArmObjSerialDebugPortInfo,         ///< 10 - Serial Debug Port Info
> +  EArmObjGenericTimerInfo,            ///< 11 - Generic Timer Info
> +  EArmObjPlatformGTBlockInfo,         ///< 12 - Platform GT Block Info
> +  EArmObjGTBlockTimerFrameInfo,       ///< 13 - Generic Timer Block Frame
> Info
> +  EArmObjPlatformGenericWatchdogInfo, ///< 14 - Platform Generic
> Watchdog
> +  EArmObjPciConfigSpaceInfo,          ///< 15 - PCI Configuration Space Info
> +  EArmObjHypervisorVendorIdentity,    ///< 16 - Hypervisor Vendor Id
> +  EArmObjFixedFeatureFlags,           ///< 17 - Fixed feature flags for FADT
> +  EArmObjItsGroup,                    ///< 18 - ITS Group
> +  EArmObjNamedComponent,              ///< 19 - Named Component
> +  EArmObjRootComplex,                 ///< 20 - Root Complex
> +  EArmObjSmmuV1SmmuV2,                ///< 21 - SMMUv1 or SMMUv2
> +  EArmObjSmmuV3,                      ///< 22 - SMMUv3
> +  EArmObjPmcg,                        ///< 23 - PMCG
> +  EArmObjGicItsIdentifierArray,       ///< 24 - GIC ITS Identifier Array
> +  EArmObjIdMapping,                   ///< 25 - ID Mapping
> +  EArmObjSmmuInterruptArray,          ///< 26 - SMMU Interrupt Array
> +  EArmObjMax
> +} EARM_OBJECT_ID;
> +
> +/** A structure that describes the
> +    ARM Boot Architecture flags.
> +*/
> +typedef struct CmArmBootArchInfo {
> +  /** This is the ARM_BOOT_ARCH flags field of the FADT Table
> +      described in the ACPI Table Specification.
> +  */
> +  UINT32  BootArchFlags;
> +} CM_ARM_BOOT_ARCH_INFO;
> +
> +typedef struct CmArmCpuInfo {
> +  // Reserved for use when SMBIOS tables are implemented
> +} CM_ARM_CPU_INFO;
> +
> +typedef struct CmArmCpuInfoList {
> +  UINT32             CpuCount;
> +  CM_ARM_CPU_INFO  * CpuInfo;
> +} CM_ARM_CPU_INFO_LIST;
> +
> +/** A structure that describes the
> +    Power Management Profile Information for the Platform.
> +*/
> +typedef struct CmArmPowerManagementProfileInfo {
> +  /** This is the Preferred_PM_Profile field of the FADT Table
> +      described in the ACPI Specification
> +  */
> +  UINT8  PowerManagementProfile;
> +} CM_ARM_POWER_MANAGEMENT_PROFILE_INFO;
> +
> +/** A structure that describes the
> +    GIC CPU Interface for the Platform.
> +*/
> +typedef struct CmArmGicCInfo {
> +  /// The GIC CPU Interface number.
> +  UINT32  CPUInterfaceNumber;
> +
> +  /** The ACPI Processor UID. This must match the
> +      _UID of the CPU Device object information described
> +      in the DSDT/SSDT for the CPU.
> +  */
> +  UINT32  AcpiProcessorUid;
> +
> +  /** The flags field as described by the GICC structure
> +      in the ACPI Specification.
> +  */
> +  UINT32  Flags;
> +
> +  /** The parking protocol version field as described by
> +    the GICC structure in the ACPI Specification.
> +  */
> +  UINT32  ParkingProtocolVersion;
> +
> +  /** The Performance Interrupt field as described by
> +      the GICC structure in the ACPI Specification.
> +  */
> +  UINT32  PerformanceInterruptGsiv;
> +
> +  /** The CPU Parked address field as described by
> +      the GICC structure in the ACPI Specification.
> +  */
> +  UINT64  ParkedAddress;
> +
> +  /** The base address for the GIC CPU Interface
> +      as described by the GICC structure in the
> +      ACPI Specification.
> +  */
> +  UINT64  PhysicalBaseAddress;
> +
> +  /** The base address for GICV interface
> +      as described by the GICC structure in the
> +      ACPI Specification.
> +  */
> +  UINT64  GICV;
> +
> +  /** The base address for GICH interface
> +      as described by the GICC structure in the
> +      ACPI Specification.
> +  */
> +  UINT64  GICH;
> +
> +  /** The GICV maintenance interrupt
> +      as described by the GICC structure in the
> +      ACPI Specification.
> +  */
> +  UINT32  VGICMaintenanceInterrupt;
> +
> +  /** The base address for GICR interface
> +      as described by the GICC structure in the
> +      ACPI Specification.
> +  */
> +  UINT64  GICRBaseAddress;
> +
> +  /** The MPIDR for the CPU
> +      as described by the GICC structure in the
> +      ACPI Specification.
> +  */
> +  UINT64  MPIDR;
> +
> +  /** The Processor Power Efficiency class
> +      as described by the GICC structure in the
> +      ACPI Specification.
> +  */
> +  UINT8   ProcessorPowerEfficiencyClass;
> +} CM_ARM_GICC_INFO;
> +
> +/** A structure that describes the
> +    GIC Distributor information for the Platform.
> +*/
> +typedef struct CmArmGicDInfo {
> +  /// The GIC Distributor ID.
> +  UINT32  GicId;
> +
> +  /// The Physical Base address for the GIC Distributor.
> +  UINT64  PhysicalBaseAddress;
> +
> +  /** The global system interrupt
> +      number where this GIC Distributor's
> +      interrupt inputs start.
> +  */
> +  UINT32  SystemVectorBase;
> +
> +  /** The GIC version as described
> +      by the GICD structure in the
> +      ACPI Specification.
> +  */
> +  UINT8   GicVersion;
> +} CM_ARM_GICD_INFO;
> +
> +/** A structure that describes the
> +    GIC MSI Frame information for the Platform.
> +*/
> +typedef struct CmArmGicMsiFrameInfo {
> +  /// The GIC MSI Frame ID
> +  UINT32  GicMsiFrameId;
> +
> +  /// The Physical base address for the MSI Frame
> +  UINT64  PhysicalBaseAddress;
> +
> +  /** The GIC MSI Frame flags
> +      as described by the GIC MSI frame
> +      structure in the ACPI Specification.
> +  */
> +  UINT32  Flags;
> +
> +  /// SPI Count used by this frame
> +  UINT16  SPICount;
> +
> +  /// SPI Base used by this frame
> +  UINT16  SPIBase;
> +} CM_ARM_GIC_MSI_FRAME_INFO;
> +
> +/** A structure that describes the
> +    GIC Redistributor information for the Platform.
> +*/
> +typedef struct CmArmGicRedistInfo {
> +  /** The physical address of a page range
> +      containing all GIC Redistributors.
> +  */
> +  UINT64  DiscoveryRangeBaseAddress;
> +
> +  /// Length of the GIC Redistributor Discovery page range
> +  UINT32  DiscoveryRangeLength;
> +} CM_ARM_GIC_REDIST_INFO;
> +
> +/** A structure that describes the
> +    GIC Interrupt Translation Service information for the Platform.
> +*/
> +typedef struct CmArmGicItsInfo {
> +  /// The GIC ITS ID
> +  UINT32  GicItsId;
> +
> +  /// The physical address for the Interrupt Translation Service
> +  UINT64  PhysicalBaseAddress;
> +} CM_ARM_GIC_ITS_INFO;
> +
> +/** A structure that describes the
> +    Serial Port information for the Platform.
> +*/
> +typedef struct CmArmSerialPortInfo {
> +  /// The physical base address for the serial port
> +  UINT64  BaseAddress;
> +
> +  /// The serial port interrupt
> +  UINT32  Interrupt;
> +
> +  /// The serial port baud rate
> +  UINT64  BaudRate;
> +
> +  /// The serial port clock
> +  UINT32  Clock;
> +
> +  /// Serial Port subtype
> +  UINT16  PortSubtype;
> +} CM_ARM_SERIAL_PORT_INFO;
> +
> +/** A structure that describes the
> +    Generic Timer information for the Platform.
> +*/
> +typedef struct CmArmGenericTimerInfo {
> +  /// The physical base address for the counter control frame
> +  UINT64  CounterControlBaseAddress;
> +
> +  /// The physical base address for the counter read frame
> +  UINT64  CounterReadBaseAddress;
> +
> +  /// The secure PL1 timer interrupt
> +  UINT32  SecurePL1TimerGSIV;
> +
> +  /// The secure PL1 timer flags
> +  UINT32  SecurePL1TimerFlags;
> +
> +  /// The non-secure PL1 timer interrupt
> +  UINT32  NonSecurePL1TimerGSIV;
> +
> +  /// The non-secure PL1 timer flags
> +  UINT32  NonSecurePL1TimerFlags;
> +
> +  /// The virtual timer interrupt
> +  UINT32  VirtualTimerGSIV;
> +
> +  /// The virtual timer flags
> +  UINT32  VirtualTimerFlags;
> +
> +  /// The non-secure PL2 timer interrupt
> +  UINT32  NonSecurePL2TimerGSIV;
> +
> +  /// The non-secure PL2 timer flags
> +  UINT32  NonSecurePL2TimerFlags;
> +} CM_ARM_GENERIC_TIMER_INFO;
> +
> +/** A structure that describes the
> +    Platform Generic Block Timer Frame information for the Platform.
> +*/
> +typedef struct CmArmGTBlockTimerFrameInfo {
> +  /// The Generic Timer frame number
> +  UINT8   FrameNumber;
> +
> +  /// The physical base address for the CntBase block
> +  UINT64  PhysicalAddressCntBase;
> +
> +  /// The physical base address for the CntEL0Base block
> +  UINT64  PhysicalAddressCntEL0Base;
> +
> +  /// The physical timer interrupt
> +  UINT32  PhysicalTimerGSIV;
> +
> +  /** The physical timer flags as described by the GT Block
> +      Timer frame Structure in the ACPI Specification.
> +  */
> +  UINT32  PhysicalTimerFlags;
> +
> +  /// The virtual timer interrupt
> +  UINT32  VirtualTimerGSIV;
> +
> +  /** The virtual timer flags as described by the GT Block
> +      Timer frame Structure in the ACPI Specification.
> +  */
> +  UINT32  VirtualTimerFlags;
> +
> +  /** The common timer flags as described by the GT Block
> +      Timer frame Structure in the ACPI Specification.
> +  */
> +  UINT32  CommonFlags;
> +} CM_ARM_GTBLOCK_TIMER_FRAME_INFO;
> +
> +/** A structure that describes the
> +    Platform Generic Block Timer information for the Platform.
> +*/
> +typedef struct CmArmGTBlockInfo {
> +  /// The physical base address for the GT Block Timer structure
> +  UINT64            GTBlockPhysicalAddress;
> +
> +  /// The number of timer frames implemented in the GT Block
> +  UINT32            GTBlockTimerFrameCount;
> +
> +  /// Reference token for the GT Block timer frame list
> +  CM_OBJECT_TOKEN   GTBlockTimerFrameToken;
> +} CM_ARM_GTBLOCK_INFO;
> +
> +/** A structure that describes the
> +    SBSA Generic Watchdog information for the Platform.
> +*/
> +typedef struct CmArmGenericWatchdogInfo {
> +  /// The physical base address of the SBSA Watchdog control frame
> +  UINT64  ControlFrameAddress;
> +
> +  /// The physical base address of the SBSA Watchdog refresh frame
> +  UINT64  RefreshFrameAddress;
> +
> +  /// The watchdog interrupt
> +  UINT32  TimerGSIV;
> +
> +  /** The flags for the watchdog as described by the SBSA watchdog
> +      structure in the ACPI specification.
> +  */
> +  UINT32  Flags;
> +} CM_ARM_GENERIC_WATCHDOG_INFO;
> +
> +/** A structure that describes the
> +    PCI Configuration Space information for the Platform.
> +*/
> +typedef struct CmArmPciConfigSpaceInfo {
> +  /// The physical base address for the PCI segment
> +  UINT64  BaseAddress;
> +
> +  /// The PCI segment group number
> +  UINT16  PciSegmentGroupNumber;
> +
> +  /// The start bus number
> +  UINT8   StartBusNumber;
> +
> +  /// The end bus number
> +  UINT8   EndBusNumber;
> +} CM_ARM_PCI_CONFIG_SPACE_INFO;
> +
> +/** A structure that describes the
> +    Hypervisor Vendor ID information for the Platform.
> +*/
> +typedef struct CmArmHypervisorVendorId {
> +  /// The hypervisor Vendor ID
> +  UINT64  HypervisorVendorId;
> +} CM_ARM_HYPERVISOR_VENDOR_ID;
> +
> +/** A structure that describes the
> +    Fixed feature flags for the Platform.
> +*/
> +typedef struct CmArmFixedFeatureFlags {
> +  /// The Fixed feature flags
> +  UINT32  Flags;
> +} CM_ARM_FIXED_FEATURE_FLAGS;
> +
> +/** A structure that describes the
> +    ITS Group node for the Platform.
> +*/
> +typedef struct CmArmItsGroupNode {
> +  /// An unique token used to ideintify this object
> +  CM_OBJECT_TOKEN   Token;
> +  /// The number of ITS identifiers in the ITS node
> +  UINT32            ItsIdCount;
> +  /// Reference token for the ITS identifier array
> +  CM_OBJECT_TOKEN   ItsIdToken;
> +} CM_ARM_ITS_GROUP_NODE;
> +
> +/** A structure that describes the
> +    GIC ITS Identifiers for an ITS Group node.
> +*/
> +typedef struct CmArmGicItsIdentifier {
> +  /// The ITS Identifier
> +  UINT32  ItsId;
> +} CM_ARM_ITS_IDENTIFIER;
> +
> +/** A structure that describes the
> +    Named component node for the Platform.
> +*/
> +typedef struct CmArmNamedComponentNode {
> +  /// An unique token used to ideintify this object
> +  CM_OBJECT_TOKEN   Token;
> +  /// Number of ID mappings
> +  UINT32            IdMappingCount;
> +  /// Reference token for the ID mapping array
> +  CM_OBJECT_TOKEN   IdMappingToken;
> +
> +  /// Flags for the named component
> +  UINT32            Flags;
> +
> +  /// Memory access properties : Cache coherent attributes
> +  UINT32            CacheCoherent;
> +  /// Memory access properties : Allocation hints
> +  UINT8             AllocationHints;
> +  /// Memory access properties : Memory access flags
> +  UINT8             MemoryAccessFlags;
> +
> +  /// Memory access properties : Address size limit
> +  UINT8             AddressSizeLimit;
> +  /** ASCII Null terminated string with the full path to
> +      the entry in the namespace for this object.
> +  */
> +  CHAR8*            ObjectName;
> +} CM_ARM_NAMED_COMPONENT_NODE;
> +
> +/** A structure that describes the
> +    Root complex node for the Platform.
> +*/
> +typedef struct CmArmRootComplexNode {
> +  /// An unique token used to ideintify this object
> +  CM_OBJECT_TOKEN   Token;
> +  /// Number of ID mappings
> +  UINT32            IdMappingCount;
> +  /// Reference token for the ID mapping array
> +  CM_OBJECT_TOKEN   IdMappingToken;
> +
> +  /// Memory access properties : Cache coherent attributes
> +  UINT32            CacheCoherent;
> +  /// Memory access properties : Allocation hints
> +  UINT8             AllocationHints;
> +  /// Memory access properties : Memory access flags
> +  UINT8             MemoryAccessFlags;
> +
> +  /// ATS attributes
> +  UINT32            AtsAttribute;
> +  /// PCI segment number
> +  UINT32            PciSegmentNumber;
> +} CM_ARM_ROOT_COMPLEX_NODE;
> +
> +/** A structure that describes the
> +    SMMUv1 or SMMUv2 node for the Platform.
> +*/
> +typedef struct CmArmSmmuV1SmmuV2Node {
> +  /// An unique token used to ideintify this object
> +  CM_OBJECT_TOKEN   Token;
> +  /// Number of ID mappings
> +  UINT32            IdMappingCount;
> +  /// Reference token for the ID mapping array
> +  CM_OBJECT_TOKEN   IdMappingToken;
> +
> +  /// SMMU Base Address
> +  UINT64            BaseAddress;
> +  /// Length of the memory range covered by the SMMU
> +  UINT64            Span;
> +  /// SMMU Model
> +  UINT32            Model;
> +  /// SMMU flags
> +  UINT32            Flags;
> +
> +  /// Number of context interrupts
> +  UINT32            ContextInterruptCount;
> +  /// Reference token for the context interrupt array
> +  CM_OBJECT_TOKEN   ContextInterruptToken;
> +
> +  /// Number of PMU interrupts
> +  UINT32            PmuInterruptCount;
> +  /// Reference token for the PMU interrupt array
> +  CM_OBJECT_TOKEN   PmuInterruptToken;
> +
> +  /// GSIV of the SMMU_NSgIrpt interrupt
> +  UINT32            SMMU_NSgIrpt;
> +  /// SMMU_NSgIrpt interrupt flags
> +  UINT32            SMMU_NSgIrptFlags;
> +  /// GSIV of the SMMU_NSgCfgIrpt interrupt
> +  UINT32            SMMU_NSgCfgIrpt;
> +  /// SMMU_NSgCfgIrpt interrupt flags
> +  UINT32            SMMU_NSgCfgIrptFlags;
> +} CM_ARM_SMMUV1_SMMUV2_NODE;
> +
> +/** A structure that describes the
> +    SMMUv3 node for the Platform.
> +*/
> +typedef struct CmArmSmmuV3Node {
> +  /// An unique token used to ideintify this object
> +  CM_OBJECT_TOKEN   Token;
> +  /// Number of ID mappings
> +  UINT32            IdMappingCount;
> +  /// Reference token for the ID mapping array
> +  CM_OBJECT_TOKEN   IdMappingToken;
> +
> +  /// SMMU Base Address
> +  UINT64    BaseAddress;
> +  /// SMMU flags
> +  UINT32            Flags;
> +  /// VATOS address
> +  UINT64            VatosAddress;
> +  /// Model
> +  UINT32            Model;
> +  /// GSIV of the Event interrupt if SPI based
> +  UINT32            EventInterrupt;
> +  /// PRI Interrupt if SPI based
> +  UINT32            PriInterrupt;
> +  /// GERR interrupt if GSIV based
> +  UINT32            GerrInterrupt;
> +  /// Sync interrupt if GSIV based
> +  UINT32            SyncInterrupt;
> +
> +  /// Proximity domain flag
> +  UINT8             ProximityDomain;
> +  /// Index into the array of ID mapping
> +  UINT32            DeviceIdMappingIndex;
> +} CM_ARM_SMMUV3_NODE;
> +
> +/** A structure that describes the
> +    PMCG node for the Platform.
> +*/
> +typedef struct CmArmPmcgNode {
> +  /// An unique token used to ideintify this object
> +  CM_OBJECT_TOKEN   Token;
> +  /// Number of ID mappings
> +  UINT32            IdMappingCount;
> +  /// Reference token for the ID mapping array
> +  CM_OBJECT_TOKEN   IdMappingToken;
> +
> +  /// Base Address for performance monitor counter group
> +  UINT64            BaseAddress;
> +  /// GSIV for the Overflow interrupt
> +  UINT32            OverflowInterrupt;
> +
> +  /// Reference token for the IORT node associated with this node
> +  CM_OBJECT_TOKEN   ReferenceToken;
> +} CM_ARM_PMCG_NODE;
> +
> +/** A structure that describes the
> +    ID Mappings for the Platform.
> +*/
> +typedef struct CmArmIdMapping {
> +  /// Input base
> +  UINT32           InputBase;
> +  /// Number of input IDs
> +  UINT32           NumIds;
> +  /// Output Base
> +  UINT32           OutputBase;
> +  /// Reference token for the output node
> +  CM_OBJECT_TOKEN  OutputReferenceToken;
> +  /// Flags
> +  UINT32    Flags;
> +} CM_ARM_ID_MAPPING;
> +
> +/** A structure that describes the
> +    SMMU interrupts for the Platform.
> +*/
> +typedef struct CmArmSmmuInterrupt {
> +  /// Interrupt number
> +  UINT32    Interrupt;
> +
> +  /// Flags
> +  UINT32    Flags;
> +} CM_ARM_SMMU_INTERRUPT;
> +
> +#pragma pack()
> +
> +#endif // ARM_NAMESPACE_OBJECTS_H_
> diff --git a/DynamicTablesPkg/Include/ConfigurationManagerHelper.h
> b/DynamicTablesPkg/Include/ConfigurationManagerHelper.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..7f39e2167166e1ea0e
> 895a535d85ddaf231bf394
> --- /dev/null
> +++ b/DynamicTablesPkg/Include/ConfigurationManagerHelper.h
> @@ -0,0 +1,119 @@
> +/** @file
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Cm or CM   - Configuration Manager
> +    - Obj or OBJ - Object
> +**/
> +
> +#ifndef CONFIGURATION_MANAGER_HELPER_H_
> +#define CONFIGURATION_MANAGER_HELPER_H_
> +
> +/** The GET_OBJECT_LIST macro expands to a function that is used to
> retrieve
> +    an object or an object list from the Configuration Manager using the
> +    Configuration Manager Protocol interface.
> +
> +  The macro expands to a function which has the following prototype:
> +
> +  STATIC
> +  EFI_STATUS
> +  EFIAPI
> +  Get<CmObjectId> (
> +    IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL * CONST
> CfgMgrProtocol,
> +    IN  CONST CM_OBJECT_TOKEN                            Token OPTIONAL,
> +    OUT       Type                              **       List,
> +    OUT       UINT32                             *       Count OPTIONAL
> +    );
> +
> +  Generated function parameters:
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> protocol
> +                              interface.
> +  @param [in]  Token          Reference token for the Object.
> +  @param [out] List           Pointer to the Object list.
> +  @param [out] Count          Count of the objects returned in the list.
> +
> +  Macro Parameters:
> +  @param [in] CmObjectNameSpace The Object Namespace
> +  @param [in] CmObjectId        Object Id.
> +  @param [in] Type              Structure used to describe the Object.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object information is not
> found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +#define GET_OBJECT_LIST(CmObjectNameSpace, CmObjectId, Type)
> \
> +STATIC                                                                        \
> +EFI_STATUS                                                                    \
> +EFIAPI                                                                        \
> +Get##CmObjectId (                                                             \
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,       \
> +  IN  CONST CM_OBJECT_TOKEN                             Token OPTIONAL,       \
> +  OUT       Type                               **       List,                 \
> +  OUT       UINT32                              * CONST Count OPTIONAL        \
> +  )                                                                           \
> +{                                                                             \
> +  EFI_STATUS         Status;                                                  \
> +  CM_OBJ_DESCRIPTOR  CmObjectDesc;                                            \
> +  UINT32             ObjCount = 0;                                            \
> +  if (List == NULL) {                                                         \
> +    Status = EFI_INVALID_PARAMETER;                                           \
> +    DEBUG ((                                                                  \
> +      DEBUG_ERROR,                                                            \
> +      "ERROR: Get" #CmObjectId ": Invalid out parameter for"                  \
> +      " object list. Status = %r\n",                                          \
> +      Status                                                                  \
> +      ));                                                                     \
> +    goto error_handler;                                                       \
> +  }                                                                           \
> +  Status = CfgMgrProtocol->GetObject (                                        \
> +                             CfgMgrProtocol,                                  \
> +                             CREATE_CM_OBJECT_ID (                            \
> +                               CmObjectNameSpace,                             \
> +                               CmObjectId                                     \
> +                               ),                                             \
> +                             Token,                                           \
> +                             &CmObjectDesc                                    \
> +                             );                                               \
> +  if (EFI_ERROR (Status)) {                                                   \
> +    DEBUG ((                                                                  \
> +      DEBUG_INFO,                                                             \
> +      "INFO: Get" #CmObjectId ": Platform does not implement "                \
> +      #CmObjectId ". Status = %r\n",                                          \
> +      Status                                                                  \
> +      ));                                                                     \
> +    *List = NULL;                                                             \
> +    goto error_handler;                                                       \
> +  }                                                                           \
> +  if (CmObjectDesc.Size < sizeof (Type)) {                                    \
> +    DEBUG ((                                                                  \
> +      DEBUG_ERROR,                                                            \
> +      "ERROR: Get" #CmObjectId ": " #CmObjectId                               \
> +      ": Buffer too small, size = 0x%x\n",                                    \
> +      CmObjectDesc.Size                                                       \
> +      ));                                                                     \
> +    ASSERT (CmObjectDesc.Size >= sizeof (Type));                              \
> +    Status = EFI_BAD_BUFFER_SIZE;                                             \
> +    goto error_handler;                                                       \
> +  }                                                                           \
> +  ObjCount = CmObjectDesc.Size / sizeof (Type);                               \
> +  *List = (Type*)CmObjectDesc.Data;                                           \
> +error_handler:                                                                \
> +  if (Count != NULL) {                                                        \
> +    *Count = ObjCount;                                                        \
> +  }                                                                           \
> +  return Status;                                                              \
> +}
> +
> +#endif // CONFIGURATION_MANAGER_HELPER_H_
> diff --git a/DynamicTablesPkg/Include/ConfigurationManagerObject.h
> b/DynamicTablesPkg/Include/ConfigurationManagerObject.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..98329133a67f6ba477
> 1ceb98c8cd30d1f470bd19
> --- /dev/null
> +++ b/DynamicTablesPkg/Include/ConfigurationManagerObject.h
> @@ -0,0 +1,176 @@
> +/** @file
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Cm or CM   - Configuration Manager
> +    - Obj or OBJ - Object
> +**/
> +
> +#ifndef CONFIGURATION_MANAGER_OBJECT_H_
> +#define CONFIGURATION_MANAGER_OBJECT_H_
> +
> +#include <ArmNameSpaceObjects.h>
> +#include <StandardNameSpaceObjects.h>
> +
> +#pragma pack(1)
> +
> +/** The CM_OBJECT_ID type is used to identify the Configuration Manager
> +    objects.
> +
> + Description of Configuration Manager Object ID
> +_________________________________________________________
> ______________________
> +|31 |30 |29 |28 || 27 | 26 | 25 | 24 || 23 | 22 | 21 | 20 || 19 | 18 | 17
> | 16|
> +-------------------------------------------------------------------------------
> +| Name Space ID ||  0 |  0 |  0 |  0 ||  0 |  0 |  0 |  0 ||  0 |  0 |  0 |  0|
> +_________________________________________________________
> ______________________
> +
> +Bits: [31:28] - Name Space ID
> +                0000 - Standard
> +                0001 - ARM
> +                1000 - Custom/OEM
> +                All other values are reserved.
> +
> +Bits: [27:16] - Reserved.
> +_________________________________________________________
> ______________________
> +|15 |14 |13 |12 || 11 | 10 |  9 |  8 ||  7 |  6 |  5 |  4 ||  3 |  2 |  1 |  0|
> +-------------------------------------------------------------------------------
> +| 0 | 0 | 0 | 0 ||  0 |  0 |  0 |  0 ||                 Object ID             |
> +_________________________________________________________
> ______________________
> +
> +Bits: [15:8] - Are reserved and must be zero.
> +
> +Bits: [7:0] - Object ID
> +
> +Object ID's in the Standard Namespace:
> +  0 - Configuration Manager Revision
> +  1 - ACPI Table List
> +  2 - SMBIOS Table List
> +
> +Object ID's in the ARM Namespace:
> +   0 - Reserved
> +   1 - Boot Architecture Info
> +   2 - CPU Info
> +   3 - Power Management Profile Info
> +   4 - GICC Info
> +   5 - GICD Info
> +   6 - GIC MSI Frame Info
> +   7 - GIC Redistributor Info
> +   8 - GIC ITS Info
> +   9 - Serial Console Port Info
> +  10 - Serial Debug Port Info
> +  11 - Generic Timer Info
> +  12 - Platform GT Block Info
> +  13 - Platform Generic Watchdog
> +  14 - PCI Configuration Space Info
> +  15 - Hypervisor Vendor Id
> +  16 - Fixed feature flags for FADT
> +*/
> +typedef UINT32  CM_OBJECT_ID;
> +
> +/** A mask for Object ID
> +*/
> +#define OBJECT_ID_MASK            0xFF
> +
> +/** A mask for Namespace ID
> +*/
> +#define NAMESPACE_ID_MASK         0xF
> +
> +/** Starting bit position for Namespace ID
> +*/
> +#define NAMESPACE_ID_BIT_SHIFT    28
> +
> +/** The EOBJECT_NAMESPACE_ID enum describes the defined
> namespaces
> +    for the Configuration Manager Objects.
> +*/
> +typedef enum ObjectNameSpaceID {
> +  EObjNameSpaceStandard,      ///< Standard Objects Namespace
> +  EObjNameSpaceArm,           ///< ARM Objects Namespace
> +  EObjNameSpaceOem = 0x8,     ///< OEM Objects Namespace
> +  EObjNameSpaceMax
> +} EOBJECT_NAMESPACE_ID;
> +
> +/** A descriptor for Configuration Manager Objects.
> +
> +  The Configuration Manager Protocol interface uses this descriptor
> +  to return the Configuration Manager Objects.
> +*/
> +typedef struct CmObjDescriptor {
> +  /// sizeof the described Object or Object List.
> +  UINT32   Size;
> +
> +  /// Pointer to the described Object or Object List.
> +  VOID   * Data;
> +} CM_OBJ_DESCRIPTOR;
> +
> +#pragma pack()
> +
> +/** This macro returns the namespace ID from the CmObjectID.
> +
> +  @param [in] CmObjectId  The Configuration Manager Object ID.
> +
> +  @retval Returns the Namespace ID corresponding to the CmObjectID.
> +*/
> +#define GET_CM_NAMESPACE_ID(CmObjectId)               \
> +          (((CmObjectId) >> NAMESPACE_ID_BIT_SHIFT) & \
> +            NAMESPACE_ID_MASK)
> +
> +/** This macro returns the Object ID from the CmObjectID.
> +
> +  @param [in] CmObjectId  The Configuration Manager Object ID.
> +
> +  @retval Returns the Object ID corresponding to the CmObjectID.
> +*/
> +#define GET_CM_OBJECT_ID(CmObjectId)    ((CmObjectId) &
> OBJECT_ID_MASK)
> +
> +/** This macro returns a Configuration Manager Object ID
> +    from the NameSpace ID and the ObjectID.
> +
> +  @param [in] NameSpaceId The namespace ID for the Object.
> +  @param [in] ObjectId    The Object ID.
> +
> +  @retval Returns the Configuration Manager Object ID.
> +*/
> +#define CREATE_CM_OBJECT_ID(NameSpaceId, ObjectId)                           \
> +          ((((NameSpaceId) & NAMESPACE_ID_MASK) <<
> NAMESPACE_ID_BIT_SHIFT) | \
> +            ((ObjectId) & OBJECT_ID_MASK))
> +
> +/** This macro returns a Configuration Manager Object ID
> +    in the Standard Object Namespace.
> +
> +  @param [in] ObjectId    The Object ID.
> +
> +  @retval Returns a Standard Configuration Manager Object ID.
> +*/
> +#define CREATE_CM_STD_OBJECT_ID(ObjectId) \
> +          (CREATE_CM_OBJECT_ID (EObjNameSpaceStandard, ObjectId))
> +
> +/** This macro returns a Configuration Manager Object ID
> +    in the ARM Object Namespace.
> +
> +  @param [in] ObjectId    The Object ID.
> +
> +  @retval Returns an ARM Configuration Manager Object ID.
> +*/
> +#define CREATE_CM_ARM_OBJECT_ID(ObjectId) \
> +          (CREATE_CM_OBJECT_ID (EObjNameSpaceArm, ObjectId))
> +
> +/** This macro returns a Configuration Manager Object ID
> +    in the OEM Object Namespace.
> +
> +  @param [in] ObjectId    The Object ID.
> +
> +  @retval Returns an OEM Configuration Manager Object ID.
> +*/
> +#define CREATE_CM_OEM_OBJECT_ID(ObjectId) \
> +          (CREATE_CM_OBJECT_ID (EObjNameSpaceOem, ObjectId))
> +
> +#endif // CONFIGURATION_MANAGER_OBJECT_H_
> diff --git a/DynamicTablesPkg/Include/DeviceTreeTableGenerator.h
> b/DynamicTablesPkg/Include/DeviceTreeTableGenerator.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..767a62d383e6d530e5
> 51b69a0a7146359f6fd093
> --- /dev/null
> +++ b/DynamicTablesPkg/Include/DeviceTreeTableGenerator.h
> @@ -0,0 +1,182 @@
> +/** @file
> +
> +  Copyright (c) 2017, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Cm or CM   - Configuration Manager
> +    - Obj or OBJ - Object
> +    - Std or STD - Standard
> +**/
> +
> +#ifndef DEVICETREE_TABLE_GENERATOR_H_
> +#define DEVICETREE_TABLE_GENERATOR_H_
> +
> +#include <TableGenerator.h>
> +
> +#pragma pack(1)
> +
> +/** The DT_TABLE_GENERATOR_ID type describes Device Tree table
> generator ID.
> +*/
> +typedef TABLE_GENERATOR_ID DT_TABLE_GENERATOR_ID;
> +
> +/** The ESTD_DT_TABLE_ID enum describes the DT table IDs reserved for
> +  the standard generators.
> +*/
> +typedef enum StdDtTableId {
> +  ESTD_DT_TABLE_ID_RESERVED = 0x0000,             ///< Reserved.
> +  ESTD_DT_TABLE_ID_RAW,                           ///< RAW Generator.
> +  ESTD_DT_TABLE_ID_MAX
> +} ESTD_DT_TABLE_ID;
> +
> +/** This macro checks if the Table Generator ID is for an DT Table
> Generator.
> +
> +  @param [in] TableGeneratorId  The table generator ID.
> +
> +  @returns TRUE if the table generator ID is for an DT Table
> +            Generator.
> +*/
> +#define IS_GENERATOR_TYPE_DT(TableGeneratorId) \
> +          (GET_TABLE_TYPE(TableGeneratorId) == ETableGeneratorTypeDt)
> +
> +/** This macro checks if the Table Generator ID is for a standard DT
> +    Table Generator.
> +
> +  @param [in] TableGeneratorId  The table generator ID.
> +
> +  @returns TRUE if the table generator ID is for a standard DT
> +            Table Generator.
> +*/
> +#define IS_VALID_STD_DT_GENERATOR_ID(TableGeneratorId)               \
> +          (                                                          \
> +          IS_GENERATOR_NAMESPACE_STD(TableGeneratorId) &&            \
> +          IS_GENERATOR_TYPE_DT(TableGeneratorId)       &&            \
> +          ((GET_TABLE_ID(GeneratorId) >= ESTD_DT_TABLE_ID_RAW) &&    \
> +           (GET_TABLE_ID(GeneratorId) < ESTD_DT_TABLE_ID_MAX))       \
> +          )
> +
> +/** This macro creates a standard DT Table Generator ID.
> +
> +  @param [in] TableId  The table generator ID.
> +
> +  @returns a standard DT table generator ID.
> +*/
> +#define CREATE_STD_DT_TABLE_GEN_ID(TableId) \
> +          CREATE_TABLE_GEN_ID (             \
> +            ETableGeneratorTypeDt,          \
> +            ETableGeneratorNameSpaceStd,    \
> +            TableId                         \
> +            )
> +
> +/** Forward declarations.
> +*/
> +typedef struct ConfigurationManagerProtocol
> EFI_CONFIGURATION_MANAGER_PROTOCOL;
> +typedef struct CmAStdObjDtTableInfo         CM_STD_OBJ_DT_TABLE_INFO;
> +typedef struct DtTableGenerator             DT_TABLE_GENERATOR;
> +
> +/** This function pointer describes the interface to DT table build
> +    functions provided by the DT table generator and called by the
> +    Table Manager to build an DT table.
> +
> +  @param [in]  Generator       Pointer to the DT table generator.
> +  @param [in]  DtTableInfo     Pointer to the DT table information.
> +  @param [in]  CfgMgrProtocol  Pointer to the Configuration Manager
> +                               Protocol interface.
> +  @param [out] Table           Pointer to the generated DT table.
> +
> +  @returns EFI_SUCCESS  If the table is generated successfully or other
> +                        failure codes as returned by the generator.
> +*/
> +typedef EFI_STATUS (*DT_TABLE_GENERATOR_BUILD_TABLE) (
> +  IN  CONST DT_TABLE_GENERATOR                  *       Generator,
> +  IN  CONST CM_STD_OBJ_DT_TABLE_INFO            * CONST DtTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       VOID                               **       Table
> +  );
> +
> +/** This function pointer describes the interface to used by the
> +    Table Manager to give the generator an opportunity to free
> +    any resources allocated for building the DT table.
> +
> +  @param [in]  Generator       Pointer to the DT table generator.
> +  @param [in]  DtTableInfo     Pointer to the DT table information.
> +  @param [in]  CfgMgrProtocol  Pointer to the Configuration Manager
> +                               Protocol interface.
> +  @param [in]  Table           Pointer to the generated DT table.
> +
> +  @returns EFI_SUCCESS  If freed successfully or other failure codes
> +                        as returned by the generator.
> +*/
> +typedef EFI_STATUS (*DT_TABLE_GENERATOR_FREE_TABLE) (
> +  IN  CONST DT_TABLE_GENERATOR                  *       Generator,
> +  IN  CONST CM_STD_OBJ_DT_TABLE_INFO            * CONST DtTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN        VOID                               **       Table
> +  );
> +
> +/** The DT_TABLE_GENERATOR structure provides an interface that the
> +    Table Manager can use to invoke the functions to build DT tables.
> +*/
> +typedef struct DtTableGenerator {
> +  /// The DT table generator ID.
> +  DT_TABLE_GENERATOR_ID                  GeneratorID;
> +
> +  /// String describing the DT table generator.
> +  CONST CHAR16                         * Description;
> +
> +  /// DT table build function pointer.
> +  DT_TABLE_GENERATOR_BUILD_TABLE         BuildDtTable;
> +
> +  /// The function to free any resources allocated for building the DT table.
> +  DT_TABLE_GENERATOR_FREE_TABLE          FreeTableResources;
> +} DT_TABLE_GENERATOR;
> +
> +/** Register DT table factory generator.
> +
> +  The DT table factory maintains a list of the Standard and OEM DT
> +  table generators.
> +
> +  @param [in]  Generator       Pointer to the DT table generator.
> +
> +  @retval  EFI_SUCCESS          The Generator was registered
> +                                successfully.
> +  @retval EFI_INVALID_PARAMETER The Generator ID is invalid or
> +                                the Generator pointer is NULL.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID is
> +                                already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +RegisterDtTableGenerator (
> +  IN CONST DT_TABLE_GENERATOR                   * CONST Generator
> +  );
> +
> +/** Deregister DT generator.
> +
> +  This function is called by the DT table generator to deregister itself
> +  from the DT table factory.
> +
> +  @param [in]  Generator       Pointer to the DT table generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER The generator is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +DeregisterDtTableGenerator (
> +  IN CONST DT_TABLE_GENERATOR                   * CONST Generator
> +  );
> +
> +#pragma pack()
> +
> +#endif // DEVICETREE_TABLE_GENERATOR_H_
> +
> diff --git a/DynamicTablesPkg/Include/Library/TableHelperLib.h
> b/DynamicTablesPkg/Include/Library/TableHelperLib.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..71efd2e7b94d072feeb
> a39921e19a2460641e1d1
> --- /dev/null
> +++ b/DynamicTablesPkg/Include/Library/TableHelperLib.h
> @@ -0,0 +1,70 @@
> +/** @file
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef TABLE_HELPER_LIB_H_
> +#define TABLE_HELPER_LIB_H_
> +
> +/** A helper macro to align a value to the 32-bit word boundary
> +*/
> +#define ALIGN32(x) ((x) + (sizeof (UINT32) - 1)) & ~(sizeof (UINT32) - 1)
> +
> +/** The GetCgfMgrInfo function gets the
> CM_STD_OBJ_CONFIGURATION_MANAGER_INFO
> +    object from the Configuration Manager.
> +
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> protocol
> +                              interface.
> +  @param [out] CfgMfrInfo     Pointer to the Configuration Manager Info
> +                              object structure.
> +
> +  @retval EFI_SUCCESS           The object is returned.
> +  @retval EFI_INVALID_PARAMETER The Object ID is invalid.
> +  @retval EFI_NOT_FOUND         The requested Object is not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size.
> +*/
> +EFI_STATUS
> +EFIAPI
> +GetCgfMgrInfo (
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL      * CONST
> CfgMgrProtocol,
> +  OUT       CM_STD_OBJ_CONFIGURATION_MANAGER_INFO  **
> CfgMfrInfo
> +  );
> +
> +/** The AddAcpiHeader function updates the ACPI header structure. It
> uses the
> +    ACPI table Generator and the Configuration Manager protocol to obtain
> the
> +    information required for constructing the header.
> +
> +  @param [in]     CfgMgrProtocol Pointer to the Configuration Manager
> +                                 protocol interface.
> +  @param [in]     Generator      Pointer to the ACPI table Generator.
> +  @param [in,out] AcpiHeader     Pointer to the ACPI table header to be
> +                                 updated.
> +  @param [in]     Length         Length of the ACPI table.
> +
> +  @retval EFI_SUCCESS           The ACPI table is updated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object information is not
> found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AddAcpiHeader (
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN      CONST ACPI_TABLE_GENERATOR                * CONST Generator,
> +  IN OUT  EFI_ACPI_DESCRIPTION_HEADER               * CONST AcpiHeader,
> +  IN      CONST UINT32                                      Length
> +  );
> +
> +#endif // TABLE_HELPER_LIB_H_
> diff --git
> a/DynamicTablesPkg/Include/Protocol/ConfigurationManagerProtocol.h
> b/DynamicTablesPkg/Include/Protocol/ConfigurationManagerProtocol.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..15ca0a22aac5129e5b
> 291f1385f058113e186070
> --- /dev/null
> +++
> b/DynamicTablesPkg/Include/Protocol/ConfigurationManagerProtocol.h
> @@ -0,0 +1,128 @@
> +/** @file
> +
> +  Copyright (c) 2017, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Cm or CM   - Configuration Manager
> +    - Obj or OBJ - Object
> +**/
> +
> +#ifndef CONFIGURATION_MANAGER_PROTOCOL_H_
> +#define CONFIGURATION_MANAGER_PROTOCOL_H_
> +
> +#include <ConfigurationManagerObject.h>
> +
> +/** This macro defines the Configuration Manager Protocol GUID.
> +
> +  GUID: {D85A4835-5A82-4894-AC02-706F43D5978E}
> +*/
> +#define EFI_CONFIGURATION_MANAGER_PROTOCOL_GUID         \
> +  { 0xd85a4835, 0x5a82, 0x4894,                         \
> +    { 0xac, 0x2, 0x70, 0x6f, 0x43, 0xd5, 0x97, 0x8e }   \
> +  };
> +
> +/** This macro defines the Configuration Manager Protocol Revision.
> +*/
> +#define EFI_CONFIGURATION_MANAGER_PROTOCOL_REVISION
> CREATE_REVISION (1, 0)
> +
> +#pragma pack(1)
> +
> +/**
> +  Forward declarations:
> +*/
> +typedef struct ConfigurationManagerProtocol
> EFI_CONFIGURATION_MANAGER_PROTOCOL;
> +typedef struct PlatformRepositoryInfo
> EFI_PLATFORM_REPOSITORY_INFO;
> +
> +/** The GetObject function defines the interface implemented by the
> +    Configuration Manager Protocol for returning the Configuration
> +    Manager Objects.
> +
> +  @param [in]  This        Pointer to the Configuration Manager Protocol.
> +  @param [in]  CmObjectId  The Configuration Manager Object ID.
> +  @param [in]  Token       An optional token identifying the object. If
> +                           unused this must be CM_NULL_TOKEN.
> +  @param [out] CmObject    Pointer to the Configuration Manager Object
> +                           descriptor describing the requested Object.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object information is not
> found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> Manager
> +                                is less than the Object size for the requested
> +                                object.
> +*/
> +typedef
> +EFI_STATUS
> +(EFIAPI * EFI_CONFIGURATION_MANAGER_GET_OBJECT) (
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST This,
> +  IN  CONST CM_OBJECT_ID                                CmObjectId,
> +  IN  CONST CM_OBJECT_TOKEN                             Token OPTIONAL,
> +  IN  OUT   CM_OBJ_DESCRIPTOR                   * CONST CmObject
> +  );
> +
> +/** The SetObject function defines the interface implemented by the
> +    Configuration Manager Protocol for updating the Configuration
> +    Manager Objects.
> +
> +  @param [in]  This        Pointer to the Configuration Manager Protocol.
> +  @param [in]  CmObjectId  The Configuration Manager Object ID.
> +  @param [in]  Token       An optional token identifying the object. If
> +                           unused this must be CM_NULL_TOKEN.
> +  @param [out] CmObject    Pointer to the Configuration Manager Object
> +                           descriptor describing the Object.
> +
> +  @retval EFI_SUCCESS           The operation completed successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object information is not
> found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> Manager
> +                                is less than the Object size for the requested
> +                                object.
> +  @retval EFI_UNSUPPORTED       This operation is not supported.
> +*/
> +typedef
> +EFI_STATUS
> +(EFIAPI * EFI_CONFIGURATION_MANAGER_SET_OBJECT) (
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST This,
> +  IN  CONST CM_OBJECT_ID                                CmObjectId,
> +  IN  CONST CM_OBJECT_TOKEN                             Token OPTIONAL,
> +  IN        CM_OBJ_DESCRIPTOR                   * CONST CmObject
> +  );
> +
> +/** The EFI_CONFIGURATION_MANAGER_PROTOCOL structure describes
> the
> +    Configuration Manager Protocol interface.
> +*/
> +typedef struct ConfigurationManagerProtocol {
> +  /// The Configuration Manager Protocol revision.
> +  UINT32                                Revision;
> +
> +  /** The interface used to request information about
> +      the Configuration Manager Objects.
> +  */
> +  EFI_CONFIGURATION_MANAGER_GET_OBJECT  GetObject;
> +
> +  /** The interface used to update the information stored
> +      in the Configuration Manager repository.
> +  */
> +  EFI_CONFIGURATION_MANAGER_SET_OBJECT  SetObject;
> +
> +  /** Pointer to an implementation defined abstract repository
> +      provisioned by the Configuration Manager.
> +  */
> +  EFI_PLATFORM_REPOSITORY_INFO        * PlatRepoInfo;
> +} EFI_CONFIGURATION_MANAGER_PROTOCOL;
> +
> +/** The Configuration Manager Protocol GUID.
> +*/
> +extern EFI_GUID gEfiConfigurationManagerProtocolGuid;
> +
> +#pragma pack()
> +
> +#endif // CONFIGURATION_MANAGER_PROTOCOL_H_
> diff --git
> a/DynamicTablesPkg/Include/Protocol/DynamicTableFactoryProtocol.h
> b/DynamicTablesPkg/Include/Protocol/DynamicTableFactoryProtocol.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..8688d0a40900c9dcd9
> 0c76bfb38911ccd6b4add6
> --- /dev/null
> +++ b/DynamicTablesPkg/Include/Protocol/DynamicTableFactoryProtocol.h
> @@ -0,0 +1,140 @@
> +/** @file
> +
> +  Copyright (c) 2017, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - ACPI   - Advanced Configuration and Power Interface
> +    - SMBIOS - System Management BIOS
> +    - DT     - Device Tree
> +**/
> +
> +#ifndef DYNAMIC_TABLE_FACTORY_PROTOCOL_H_
> +#define DYNAMIC_TABLE_FACTORY_PROTOCOL_H_
> +
> +#include <AcpiTableGenerator.h>
> +#include <SmbiosTableGenerator.h>
> +#include <DeviceTreeTableGenerator.h>
> +
> +/** This macro defines the Dynamic Table Factory Protocol GUID.
> +
> +  GUID: {91D1E327-FE5A-49B8-AB65-0ECE2DDB45EC}
> +*/
> +#define EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL_GUID         \
> +  { 0x91d1e327, 0xfe5a, 0x49b8,                         \
> +    { 0xab, 0x65, 0xe, 0xce, 0x2d, 0xdb, 0x45, 0xec }   \
> +  };
> +
> +/** This macro defines the Configuration Manager Protocol Revision.
> +*/
> +#define EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL_REVISION
> CREATE_REVISION (1, 0)
> +
> +#pragma pack(1)
> +
> +/**
> +  Forward declarations:
> +*/
> +typedef struct DynamicTableFactoryProtocol
> EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL;
> +typedef struct DynamicTableFactoryInfo
> EFI_DYNAMIC_TABLE_FACTORY_INFO;
> +
> +/** Return a pointer to the ACPI table generator.
> +
> +  @param [in]  This       Pointer to the Dynamic Table Factory Protocol.
> +  @param [in]  TableId    The ACPI table generator ID for the
> +                          requested generator.
> +  @param [out] Generator  Pointer to the requested ACPI table
> +                          generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +typedef
> +EFI_STATUS
> +EFIAPI
> +(EFIAPI * EFI_DYNAMIC_TABLE_FACTORY_GET_ACPI_TABLE_GENERATOR) (
> +  IN  CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST This,
> +  IN  CONST ACPI_TABLE_GENERATOR_ID                     GeneratorId,
> +  OUT CONST ACPI_TABLE_GENERATOR               ** CONST Generator
> +  );
> +
> +/** Return a pointer to the SMBIOS table generator.
> +
> +  @param [in]  This       Pointer to the Dynamic Table Factory Protocol.
> +  @param [in]  TableId    The SMBIOS table generator ID for the
> +                          requested generator.
> +  @param [out] Generator  Pointer to the requested SMBIOS table
> +                          generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +typedef
> +EFI_STATUS
> +EFIAPI
> +(EFIAPI *
> EFI_DYNAMIC_TABLE_FACTORY_GET_SMBIOS_TABLE_GENERATOR) (
> +  IN  CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST This,
> +  IN  CONST SMBIOS_TABLE_GENERATOR_ID                   GeneratorId,
> +  OUT CONST SMBIOS_TABLE_GENERATOR             ** CONST Generator
> +  );
> +
> +/** Return a pointer to the Device Tree table generator.
> +
> +  @param [in]  This       Pointer to the Dynamic Table Factory Protocol.
> +  @param [in]  TableId    The Device Tree table generator ID for the
> +                          requested generator.
> +  @param [out] Generator  Pointer to the requested Device Tree table
> +                          generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +typedef
> +EFI_STATUS
> +EFIAPI
> +(EFIAPI * EFI_DYNAMIC_TABLE_FACTORY_GET_DT_TABLE_GENERATOR) (
> +  IN  CONST EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL  * CONST This,
> +  IN  CONST DT_TABLE_GENERATOR_ID                       GeneratorId,
> +  OUT CONST DT_TABLE_GENERATOR                 ** CONST Generator
> +  );
> +
> +/** A structure describing the Dynamic Table Factory Protocol interface.
> +*/
> +typedef struct DynamicTableFactoryProtocol {
> +  /// The Dynamic Table Factory Protocol revision.
> +  UINT32                                               Revision;
> +
> +  /// The interface used to request an ACPI Table Generator.
> +  EFI_DYNAMIC_TABLE_FACTORY_GET_ACPI_TABLE_GENERATOR
> GetAcpiTableGenerator;
> +
> +  /// The interface used to request a SMBIOS Table Generator.
> +  EFI_DYNAMIC_TABLE_FACTORY_GET_SMBIOS_TABLE_GENERATOR
> GetSmbiosTableGenerator;
> +
> +  /// The interface used to request a Device Tree Table Generator.
> +  EFI_DYNAMIC_TABLE_FACTORY_GET_DT_TABLE_GENERATOR
> GetDtTableGenerator;
> +
> +  /** Pointer to the data structure that holds the
> +      list of registered table generators
> +  */
> +  EFI_DYNAMIC_TABLE_FACTORY_INFO          * TableFactoryInfo;
> +} EFI_DYNAMIC_TABLE_FACTORY_PROTOCOL;
> +
> +/** The Dynamic Table Factory Protocol GUID.
> +*/
> +extern EFI_GUID gEfiDynamicTableFactoryProtocolGuid;
> +
> +#pragma pack()
> +
> +#endif // DYNAMIC_TABLE_FACTORY_PROTOCOL_H_
> diff --git a/DynamicTablesPkg/Include/SmbiosTableGenerator.h
> b/DynamicTablesPkg/Include/SmbiosTableGenerator.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..139d31464db473da9d
> f427e1848835f3d693c41b
> --- /dev/null
> +++ b/DynamicTablesPkg/Include/SmbiosTableGenerator.h
> @@ -0,0 +1,240 @@
> +/** @file
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#ifndef SMBIOS_TABLE_GENERATOR_H_
> +#define SMBIOS_TABLE_GENERATOR_H_
> +
> +#include <IndustryStandard/SmBios.h>
> +
> +#include <TableGenerator.h>
> +
> +#pragma pack(1)
> +
> +/** The SMBIOS_TABLE_GENERATOR_ID type describes SMBIOS table
> generator ID.
> +*/
> +typedef TABLE_GENERATOR_ID SMBIOS_TABLE_GENERATOR_ID;
> +
> +/** The ESTD_SMBIOS_TABLE_ID enum describes the SMBIOS table IDs
> reserved for
> +  the standard generators.
> +
> +  NOTE: The SMBIOS Generator IDs do not match the table type numbers!
> +          This allows 0 to be used to catch invalid parameters.
> +*/
> +typedef enum StdSmbiosTableGeneratorId {
> +  ESTD_SMBIOS_TABLE_ID_RESERVED = 0x0000,
> +  ESTD_SMBIOS_TABLE_ID_RAW,
> +  ESTD_SMBIOS_TABLE_ID_TYPE00,
> +  ESTD_SMBIOS_TABLE_ID_TYPE01,
> +  ESTD_SMBIOS_TABLE_ID_TYPE02,
> +  ESTD_SMBIOS_TABLE_ID_TYPE03,
> +  ESTD_SMBIOS_TABLE_ID_TYPE04,
> +  ESTD_SMBIOS_TABLE_ID_TYPE05,
> +  ESTD_SMBIOS_TABLE_ID_TYPE06,
> +  ESTD_SMBIOS_TABLE_ID_TYPE07,
> +  ESTD_SMBIOS_TABLE_ID_TYPE08,
> +  ESTD_SMBIOS_TABLE_ID_TYPE09,
> +  ESTD_SMBIOS_TABLE_ID_TYPE10,
> +  ESTD_SMBIOS_TABLE_ID_TYPE11,
> +  ESTD_SMBIOS_TABLE_ID_TYPE12,
> +  ESTD_SMBIOS_TABLE_ID_TYPE13,
> +  ESTD_SMBIOS_TABLE_ID_TYPE14,
> +  ESTD_SMBIOS_TABLE_ID_TYPE15,
> +  ESTD_SMBIOS_TABLE_ID_TYPE16,
> +  ESTD_SMBIOS_TABLE_ID_TYPE17,
> +  ESTD_SMBIOS_TABLE_ID_TYPE18,
> +  ESTD_SMBIOS_TABLE_ID_TYPE19,
> +  ESTD_SMBIOS_TABLE_ID_TYPE20,
> +  ESTD_SMBIOS_TABLE_ID_TYPE21,
> +  ESTD_SMBIOS_TABLE_ID_TYPE22,
> +  ESTD_SMBIOS_TABLE_ID_TYPE23,
> +  ESTD_SMBIOS_TABLE_ID_TYPE24,
> +  ESTD_SMBIOS_TABLE_ID_TYPE25,
> +  ESTD_SMBIOS_TABLE_ID_TYPE26,
> +  ESTD_SMBIOS_TABLE_ID_TYPE27,
> +  ESTD_SMBIOS_TABLE_ID_TYPE28,
> +  ESTD_SMBIOS_TABLE_ID_TYPE29,
> +  ESTD_SMBIOS_TABLE_ID_TYPE30,
> +  ESTD_SMBIOS_TABLE_ID_TYPE31,
> +  ESTD_SMBIOS_TABLE_ID_TYPE32,
> +  ESTD_SMBIOS_TABLE_ID_TYPE33,
> +  ESTD_SMBIOS_TABLE_ID_TYPE34,
> +  ESTD_SMBIOS_TABLE_ID_TYPE35,
> +  ESTD_SMBIOS_TABLE_ID_TYPE36,
> +  ESTD_SMBIOS_TABLE_ID_TYPE37,
> +  ESTD_SMBIOS_TABLE_ID_TYPE38,
> +  ESTD_SMBIOS_TABLE_ID_TYPE39,
> +  ESTD_SMBIOS_TABLE_ID_TYPE40,
> +  ESTD_SMBIOS_TABLE_ID_TYPE41,
> +  ESTD_SMBIOS_TABLE_ID_TYPE42,
> +
> +  // IDs 43 - 125 are reserved
> +
> +  ESTD_SMBIOS_TABLE_ID_TYPE126 = (ESTD_SMBIOS_TABLE_ID_TYPE00 +
> 126),
> +  ESTD_SMBIOS_TABLE_ID_TYPE127,
> +  ESTD_SMBIOS_TABLE_ID_MAX
> +} ESTD_SMBIOS_TABLE_ID;
> +
> +/** This macro checks if the Table Generator ID is for an SMBIOS Table
> +    Generator.
> +
> +  @param [in] TableGeneratorId  The table generator ID.
> +
> +  @returns  TRUE if the table generator ID is for an SMBIOS Table
> +            Generator.
> +*/
> +#define IS_GENERATOR_TYPE_SMBIOS(TableGeneratorId) \
> +          (                                        \
> +          GET_TABLE_TYPE (TableGeneratorId) ==     \
> +          ETableGeneratorTypeSmbios                \
> +          )
> +
> +/** This macro checks if the Table Generator ID is for a standard SMBIOS
> +    Table Generator.
> +
> +  @param [in] TableGeneratorId  The table generator ID.
> +
> +  @returns  TRUE if the table generator ID is for a standard SMBIOS
> +            Table Generator.
> +*/
> +#define IS_VALID_STD_SMBIOS_GENERATOR_ID(TableGeneratorId)            \
> +          (                                                           \
> +          IS_GENERATOR_NAMESPACE_STD(TableGeneratorId) &&             \
> +          IS_GENERATOR_TYPE_SMBIOS(TableGeneratorId)   &&             \
> +          ((GET_TABLE_ID(GeneratorId) >= ESTD_SMBIOS_TABLE_ID_RAW) &&
> \
> +           (GET_TABLE_ID(GeneratorId) < ESTD_SMIOS_TABLE_ID_MAX))     \
> +          )
> +
> +/** This macro creates a standard SMBIOS Table Generator ID.
> +
> +  @param [in] TableId  The table generator ID.
> +
> +  @returns a standard SMBIOS table generator ID.
> +*/
> +#define CREATE_STD_SMBIOS_TABLE_GEN_ID(TableId) \
> +          CREATE_TABLE_GEN_ID (                 \
> +            ETableGeneratorTypeSmbios,          \
> +            ETableGeneratorNameSpaceStd,        \
> +            TableId                             \
> +            )
> +
> +/** Forward declarations.
> +*/
> +typedef struct ConfigurationManagerProtocol
> EFI_CONFIGURATION_MANAGER_PROTOCOL;
> +typedef struct CmStdObjSmbiosTableInfo
> CM_STD_OBJ_SMBIOS_TABLE_INFO;
> +typedef struct SmbiosTableGenerator         SMBIOS_TABLE_GENERATOR;
> +
> +/** This function pointer describes the interface to SMBIOS table build
> +    functions provided by the SMBIOS table generator and called by the
> +    Table Manager to build an SMBIOS table.
> +
> +  @param [in]  Generator       Pointer to the SMBIOS table generator.
> +  @param [in]  SmbiosTableInfo Pointer to the SMBIOS table information.
> +  @param [in]  CfgMgrProtocol  Pointer to the Configuration Manager
> +                               Protocol interface.
> +  @param [out] Table           Pointer to the generated SMBIOS table.
> +
> +  @returns EFI_SUCCESS  If the table is generated successfully or other
> +                        failure codes as returned by the generator.
> +*/
> +typedef EFI_STATUS (*SMBIOS_TABLE_GENERATOR_BUILD_TABLE) (
> +  IN  CONST SMBIOS_TABLE_GENERATOR              *       Generator,
> +  IN        CM_STD_OBJ_SMBIOS_TABLE_INFO        * CONST SmbiosTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       SMBIOS_STRUCTURE                   **       Table
> +  );
> +
> +/** This function pointer describes the interface to used by the
> +    Table Manager to give the generator an opportunity to free
> +    any resources allocated for building the SMBIOS table.
> +
> +  @param [in]  Generator       Pointer to the SMBIOS table generator.
> +  @param [in]  SmbiosTableInfo Pointer to the SMBIOS table information.
> +  @param [in]  CfgMgrProtocol  Pointer to the Configuration Manager
> +                               Protocol interface.
> +  @param [in]  Table           Pointer to the generated SMBIOS table.
> +
> +  @returns  EFI_SUCCESS If freed successfully or other failure codes
> +                        as returned by the generator.
> +*/
> +typedef EFI_STATUS (*SMBIOS_TABLE_GENERATOR_FREE_TABLE) (
> +  IN  CONST SMBIOS_TABLE_GENERATOR              *       Generator,
> +  IN  CONST CM_STD_OBJ_SMBIOS_TABLE_INFO        * CONST
> SmbiosTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN        SMBIOS_STRUCTURE                   **       Table
> +  );
> +
> +/** The SMBIOS_TABLE_GENERATOR structure provides an interface that
> the
> +    Table Manager can use to invoke the functions to build SMBIOS tables.
> +*/
> +typedef struct SmbiosTableGenerator {
> +  /// The SMBIOS table generator ID.
> +  SMBIOS_TABLE_GENERATOR_ID                GeneratorID;
> +
> +  /// String describing the DT table
> +  /// generator.
> +  CONST CHAR16*                            Description;
> +
> +  /// The SMBIOS table type.
> +  SMBIOS_TYPE                              Type;
> +
> +  /// SMBIOS table build function pointer.
> +  SMBIOS_TABLE_GENERATOR_BUILD_TABLE       BuildSmbiosTable;
> +
> +  /** The function to free any resources
> +      allocated for building the SMBIOS table.
> +  */
> +  SMBIOS_TABLE_GENERATOR_FREE_TABLE        FreeTableResources;
> +} SMBIOS_TABLE_GENERATOR;
> +
> +/** Register SMBIOS table factory generator.
> +
> +  The SMBIOS table factory maintains a list of the Standard and OEM
> SMBIOS
> +  table generators.
> +
> +  @param [in]  Generator       Pointer to the SMBIOS table generator.
> +
> +  @retval EFI_SUCCESS           The Generator was registered
> +                                successfully.
> +  @retval EFI_INVALID_PARAMETER The Generator ID is invalid or
> +                                the Generator pointer is NULL.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID is
> +                                already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +RegisterSmbiosTableGenerator (
> +  IN CONST SMBIOS_TABLE_GENERATOR                 * CONST Generator
> +  );
> +
> +/** Deregister SMBIOS generator.
> +
> +  This function is called by the SMBIOS table generator to deregister itself
> +  from the SMBIOS table factory.
> +
> +  @param [in]  Generator       Pointer to the SMBIOS table generator.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER The generator is invalid.
> +  @retval EFI_NOT_FOUND         The requested generator is not found
> +                                in the list of registered generators.
> +*/
> +EFI_STATUS
> +EFIAPI
> +DeregisterSmbiosTableGenerator (
> +  IN CONST SMBIOS_TABLE_GENERATOR                 * CONST Generator
> +  );
> +#pragma pack()
> +
> +#endif // SMBIOS_TABLE_GENERATOR_H_
> +
> diff --git a/DynamicTablesPkg/Include/StandardNameSpaceObjects.h
> b/DynamicTablesPkg/Include/StandardNameSpaceObjects.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..bcc9287527da4cdbc3
> 2a929ec6f68773a88a74f6
> --- /dev/null
> +++ b/DynamicTablesPkg/Include/StandardNameSpaceObjects.h
> @@ -0,0 +1,116 @@
> +/** @file
> +
> +  Copyright (c) 2017, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Cm or CM   - Configuration Manager
> +    - Obj or OBJ - Object
> +    - Std or STD - Standard
> +**/
> +
> +#ifndef STANDARD_NAMESPACE_OBJECTS_H_
> +#define STANDARD_NAMESPACE_OBJECTS_H_
> +
> +#include <AcpiTableGenerator.h>
> +#include <SmbiosTableGenerator.h>
> +
> +#pragma pack(1)
> +
> +/** A macro defining a reserved zero/NULL token value that
> +    does not identify any object.
> +*/
> +#define CM_NULL_TOKEN  0
> +
> +/** A reference token that the Configuration Manager can use
> +    to identify a Configuration Manager object.
> +
> +  This can be used to differentiate between instances of
> +  objects of the same types. The identification scheme is
> +  implementation defined and is defined by the Configuration
> +  Manager.
> +
> +  Typically the token is used to identify a specific instance
> +  from a set of objects in a call to the GetObject()/SetObject(),
> +  implemented by the Configuration Manager protocol.
> +
> +  Note: The token value 0 is reserved for a NULL token and does
> +        not identify any object.
> +*/
> +typedef UINTN   CM_OBJECT_TOKEN;
> +
> +/** The ESTD_OBJECT_ID enum describes the Object IDs
> +    in the Standard Namespace.
> +*/
> +typedef enum StdObjectID {
> +  EStdObjCfgMgrInfo = 0x00000000, ///< 0 - Configuration Manager Info
> +  EStdObjAcpiTableList,           ///< 1 - ACPI table Info List
> +  EStdObjSmbiosTableList,         ///< 2 - SMBIOS table Info List
> +  EStdObjMax
> +} ESTD_OBJECT_ID;
> +
> +/** A structure that describes the Configuration Manager Information.
> +*/
> +typedef struct CmStdObjConfigurationManagerInfo {
> +  /// The Configuration Manager Revision.
> +  UINT32  Revision;
> +
> +  /** The OEM ID. This information is used to
> +      populate the ACPI table header information.
> +  */
> +  UINT8   OemId[6];
> +} CM_STD_OBJ_CONFIGURATION_MANAGER_INFO;
> +
> +/** A structure used to describe the ACPI table generators to be invoked.
> +
> +  The AcpiTableData member of this structure may be used to directly
> provide
> +  the binary ACPI table data which is required by the following standard
> +  generators:
> +    - RAW
> +    - DSDT
> +    - SSDT
> +
> +  Providing the ACPI table data is optional and depends on the generator
> +  that is being invoked. If unused, set AcpiTableData to NULL.
> +*/
> +typedef struct CmAStdObjAcpiTableInfo {
> +  /// The signature of the ACPI Table to be installed.
> +  UINT32                         AcpiTableSignature;
> +
> +  /// The ACPI Table Generator ID.
> +  ACPI_TABLE_GENERATOR_ID        TableGeneratorId;
> +
> +  /// Optional pointer to the ACPI table data.
> +  EFI_ACPI_DESCRIPTION_HEADER  * AcpiTableData;
> +
> +} CM_STD_OBJ_ACPI_TABLE_INFO;
> +
> +/** A structure used to describe the SMBIOS table generators to be
> invoked.
> +
> +  The SmbiosTableData member of this structure is used to provide
> +  the SMBIOS table data which is required by the following standard
> +  generator(s):
> +    - RAW
> +
> +  Providing the SMBIOS table data is optional and depends on the
> +  generator that is being invoked. If unused, set the SmbiosTableData
> +  to NULL.
> +*/
> +typedef struct CmStdObjSmbiosTableInfo {
> +  /// The SMBIOS Table Generator ID.
> +  SMBIOS_TABLE_GENERATOR_ID   TableGeneratorId;
> +
> +  /// Optional pointer to the SMBIOS table data.
> +  SMBIOS_STRUCTURE           * SmbiosTableData;
> +} CM_STD_OBJ_SMBIOS_TABLE_INFO;
> +
> +#pragma pack()
> +
> +#endif // STANDARD_NAMESPACE_OBJECTS_H_
> diff --git a/DynamicTablesPkg/Include/TableGenerator.h
> b/DynamicTablesPkg/Include/TableGenerator.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..171609f1b73736596d
> edff906ef8de275f2c8cca
> --- /dev/null
> +++ b/DynamicTablesPkg/Include/TableGenerator.h
> @@ -0,0 +1,252 @@
> +/** @file
> +
> +  Copyright (c) 2017, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - ACPI   - Advanced Configuration and Power Interface
> +    - SMBIOS - System Management BIOS
> +    - DT     - Device Tree
> +**/
> +
> +#ifndef TABLE_GENERATOR_H_
> +#define TABLE_GENERATOR_H_
> +
> +/** The TABLE_GENERATOR_ID type describes the Table Generator ID
> +
> +  Table Generator ID
> +
> +_________________________________________________________
> ______________________
> +|  31 | 30 |29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17|
> 16|
> +-------------------------------------------------------------------------------
> +|TNSID|  0 |   TT   |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0|  0|
> +_________________________________________________________
> ______________________
> +_________________________________________________________
> ______________________
> +|15 | 14 | 13 | 12 | 11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0|
> +-------------------------------------------------------------------------------
> +|                                 Table ID                                    |
> +_________________________________________________________
> ______________________
> +
> +  Bit [31] - Table NameSpace ID (TNSID)
> +      0 - Standard
> +      1 - Custom/OEM
> +
> +  Bit [30] - Reserved, Must be Zero
> +
> +  Bit [29:28] - Table Type (TT)
> +       0 - ACPI Table
> +       1 - SMBIOS Table
> +       2 - DT (Device Tree) Table
> +       3 - Reserved (INVALID)
> +
> +  Bit [27:16] - Reserved, Must Be Zero
> +
> +  Bit [15:0] - Table ID
> +
> +    Standard ACPI Table IDs:
> +       0 - Reserved
> +       1 - RAW
> +       2 - FADT
> +       3 - DSDT
> +       4 - SSDT
> +       5 - MADT
> +       6 - GTDT
> +       7 - DBG2
> +       8 - SPCR
> +       9 - MCFG
> +
> +    Standard SMBIOS Table IDs:
> +       0 - Reserved
> +       1 - RAW
> +       2 - Table Type00
> +       3 - Table Type01
> +       4 - Table Type02
> +       5 - Table Type03
> +       6 - Table Type04
> +       7 - Table Type05
> +       8 - Table Type06
> +       9 - Table Type07
> +      10 - Table Type08
> +      11 - Table Type09
> +      12 - Table Type10
> +      13 - Table Type11
> +      14 - Table Type12
> +      15 - Table Type13
> +      16 - Table Type14
> +      17 - Table Type15
> +      18 - Table Type16
> +      19 - Table Type17
> +      20 - Table Type18
> +      21 - Table Type19
> +      22 - Table Type20
> +      23 - Table Type21
> +      24 - Table Type22
> +      25 - Table Type23
> +      26 - Table Type24
> +      27 - Table Type25
> +      28 - Table Type26
> +      29 - Table Type27
> +      30 - Table Type28
> +      31 - Table Type29
> +      32 - Table Type30
> +      33 - Table Type31
> +      34 - Table Type32
> +      35 - Table Type33
> +      36 - Table Type34
> +      37 - Table Type35
> +      38 - Table Type36
> +      39 - Table Type37
> +      40 - Table Type38
> +      41 - Table Type39
> +      42 - Table Type40
> +      43 - Table Type41
> +      44 - Table Type42
> +  45-127 - Reserved
> +     128 - Table Type126
> +     129 - Table Type127
> +**/
> +typedef UINT32  TABLE_GENERATOR_ID;
> +
> +/** This enum lists the Table Generator Types.
> +*/
> +typedef enum TableGeneratorType {
> +  ETableGeneratorTypeAcpi = 0,  ///< ACPI Table Generator Type.
> +  ETableGeneratorTypeSmbios,    ///< SMBIOS Table Generator Type.
> +  ETableGeneratorTypeDt,        ///< Device Tree Table Generator Type.
> +  ETableGeneratorTypeReserved
> +} ETABLE_GENERATOR_TYPE;
> +
> +/** This enum lists the namespaces for the Table Generators.
> +*/
> +typedef enum TableGeneratorNameSpace {
> +  ETableGeneratorNameSpaceStd = 0,  ///< Standard Namespace.
> +  ETableGeneratorNameSpaceOem       ///< OEM Namespace.
> +} ETABLE_GENERATOR_NAMESPACE;
> +
> +/** A mask for the Table ID bits of TABLE_GENERATOR_ID.
> +*/
> +#define TABLE_ID_MASK                 0xFF
> +
> +/** A mask for the Namespace ID bits of TABLE_GENERATOR_ID.
> +*/
> +#define TABLE_NAMESPACEID_MASK        (BIT31)
> +
> +/** A mask for the Table Type bits of TABLE_GENERATOR_ID.
> +*/
> +#define TABLE_TYPE_MASK               (BIT29 | BIT28)
> +
> +/** Starting bit position for the Table Type bits
> +*/
> +#define TABLE_TYPE_BIT_SHIFT          28
> +
> +/** Starting bit position for the Table Namespace ID bit
> +*/
> +#define TABLE_NAMESPACE_ID_BIT_SHIFT  31
> +
> +/** This macro returns the Table ID from the TableGeneratorId.
> +
> +  @param [in]  TableGeneratorId  The table generator ID.
> +
> +  @returns the Table ID described by the TableGeneratorId.
> +*/
> +#define GET_TABLE_ID(TableGeneratorId)         \
> +          ((TableGeneratorId) & TABLE_ID_MASK)
> +
> +/** This macro returns the Table type from the TableGeneratorId.
> +
> +  @param [in]  TableGeneratorId  The table generator ID.
> +
> +  @returns the Table type described by the TableGeneratorId.
> +*/
> +#define GET_TABLE_TYPE(TableGeneratorId)                                   \
> +          (((TableGeneratorId) & TABLE_TYPE_MASK) >>
> TABLE_TYPE_BIT_SHIFT)
> +
> +/** This macro returns the Namespace ID from the TableGeneratorId.
> +
> +  @param [in]  TableGeneratorId  The table generator ID.
> +
> +  @returns the Namespace described by the TableGeneratorId.
> +*/
> +#define GET_TABLE_NAMESPACEID(TableGeneratorId)             \
> +          (((TableGeneratorId) & TABLE_NAMESPACEID_MASK) >> \
> +            TABLE_NAMESPACE_ID_BIT_SHIFT)
> +
> +/** This macro checks if the TableGeneratorId is in the Standard
> Namespace.
> +
> +  @param [in]  TableGeneratorId  The table generator ID.
> +
> +  @returns TRUE if the TableGeneratorId is in the Standard Namespace.
> +*/
> +#define IS_GENERATOR_NAMESPACE_STD(TableGeneratorId) \
> +          (                                          \
> +          GET_TABLE_NAMESPACEID(TableGeneratorId) == \
> +          ETableGeneratorNameSpaceStd                \
> +          )
> +
> +/** This macro creates a TableGeneratorId
> +
> +  @param [in]  TableType        The table type.
> +  @param [in]  TableNameSpaceId The namespace ID for the table.
> +  @param [in]  TableId          The table ID.
> +
> +  @returns a TableGeneratorId calculated from the inputs.
> +*/
> +#define CREATE_TABLE_GEN_ID(TableType, TableNameSpaceId, TableId)
> \
> +          ((((TableType) << TABLE_TYPE_BIT_SHIFT) & TABLE_TYPE_MASK) | \
> +           (((TableNameSpaceId) << TABLE_NAMESPACE_ID_BIT_SHIFT) &     \
> +             TABLE_NAMESPACEID_MASK) | ((TableId) & TABLE_ID_MASK))
> +
> +/** Starting bit position for MAJOR revision
> +*/
> +#define MAJOR_REVISION_BIT_SHIFT  16
> +
> +/** A mask for Major revision.
> +*/
> +#define MAJOR_REVISION_MASK       0xFFFF
> +
> +/** A mask for Minor revision.
> +*/
> +#define MINOR_REVISION_MASK       0xFFFF
> +
> +/** This macro generates a Major.Minor version
> +    where the Major and Minor fields are 16 bit.
> +
> +  @param [in]  Major  The Major revision.
> +  @param [in]  Minor  The Minor revision.
> +
> +  @returns a 32 bit representation of the type Major.Minor.
> +*/
> +#define CREATE_REVISION(Major, Minor)                                      \
> +          ((((Major) & MAJOR_REVISION_MASK) <<
> MAJOR_REVISION_BIT_SHIFT) | \
> +            ((Minor) & MINOR_REVISION_MASK))
> +
> +/** This macro returns the Major revision
> +
> +  Extracts Major from the 32 bit representation of the type Major.Minor
> +
> +  @param [in]  Revision  The Revision value which is 32 bit.
> +
> +  @returns the Major part of the revision.
> +*/
> +#define GET_MAJOR_REVISION(Revision)                                       \
> +          (((Revision) >> MAJOR_REVISION_BIT_SHIFT) &
> MAJOR_REVISION_MASK)
> +
> +/** This macro returns the Minor revision
> +
> +  Extracts Minor from the 32 bit representation of the type Major.Minor
> +
> +  @param [in]  Revision  The Revision value which is 32 bit.
> +
> +  @returns the Minor part of the revision.
> +*/
> +#define GET_MINOR_REVISION(Revision)  ((Revision) &
> MINOR_REVISION_MASK)
> +
> +#endif // TABLE_GENERATOR_H_
> +
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/AcpiDbg2LibArm.i
> nf
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/AcpiDbg2LibArm.i
> nf
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..e81ad7018334075758
> 441b1180a6a2d5e8565db3
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/AcpiDbg2LibArm.i
> nf
> @@ -0,0 +1,47 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x00010019
> +  BASE_NAME      = AcpiDbg2LibArm
> +  FILE_GUID      = A17BA4F0-3DEB-4FE5-BD27-EC008E541B22
> +  VERSION_STRING = 1.0
> +  MODULE_TYPE    = DXE_DRIVER
> +  LIBRARY_CLASS  = NULL|DXE_DRIVER
> +  CONSTRUCTOR    = AcpiDbg2LibConstructor
> +  DESTRUCTOR     = AcpiDbg2LibDestructor
> +
> +[Sources]
> +  Dbg2Generator.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  ArmPlatformPkg/ArmPlatformPkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  SerialPortLib
> +
> +[FixedPcd]
> +  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
> +  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
> +  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
> +  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
> +
> +[Protocols]
> +
> +[Guids]
> +
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/Dbg2Generator.c
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/Dbg2Generator.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..910b9b68f43b4a9e7d
> 0d8e9a8c879abb172a9678
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/Dbg2Generator.c
> @@ -0,0 +1,440 @@
> +/** @file
> +  DBG2 Table Generator
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Reference(s):
> +  - Microsoft Debug Port Table 2 (DBG2) Specification - December 10, 2015.
> +
> +**/
> +
> +#include <IndustryStandard/DebugPort2Table.h>
> +#include <Library/AcpiLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/PL011UartLib.h>
> +#include <Protocol/AcpiTable.h>
> +#include <Protocol/SerialIo.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <Library/TableHelperLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +
> +/** ARM standard DBG2 Table Generator
> +
> +  Constructs the DBG2 table for PL011 or SBSA UART peripherals.
> +
> +Requirements:
> +  The following Configuration Manager Object(s) are required by
> +  this Generator:
> +  - EArmObjSerialDebugPortInfo
> +*/
> +
> +#pragma pack(1)
> +
> +/** The number of debug ports represented by the Table.
> +*/
> +#define DBG2_NUM_DEBUG_PORTS                       1
> +
> +/** The number of Generic Address Registers
> +    presented in the debug device information.
> +*/
> +#define DBG2_NUMBER_OF_GENERIC_ADDRESS_REGISTERS   1
> +
> +/** The index for the debug port 1 in the Debug port information list.
> +*/
> +#define DBG_PORT_INDEX_PORT1                       0
> +
> +/** A string representing the name of the debug port 1.
> +*/
> +#define NAME_STR_PORT1                            "COM1"
> +
> +/** The length of the namespace string.
> +*/
> +#define DBG2_NAMESPACESTRING_FIELD_SIZE            sizeof
> (NAME_STR_PORT1)
> +
> +/** The PL011 UART address range length.
> +*/
> +#define PL011_UART_LENGTH                          0x1000
> +
> +/** A structure that provides the OS with the required information
> +    for initializing a debugger connection.
> +*/
> +typedef struct {
> +  /// The debug device information for the platform
> +  EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT Dbg2Device;
> +
> +  /// The base address register for the serial port
> +  EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE        BaseAddressRegister;
> +
> +  /// The address size
> +  UINT32 AddressSize;
> +
> +  /// The debug port name string
> +  UINT8  NameSpaceString[DBG2_NAMESPACESTRING_FIELD_SIZE];
> +} DBG2_DEBUG_DEVICE_INFORMATION;
> +
> +/** A structure representing the information about the debug port(s)
> +    available on the platform.
> +*/
> +typedef struct {
> +  /// The DBG2 table header
> +  EFI_ACPI_DEBUG_PORT_2_DESCRIPTION_TABLE Description;
> +
> +  /// Debug port information list
> +  DBG2_DEBUG_DEVICE_INFORMATION
> Dbg2DeviceInfo[DBG2_NUM_DEBUG_PORTS];
> +} DBG2_TABLE;
> +
> +/** A helper macro used for initializing the debug port device
> +    information structure.
> +
> +  @param [in]  NumReg       The number of generic address registers.
> +  @param [in]  SubType      The DBG Port SubType.
> +  @param [in]  UartBase     The UART port base address.
> +  @param [in]  UartAddrLen  The UART port address range length.
> +  @param [in]  UartNameStr  The UART port name string.
> +*/
> +#define DBG2_DEBUG_PORT_DDI(                                          \
> +          NumReg,                                                     \
> +          SubType,                                                    \
> +          UartBase,                                                   \
> +          UartAddrLen,                                                \
> +          UartNameStr                                                 \
> +          ) {                                                         \
> +    {                                                                 \
> +      /* UINT8     Revision */                                        \
> +      EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION,
> \
> +      /* UINT16    Length */                                          \
> +      sizeof (DBG2_DEBUG_DEVICE_INFORMATION),                         \
> +      /* UINT8     NumberofGenericAddressRegisters */                 \
> +      NumReg,                                                         \
> +      /* UINT16    NameSpaceStringLength */                           \
> +      DBG2_NAMESPACESTRING_FIELD_SIZE,                                \
> +      /* UINT16    NameSpaceStringOffset */                           \
> +      OFFSET_OF (DBG2_DEBUG_DEVICE_INFORMATION, NameSpaceString),
> \
> +      /* UINT16    OemDataLength */                                   \
> +      0,                                                              \
> +      /* UINT16    OemDataOffset */                                   \
> +      0,                                                              \
> +      /* UINT16    Port Type */                                       \
> +      EFI_ACPI_DBG2_PORT_TYPE_SERIAL,                                 \
> +      /* UINT16    Port Subtype */                                    \
> +      SubType,                                                        \
> +      /* UINT8     Reserved[2] */                                     \
> +      {EFI_ACPI_RESERVED_BYTE, EFI_ACPI_RESERVED_BYTE},               \
> +      /* UINT16    BaseAddressRegister Offset */                      \
> +      OFFSET_OF (DBG2_DEBUG_DEVICE_INFORMATION,
> BaseAddressRegister), \
> +      /* UINT16    AddressSize Offset */                              \
> +      OFFSET_OF (DBG2_DEBUG_DEVICE_INFORMATION, AddressSize)
> \
> +    },                                                                \
> +    /* EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE BaseAddressRegister
> */  \
> +    ARM_GAS32 (UartBase),                                             \
> +    /* UINT32  AddressSize */                                         \
> +    UartAddrLen,                                                      \
> +    /* UINT8   NameSpaceString[MAX_DBG2_NAME_LEN] */                  \
> +    UartNameStr                                                       \
> +  }
> +
> +/** The DBG2 Table template definition.
> +
> +  Note: fields marked with "{Template}" will be set dynamically
> +*/
> +STATIC
> +DBG2_TABLE AcpiDbg2 = {
> +  {
> +    ACPI_HEADER (
> +      EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE,
> +      DBG2_TABLE,
> +      EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION
> +      ),
> +    OFFSET_OF (DBG2_TABLE, Dbg2DeviceInfo),
> +    DBG2_NUM_DEBUG_PORTS
> +  },
> +  {
> +    /*
> +     * Debug port 1
> +     */
> +    DBG2_DEBUG_PORT_DDI (
> +      DBG2_NUMBER_OF_GENERIC_ADDRESS_REGISTERS,
> +      0,                    // {Template}: Serial Port Subtype
> +      0,                    // {Template}: Serial Port Base Address
> +      PL011_UART_LENGTH,
> +      NAME_STR_PORT1
> +      )
> +  }
> +};
> +
> +#pragma pack()
> +
> +/** This macro expands to a function that retrieves the Serial
> +    debug port information from the Configuration Manager
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjSerialDebugPortInfo,
> +  CM_ARM_SERIAL_PORT_INFO
> +  );
> +
> +/** Initialize the PL011 UART with the parameters obtained from
> +    the Configuration Manager.
> +
> +  @param [in]  SerialPortInfo Pointer to the Serial Port Information.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER The parameters for serial port
> initialization
> +                                are invalid.
> +*/
> +STATIC
> +EFI_STATUS
> +SetupDebugUart (
> +  IN  CONST CM_ARM_SERIAL_PORT_INFO  * CONST SerialPortInfo
> +  )
> +{
> +  EFI_STATUS          Status;
> +  UINT64              BaudRate;
> +  UINT32              ReceiveFifoDepth;
> +  EFI_PARITY_TYPE     Parity;
> +  UINT8               DataBits;
> +  EFI_STOP_BITS_TYPE  StopBits;
> +
> +  ASSERT (SerialPortInfo != NULL);
> +
> +  // Initialize the Serial Debug UART
> +  DEBUG ((DEBUG_INFO, "Initializing Serial Debug UART...\n"));
> +  ReceiveFifoDepth = 0; // Use the default value for FIFO depth
> +  Parity = (EFI_PARITY_TYPE)FixedPcdGet8 (PcdUartDefaultParity);
> +  DataBits = FixedPcdGet8 (PcdUartDefaultDataBits);
> +  StopBits = (EFI_STOP_BITS_TYPE)FixedPcdGet8 (PcdUartDefaultStopBits);
> +
> +  BaudRate = SerialPortInfo->BaudRate;
> +  Status = PL011UartInitializePort (
> +             (UINTN)SerialPortInfo->BaseAddress,
> +             SerialPortInfo->Clock,
> +             &BaudRate,
> +             &ReceiveFifoDepth,
> +             &Parity,
> +             &DataBits,
> +             &StopBits
> +             );
> +
> +  DEBUG ((DEBUG_INFO, "Debug UART Configuration:\n"));
> +  DEBUG ((DEBUG_INFO, "UART Base  = 0x%lx\n", SerialPortInfo-
> >BaseAddress));
> +  DEBUG ((DEBUG_INFO, "Clock      = %d\n", SerialPortInfo->Clock));
> +  DEBUG ((DEBUG_INFO, "Baudrate   = %ld\n", BaudRate));
> +  DEBUG ((DEBUG_INFO, "Configuring Debug UART. Status = %r\n", Status));
> +
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> +
> +/** Construct the DBG2 ACPI table
> +
> +    The BuildDbg2Table function is called by the Dynamic Table Manager
> +    to construct the DBG2 ACPI table.
> +
> +  This function invokes the Configuration Manager protocol interface
> +  to get the required hardware information for generating the ACPI
> +  table.
> +
> +  If this function allocates any resources then they must be freed
> +  in the FreeXXXXTableResources function.
> +
> +  @param [in]  This           Pointer to the table generator.
> +  @param [in]  AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +  @param [out] Table          Pointer to the constructed ACPI Table.
> +
> +  @retval EFI_SUCCESS           Table generated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildDbg2Table (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN  CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST AcpiTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  CM_ARM_SERIAL_PORT_INFO  * SerialPortInfo;
> +
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Table != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  *Table = NULL;
> +
> +  Status = GetEArmObjSerialDebugPortInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &SerialPortInfo,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: DBG2: Failed to get serial port information. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  if (SerialPortInfo->BaseAddress == 0) {
> +    Status = EFI_INVALID_PARAMETER;
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: DBG2: Uart port base address is invalid. BaseAddress =
> 0x%lx\n",
> +      SerialPortInfo->BaseAddress
> +      ));
> +    goto error_handler;
> +  }
> +
> +  if ((SerialPortInfo->PortSubtype !=
> +      EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART) &&
> +      (SerialPortInfo->PortSubtype !=
> +
> EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X)
> &&
> +      (SerialPortInfo->PortSubtype !=
> +      EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART)
> &&
> +      (SerialPortInfo->PortSubtype !=
> +      EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_DCC)) {
> +    Status = EFI_INVALID_PARAMETER;
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: DBG2: Uart port sybtype is invalid. PortSubtype = 0x%x\n",
> +      SerialPortInfo->PortSubtype
> +      ));
> +    goto error_handler;
> +  }
> +
> +  Status = AddAcpiHeader (
> +             CfgMgrProtocol,
> +             This,
> +             (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiDbg2,
> +             sizeof (DBG2_TABLE)
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: DBG2: Failed to add ACPI header. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // Update the base address
> +
> AcpiDbg2.Dbg2DeviceInfo[DBG_PORT_INDEX_PORT1].BaseAddressRegister.
> Address =
> +    SerialPortInfo->BaseAddress;
> +
> +  // Update the serial port subtype
> +
> AcpiDbg2.Dbg2DeviceInfo[DBG_PORT_INDEX_PORT1].Dbg2Device.PortSubty
> pe =
> +    SerialPortInfo->PortSubtype;
> +
> +  // Initialize the serial port
> +  Status = SetupDebugUart (SerialPortInfo);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: DBG2: Failed to configure debug serial port. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  *Table = (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiDbg2;
> +
> +error_handler:
> +  return Status;
> +}
> +
> +/** This macro defines the DBG2 Table Generator revision.
> +*/
> +#define DBG2_GENERATOR_REVISION CREATE_REVISION (1, 0)
> +
> +/** The interface for the DBG2 Table Generator.
> +*/
> +STATIC
> +CONST
> +ACPI_TABLE_GENERATOR Dbg2Generator = {
> +  // Generator ID
> +  CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_DBG2),
> +  // Generator Description
> +  L"ACPI.STD.DBG2.GENERATOR",
> +  // ACPI Table Signature
> +  EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE,
> +  // ACPI Table Revision
> +  EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION,
> +  // Creator ID
> +  TABLE_GENERATOR_CREATOR_ID_ARM,
> +  // Creator Revision
> +  DBG2_GENERATOR_REVISION,
> +  // Build Table function
> +  BuildDbg2Table,
> +  // No additional resources are allocated by the generator.
> +  // Hence the Free Resource function is not required.
> +  NULL
> +};
> +
> +/** Register the Generator with the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is registered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID
> +                                is already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiDbg2LibConstructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = RegisterAcpiTableGenerator (&Dbg2Generator);
> +  DEBUG ((DEBUG_INFO, "DBG2: Register Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return Status;
> +}
> +
> +/** Deregister the Generator from the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is deregistered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The Generator is not registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiDbg2LibDestructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = DeregisterAcpiTableGenerator (&Dbg2Generator);
> +  DEBUG ((DEBUG_INFO, "DBG2: Deregister Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/AcpiFadtLibArm.in
> f
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/AcpiFadtLibArm.in
> f
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..db8b04845434fd7d0c
> db5230699b9279914b3900
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/AcpiFadtLibArm.in
> f
> @@ -0,0 +1,41 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x00010019
> +  BASE_NAME      = AcpiFadtLibArm
> +  FILE_GUID      = 686FE5FE-B944-485F-8B1C-7D60E0056487
> +  VERSION_STRING = 1.0
> +  MODULE_TYPE    = DXE_DRIVER
> +  LIBRARY_CLASS  = NULL|DXE_DRIVER
> +  CONSTRUCTOR    = AcpiFadtLibConstructor
> +  DESTRUCTOR     = AcpiFadtLibDestructor
> +
> +[Sources]
> +  FadtGenerator.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +
> +[Pcd]
> +
> +[Protocols]
> +
> +[Guids]
> +
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/FadtGenerator.c
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/FadtGenerator.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..f33c3ef9a77cd980ff26
> 8a21c933026bdde7ccf7
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/FadtGenerator.c
> @@ -0,0 +1,666 @@
> +/** @file
> +  FADT Table Generator
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Reference(s):
> +  - ACPI 6.2 Specification - Errata A, September 2017
> +
> +**/
> +
> +#include <Library/AcpiLib.h>
> +#include <Library/DebugLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <Library/TableHelperLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +
> +/** ARM standard FADT Generator
> +
> +Requirements:
> +  The following Configuration Manager Object(s) are required by
> +  this Generator:
> +  - EArmObjPowerManagementProfileInfo
> +  - EArmObjBootArchInfo
> +  - EArmObjHypervisorVendorIdentity (OPTIONAL)
> +*/
> +
> +/** This macro defines the FADT flag options for ARM Platforms.
> +*/
> +#define FADT_FLAGS  (EFI_ACPI_6_2_HW_REDUCED_ACPI |          \
> +                     EFI_ACPI_6_2_LOW_POWER_S0_IDLE_CAPABLE)
> +
> +/** This macro defines the valid mask for the FADT flag option
> +    if HW_REDUCED_ACPI flag in the table is set.
> +
> +  Invalid bits are: 1, 2, 3,7, 8, 13, 14,16, 17 and
> +    22-31 (reserved).
> +
> +  Valid bits are:
> +    EFI_ACPI_6_2_WBINVD                               BIT0
> +    EFI_ACPI_6_2_PWR_BUTTON                           BIT4
> +    EFI_ACPI_6_2_SLP_BUTTON                           BIT5
> +    EFI_ACPI_6_2_FIX_RTC                              BIT6
> +    EFI_ACPI_6_2_DCK_CAP                              BIT9
> +    EFI_ACPI_6_2_RESET_REG_SUP                        BIT10
> +    EFI_ACPI_6_2_SEALED_CASE                          BIT11
> +    EFI_ACPI_6_2_HEADLESS                             BIT12
> +    EFI_ACPI_6_2_USE_PLATFORM_CLOCK                   BIT15
> +    EFI_ACPI_6_2_FORCE_APIC_CLUSTER_MODEL             BIT18
> +    EFI_ACPI_6_2_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19
> +    EFI_ACPI_6_2_HW_REDUCED_ACPI                      BIT20
> +    EFI_ACPI_6_2_LOW_POWER_S0_IDLE_CAPABLE            BIT21
> +*/
> +#define VALID_HARDWARE_REDUCED_FLAG_MASK  (                   \
> +          EFI_ACPI_6_2_WBINVD                               | \
> +          EFI_ACPI_6_2_PWR_BUTTON                           | \
> +          EFI_ACPI_6_2_SLP_BUTTON                           | \
> +          EFI_ACPI_6_2_FIX_RTC                              | \
> +          EFI_ACPI_6_2_DCK_CAP                              | \
> +          EFI_ACPI_6_2_RESET_REG_SUP                        | \
> +          EFI_ACPI_6_2_SEALED_CASE                          | \
> +          EFI_ACPI_6_2_HEADLESS                             | \
> +          EFI_ACPI_6_2_USE_PLATFORM_CLOCK                   | \
> +          EFI_ACPI_6_2_FORCE_APIC_CLUSTER_MODEL             | \
> +          EFI_ACPI_6_2_FORCE_APIC_PHYSICAL_DESTINATION_MODE | \
> +          EFI_ACPI_6_2_HW_REDUCED_ACPI                      | \
> +          EFI_ACPI_6_2_LOW_POWER_S0_IDLE_CAPABLE)
> +
> +#pragma pack(1)
> +
> +/** The AcpiFadt is a template
> EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE
> +    structure used for generating the FADT Table.
> +  Note: fields marked with "{Template}" will be updated dynamically.
> +*/
> +STATIC
> +EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE AcpiFadt = {
> +  ACPI_HEADER (
> +    EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
> +    EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE,
> +    EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_REVISION
> +    ),
> +  // UINT32     FirmwareCtrl
> +  0,
> +  // UINT32     Dsdt
> +  0,
> +  // UINT8      Reserved0
> +  EFI_ACPI_RESERVED_BYTE,
> +  // UINT8      PreferredPmProfile
> +  EFI_ACPI_6_2_PM_PROFILE_UNSPECIFIED,  // {Template}: Power
> Management Profile
> +  // UINT16     SciInt
> +  0,
> +  // UINT32     SmiCmd
> +  0,
> +  // UINT8      AcpiEnable
> +  0,
> +  // UINT8      AcpiDisable
> +  0,
> +  // UINT8      S4BiosReq
> +  0,
> +  // UINT8      PstateCnt
> +  0,
> +  // UINT32     Pm1aEvtBlk
> +  0,
> +  // UINT32     Pm1bEvtBlk
> +  0,
> +  // UINT32     Pm1aCntBlk
> +  0,
> +  // UINT32     Pm1bCntBlk
> +  0,
> +  // UINT32     Pm2CntBlk
> +  0,
> +  // UINT32     PmTmrBlk
> +  0,
> +  // UINT32     Gpe0Blk
> +  0,
> +  // UINT32     Gpe1Blk
> +  0,
> +  // UINT8      Pm1EvtLen
> +  0,
> +  // UINT8      Pm1CntLen
> +  0,
> +  // UINT8      Pm2CntLen
> +  0,
> +  // UINT8      PmTmrLen
> +  0,
> +  // UINT8      Gpe0BlkLen
> +  0,
> +  // UINT8      Gpe1BlkLen
> +  0,
> +  // UINT8      Gpe1Base
> +  0,
> +  // UINT8      CstCnt
> +  0,
> +  // UINT16     PLvl2Lat
> +  0,
> +  // UINT16     PLvl3Lat
> +  0,
> +  // UINT16     FlushSize
> +  0,
> +  // UINT16     FlushStride
> +  0,
> +  // UINT8      DutyOffset
> +  0,
> +  // UINT8      DutyWidth
> +  0,
> +  // UINT8      DayAlrm
> +  0,
> +  // UINT8      MonAlrm
> +  0,
> +  // UINT8      Century
> +  0,
> +  // UINT16     IaPcBootArch
> +  0,
> +  // UINT8      Reserved1
> +  0,
> +  // UINT32     Flags
> +  FADT_FLAGS,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  ResetReg
> +  NULL_GAS,
> +  // UINT8      ResetValue
> +  0,
> +  // UINT16     ArmBootArch
> +  EFI_ACPI_6_2_ARM_PSCI_COMPLIANT,  // {Template}: ARM Boot
> Architecture Flags
> +  // UINT8      MinorRevision
> +  EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION,
> +  // UINT64     XFirmwareCtrl
> +  0,
> +  // UINT64     XDsdt
> +  0,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  XPm1aEvtBlk
> +  NULL_GAS,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  XPm1bEvtBlk
> +  NULL_GAS,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  XPm1aCntBlk
> +  NULL_GAS,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  XPm1bCntBlk
> +  NULL_GAS,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  XPm2CntBlk
> +  NULL_GAS,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  XPmTmrBlk
> +  NULL_GAS,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  XGpe0Blk
> +  NULL_GAS,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  XGpe1Blk
> +  NULL_GAS,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  SleepControlReg
> +  NULL_GAS,
> +  // EFI_ACPI_6_2_GENERIC_ADDRESS_STRUCTURE  SleepStatusReg
> +  NULL_GAS,
> +  // UINT64     HypervisorVendorIdentity
> +  EFI_ACPI_RESERVED_QWORD  // {Template}: Hypervisor Vendor ID
> +};
> +
> +#pragma pack()
> +
> +/** This macro expands to a function that retrieves the Power
> +    Management Profile Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjPowerManagementProfileInfo,
> +  CM_ARM_POWER_MANAGEMENT_PROFILE_INFO
> +  );
> +
> +/** This macro expands to a function that retrieves the Boot
> +    Architecture Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjBootArchInfo,
> +  CM_ARM_BOOT_ARCH_INFO
> +  );
> +
> +/** This macro expands to a function that retrieves the Hypervisor
> +    Vendor ID from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjHypervisorVendorIdentity,
> +  CM_ARM_HYPERVISOR_VENDOR_ID
> +  );
> +
> +/** This macro expands to a function that retrieves the Fixed
> +  feature flags for the platform from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjFixedFeatureFlags,
> +  CM_ARM_FIXED_FEATURE_FLAGS
> +  );
> +
> +/** Update the Power Management Profile information in the FADT Table.
> +
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +FadtAddPmProfileInfo (
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol
> +)
> +{
> +  EFI_STATUS                              Status;
> +  CM_ARM_POWER_MANAGEMENT_PROFILE_INFO  * PmProfile;
> +
> +  ASSERT (CfgMgrProtocol != NULL);
> +
> +  // Get the Power Management Profile from the Platform Configuration
> Manager
> +  Status = GetEArmObjPowerManagementProfileInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &PmProfile,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: FADT: Failed to get Power Management Profile information." \
> +      " Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "FADT: PreferredPmProfile = 0x%x\n",
> +    PmProfile->PowerManagementProfile
> +    ));
> +
> +  AcpiFadt.PreferredPmProfile = PmProfile->PowerManagementProfile;
> +
> +error_handler:
> +  return Status;
> +}
> +
> +/** Updates the Boot Architecture information in the FADT Table.
> +
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +FadtAddBootArchInfo (
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol
> +)
> +{
> +  EFI_STATUS               Status;
> +  CM_ARM_BOOT_ARCH_INFO  * BootArchInfo;
> +
> +  ASSERT (CfgMgrProtocol != NULL);
> +
> +  // Get the Boot Architecture flags from the Platform Configuration
> Manager
> +  Status = GetEArmObjBootArchInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &BootArchInfo,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: FADT: Failed to get Boot Architecture flags. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "FADT BootArchFlag = 0x%x\n",
> +    BootArchInfo->BootArchFlags
> +    ));
> +
> +  AcpiFadt.ArmBootArch = BootArchInfo->BootArchFlags;
> +
> +error_handler:
> +  return Status;
> +}
> +
> +/** Update the Hypervisor Vendor ID in the FADT Table.
> +
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +FadtAddHypervisorVendorId (
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol
> +)
> +{
> +  EFI_STATUS                     Status;
> +  CM_ARM_HYPERVISOR_VENDOR_ID  * HypervisorVendorInfo;
> +
> +  ASSERT (CfgMgrProtocol != NULL);
> +
> +  // Get the Hypervisor Vendor ID from the Platform Configuration
> Manager
> +  Status = GetEArmObjHypervisorVendorIdentity (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &HypervisorVendorInfo,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    if (Status == EFI_NOT_FOUND) {
> +      DEBUG ((
> +        DEBUG_INFO,
> +        "INFO: FADT: Platform does not have a Hypervisor Vendor ID."
> +        "Status = %r\n",
> +        Status
> +        ));
> +    } else {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: FADT: Failed to get Hypervisor Vendor ID. Status = %r\n",
> +        Status
> +        ));
> +    }
> +    goto error_handler;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "FADT: EArmObjHypervisorVendorIdentity = 0x%lx\n",
> +    HypervisorVendorInfo->HypervisorVendorId
> +    ));
> +
> +  AcpiFadt.HypervisorVendorIdentity = HypervisorVendorInfo-
> >HypervisorVendorId;
> +
> +error_handler:
> +  return Status;
> +}
> +
> +/** Update the Fixed Feature Flags in the FADT Table.
> +
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +FadtAddFixedFeatureFlags (
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol
> +)
> +{
> +  EFI_STATUS                    Status;
> +  CM_ARM_FIXED_FEATURE_FLAGS  * FixedFeatureFlags;
> +
> +  ASSERT (CfgMgrProtocol != NULL);
> +
> +  // Get the Fixed feature flags from the Platform Configuration Manager
> +  Status = GetEArmObjFixedFeatureFlags (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &FixedFeatureFlags,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    if (Status == EFI_NOT_FOUND) {
> +      DEBUG ((
> +        DEBUG_INFO,
> +        "INFO: FADT: Platform does not define additional Fixed feature flags."
> +        "Status = %r\n",
> +        Status
> +        ));
> +    } else {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: FADT: Failed to get Fixed feature flags. Status = %r\n",
> +        Status
> +        ));
> +    }
> +    goto error_handler;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "FADT: EArmObjFixedFeatureFlags = 0x%x\n",
> +    FixedFeatureFlags->Flags
> +    ));
> +
> +  if ((FixedFeatureFlags->Flags &
> ~(VALID_HARDWARE_REDUCED_FLAG_MASK)) != 0) {
> +    DEBUG ((
> +      DEBUG_WARN,
> +      "FADT: Invalid Fixed feature flags defined by platform,"
> +      "Invalid Flags bits are = 0x%x\n",
> +      (FixedFeatureFlags->Flags &
> ~(VALID_HARDWARE_REDUCED_FLAG_MASK))
> +      ));
> +  }
> +
> +  AcpiFadt.Flags |= (FixedFeatureFlags->Flags &
> +                     VALID_HARDWARE_REDUCED_FLAG_MASK);
> +
> +error_handler:
> +  return Status;
> +}
> +
> +/** Construct the FADT table.
> +
> +  This function invokes the Configuration Manager protocol interface
> +  to get the required hardware information for generating the ACPI
> +  table.
> +
> +  If this function allocates any resources then they must be freed
> +  in the FreeXXXXTableResources function.
> +
> +  @param [in]  This           Pointer to the table generator.
> +  @param [in]  AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +  @param [out] Table          Pointer to the constructed ACPI Table.
> +
> +  @retval EFI_SUCCESS           Table generated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildFadtTable (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN  CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST AcpiTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Table != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  *Table = NULL;
> +
> +  Status = AddAcpiHeader (
> +             CfgMgrProtocol,
> +             This,
> +             (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiFadt,
> +             sizeof (EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE)
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: FADT: Failed to add ACPI header. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // Update PmProfile Info
> +  Status = FadtAddPmProfileInfo (CfgMgrProtocol);
> +  if (EFI_ERROR (Status)) {
> +    goto error_handler;
> +  }
> +
> +  // Update BootArch Info
> +  Status = FadtAddBootArchInfo (CfgMgrProtocol);
> +  if (EFI_ERROR (Status)) {
> +    goto error_handler;
> +  }
> +
> +  // Add the Hypervisor Vendor Id if present
> +  // Note if no hypervisor is present the zero bytes
> +  // will be placed in this field.
> +  Status = FadtAddHypervisorVendorId (CfgMgrProtocol);
> +  if (EFI_ERROR (Status)) {
> +    if (Status == EFI_NOT_FOUND) {
> +      DEBUG ((
> +        DEBUG_INFO,
> +        "INFO: FADT: No Hypervisor Vendor ID found," \
> +        " assuming no Hypervisor is present in the firmware.\n"
> +        ));
> +    } else {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: FADT: Error reading Hypervisor Vendor ID, Status = %r",
> +        Status
> +        ));
> +      goto error_handler;
> +    }
> +  }
> +
> +  Status = FadtAddFixedFeatureFlags (CfgMgrProtocol);
> +  if (EFI_ERROR (Status)) {
> +    if (Status == EFI_NOT_FOUND) {
> +      DEBUG ((
> +        DEBUG_INFO,
> +        "INFO: FADT: No Fixed feature flags found," \
> +        " assuming no additional flags are defined for the platform.\n"
> +        ));
> +      Status = EFI_SUCCESS;
> +    } else {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: FADT: Error reading Fixed feature flags, Status = %r",
> +        Status
> +        ));
> +      goto error_handler;
> +    }
> +  }
> +
> +  *Table = (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiFadt;
> +error_handler:
> +  return Status;
> +}
> +
> +/** This macro defines the FADT Table Generator revision.
> +*/
> +#define FADT_GENERATOR_REVISION CREATE_REVISION (1, 0)
> +
> +/** The interface for the FADT Table Generator.
> +*/
> +STATIC
> +CONST
> +ACPI_TABLE_GENERATOR FadtGenerator = {
> +  // Generator ID
> +  CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_FADT),
> +  // Generator Description
> +  L"ACPI.STD.FADT.GENERATOR",
> +  // ACPI Table Signature
> +  EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
> +  // ACPI Table Revision
> +  EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_REVISION,
> +  // Creator ID
> +  TABLE_GENERATOR_CREATOR_ID_ARM,
> +  // Creator Revision
> +  FADT_GENERATOR_REVISION,
> +  // Build Table function
> +  BuildFadtTable,
> +  // No additional resources are allocated by the generator.
> +  // Hence the Free Resource function is not required.
> +  NULL
> +};
> +
> +/** Register the Generator with the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is registered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID
> +                                is already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiFadtLibConstructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = RegisterAcpiTableGenerator (&FadtGenerator);
> +  DEBUG ((DEBUG_INFO, "FADT: Register Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> +
> +/** Deregister the Generator from the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is deregistered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The Generator is not registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiFadtLibDestructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = DeregisterAcpiTableGenerator (&FadtGenerator);
> +  DEBUG ((DEBUG_INFO, "FADT: Deregister Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/AcpiGtdtLibArm.in
> f
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/AcpiGtdtLibArm.in
> f
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..701cc8b019f564469fc
> 1ec411ed11b367c48ff01
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/AcpiGtdtLibArm.in
> f
> @@ -0,0 +1,41 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x00010019
> +  BASE_NAME      = AcpiGtdtLibArm
> +  FILE_GUID      = 26490F7A-7FA2-423C-8939-C6206329BC37
> +  VERSION_STRING = 1.0
> +  MODULE_TYPE    = DXE_DRIVER
> +  LIBRARY_CLASS  = NULL|DXE_DRIVER
> +  CONSTRUCTOR    = AcpiGtdtLibConstructor
> +  DESTRUCTOR     = AcpiGtdtLibDestructor
> +
> +[Sources]
> +  GtdtGenerator.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +
> +[FixedPcd]
> +
> +[Protocols]
> +
> +[Guids]
> +
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..3bc34769346eeedb9c
> 75ce76148d187b61b6fac1
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
> @@ -0,0 +1,670 @@
> +/** @file
> +  GTDT Table Generator
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Reference(s):
> +  - ACPI 6.2 Specification - Errata A, September 2017
> +
> +**/
> +
> +#include <Library/AcpiLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <Library/TableHelperLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +
> +/** ARM standard GTDT Generator
> +
> +Requirements:
> +  The following Configuration Manager Object(s) are required by
> +  this Generator:
> +  - EArmObjGenericTimerInfo
> +  - EArmObjPlatformGenericWatchdogInfo (OPTIONAL)
> +  - EArmObjPlatformGTBlockInfo (OPTIONAL)
> +  - EArmObjGTBlockTimerFrameInfo (OPTIONAL)
> +*/
> +
> +/** This macro expands to a function that retrieves the Generic
> +    Timer Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjGenericTimerInfo,
> +  CM_ARM_GENERIC_TIMER_INFO
> +  );
> +
> +/** This macro expands to a function that retrieves the SBSA Generic
> +    Watchdog Timer Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjPlatformGenericWatchdogInfo,
> +  CM_ARM_GENERIC_WATCHDOG_INFO
> +  );
> +
> +/** This macro expands to a function that retrieves the Platform Generic
> +    Timer Block Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjPlatformGTBlockInfo,
> +  CM_ARM_GTBLOCK_INFO
> +  );
> +
> +/** This macro expands to a function that retrieves the Generic
> +  Timer Block Timer Frame Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjGTBlockTimerFrameInfo,
> +  CM_ARM_GTBLOCK_TIMER_FRAME_INFO
> +  );
> +
> +/** Add the Generic Timer Information to the GTDT table.
> +
> +  Also update the Platform Timer offset information if the platform
> +  implements platform timers.
> +
> +  @param [in]  CfgMgrProtocol     Pointer to the Configuration Manager
> +                                  Protocol Interface.
> +  @param [in]  Gtdt               Pointer to the GTDT Table.
> +  @param [in]  PlatformTimerCount Platform timer count.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +AddGenericTimerInfo (
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL * CONST
> CfgMgrProtocol,
> +  IN        EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE * CONST
> Gtdt,
> +  IN  CONST UINT32 PlatformTimerCount
> +)
> +{
> +  EFI_STATUS                   Status;
> +  CM_ARM_GENERIC_TIMER_INFO  * GenericTimerInfo;
> +
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Gtdt != NULL);
> +
> +  Status = GetEArmObjGenericTimerInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &GenericTimerInfo,
> +             NULL
> +             );
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: GTDT: Failed to get GenericTimerInfo. Status = %r\n",
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  Gtdt->CntControlBasePhysicalAddress =
> +    GenericTimerInfo->CounterControlBaseAddress;
> +  Gtdt->Reserved = EFI_ACPI_RESERVED_DWORD;
> +  Gtdt->SecurePL1TimerGSIV = GenericTimerInfo->SecurePL1TimerGSIV;
> +  Gtdt->SecurePL1TimerFlags = GenericTimerInfo->SecurePL1TimerFlags;
> +  Gtdt->NonSecurePL1TimerGSIV = GenericTimerInfo-
> >NonSecurePL1TimerGSIV;
> +  Gtdt->NonSecurePL1TimerFlags = GenericTimerInfo-
> >NonSecurePL1TimerFlags;
> +  Gtdt->VirtualTimerGSIV = GenericTimerInfo->VirtualTimerGSIV;
> +  Gtdt->VirtualTimerFlags = GenericTimerInfo->VirtualTimerFlags;
> +  Gtdt->NonSecurePL2TimerGSIV = GenericTimerInfo-
> >NonSecurePL2TimerGSIV;
> +  Gtdt->NonSecurePL2TimerFlags = GenericTimerInfo-
> >NonSecurePL2TimerFlags;
> +  Gtdt->CntReadBasePhysicalAddress =
> +    GenericTimerInfo->CounterReadBaseAddress;
> +  Gtdt->PlatformTimerCount = PlatformTimerCount;
> +  Gtdt->PlatformTimerOffset = (PlatformTimerCount == 0) ? 0 :
> +    sizeof (EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Add the SBSA Generic Watchdog Timers to the GTDT table.
> +
> +  @param [in]  Gtdt             Pointer to the GTDT Table.
> +  @param [in]  WatchdogOffset   Offset to the watchdog information in the
> +                                GTDT Table.
> +  @param [in]  WatchdogInfoList Pointer to the watchdog information list.
> +  @param [in]  WatchdogCount    Platform timer count.
> +*/
> +STATIC
> +VOID
> +AddGenericWatchdogList (
> +  IN EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE  * CONST Gtdt,
> +  IN CONST UINT32                                          WatchdogOffset,
> +  IN CONST CM_ARM_GENERIC_WATCHDOG_INFO            *
> WatchdogInfoList,
> +  IN       UINT32                                          WatchdogCount
> +  )
> +{
> +  EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE  *
> Watchdog;
> +
> +  ASSERT (Gtdt != NULL);
> +  ASSERT (WatchdogInfoList != NULL);
> +
> +  Watchdog =
> (EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE *)
> +             ((UINT8*)Gtdt + WatchdogOffset);
> +
> +  while (WatchdogCount-- != 0) {
> +    // Add watchdog entry
> +    DEBUG ((DEBUG_INFO, "GTDT: Watchdog = 0x%p\n", Watchdog));
> +    Watchdog->Type = EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG;
> +    Watchdog->Length =
> +      sizeof (EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE);
> +    Watchdog->Reserved = EFI_ACPI_RESERVED_BYTE;
> +    Watchdog->RefreshFramePhysicalAddress =
> +      WatchdogInfoList->RefreshFrameAddress;
> +    Watchdog->WatchdogControlFramePhysicalAddress =
> +      WatchdogInfoList->ControlFrameAddress;
> +    Watchdog->WatchdogTimerGSIV = WatchdogInfoList->TimerGSIV;
> +    Watchdog->WatchdogTimerFlags = WatchdogInfoList->Flags;
> +    Watchdog++;
> +    WatchdogInfoList++;
> +  } // for
> +}
> +
> +/** Update the GT Block Timer Frame lists in the GTDT Table.
> +
> +  @param [in]  GtBlockFrame           Pointer to the GT Block Frames
> +                                      list to be updated.
> +  @param [in]  GTBlockTimerFrameList  Pointer to the GT Block Frame
> +                                      Information List.
> +  @param [in]  GTBlockFrameCount      Number of GT Block Frames.
> +
> +  @retval EFI_SUCCESS           Table generated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +*/
> +STATIC
> +EFI_STATUS
> +AddGTBlockTimerFrames (
> +  IN       EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE *
> GtBlockFrame,
> +  IN CONST CM_ARM_GTBLOCK_TIMER_FRAME_INFO            *
> GTBlockTimerFrameList,
> +  IN       UINT32                                             GTBlockFrameCount
> +)
> +{
> +  ASSERT (GtBlockFrame != NULL);
> +  ASSERT (GTBlockTimerFrameList != NULL);
> +
> +  if (GTBlockFrameCount > 8) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: GTDT: GT Block Frame Count %d is greater than 8\n",
> +      GTBlockFrameCount
> +      ));
> +    ASSERT (GTBlockFrameCount <= 8);
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  while (GTBlockFrameCount-- != 0) {
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "GTDT: GtBlockFrame = 0x%p\n",
> +      GtBlockFrame
> +      ));
> +
> +    GtBlockFrame->GTFrameNumber = GTBlockTimerFrameList-
> >FrameNumber;
> +    GtBlockFrame->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
> +    GtBlockFrame->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
> +    GtBlockFrame->Reserved[2] = EFI_ACPI_RESERVED_BYTE;
> +
> +    GtBlockFrame->CntBaseX = GTBlockTimerFrameList-
> >PhysicalAddressCntBase;
> +    GtBlockFrame->CntEL0BaseX =
> +      GTBlockTimerFrameList->PhysicalAddressCntEL0Base;
> +
> +    GtBlockFrame->GTxPhysicalTimerGSIV =
> +      GTBlockTimerFrameList->PhysicalTimerGSIV;
> +    GtBlockFrame->GTxPhysicalTimerFlags =
> +      GTBlockTimerFrameList->PhysicalTimerFlags;
> +
> +    GtBlockFrame->GTxVirtualTimerGSIV = GTBlockTimerFrameList-
> >VirtualTimerGSIV;
> +    GtBlockFrame->GTxVirtualTimerFlags =
> +      GTBlockTimerFrameList->VirtualTimerFlags;
> +
> +    GtBlockFrame->GTxCommonFlags = GTBlockTimerFrameList-
> >CommonFlags;
> +    GtBlockFrame++;
> +    GTBlockTimerFrameList++;
> +  } // for
> +  return EFI_SUCCESS;
> +}
> +
> +/** Add the GT Block Timers in the GTDT Table.
> +
> +  @param [in]  CfgMgrProtocol   Pointer to the Configuration Manager
> +                                Protocol Interface.
> +  @param [in]  Gtdt             Pointer to the GTDT Table.
> +  @param [in]  GTBlockOffset    Offset of the GT Block
> +                                information in the GTDT Table.
> +  @param [in]  GTBlockInfo      Pointer to the GT Block
> +                                Information List.
> +  @param [in]  BlockTimerCount  Number of GT Block Timers.
> +
> +  @retval EFI_SUCCESS           Table generated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +*/
> +STATIC
> +EFI_STATUS
> +AddGTBlockList (
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL     * CONST
> CfgMgrProtocol,
> +  IN EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE  * CONST Gtdt,
> +  IN CONST UINT32                                          GTBlockOffset,
> +  IN CONST CM_ARM_GTBLOCK_INFO                     *       GTBlockInfo,
> +  IN       UINT32                                          BlockTimerCount
> +)
> +{
> +  EFI_STATUS                                    Status;
> +  EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE        * GTBlock;
> +  EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE  * GtBlockFrame;
> +  CM_ARM_GTBLOCK_TIMER_FRAME_INFO             *
> GTBlockTimerFrameList;
> +  UINT32                                        GTBlockTimerFrameCount;
> +
> +  ASSERT (Gtdt != NULL);
> +  ASSERT (GTBlockInfo != NULL);
> +
> +  GTBlock = (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE *)((UINT8*)Gtdt
> +
> +              GTBlockOffset);
> +
> +  while (BlockTimerCount-- != 0) {
> +    DEBUG ((DEBUG_INFO, "GTDT: GTBlock = 0x%p\n", GTBlock));
> +
> +    Status = GetEArmObjGTBlockTimerFrameInfo (
> +               CfgMgrProtocol,
> +               GTBlockInfo->GTBlockTimerFrameToken,
> +               &GTBlockTimerFrameList,
> +               &GTBlockTimerFrameCount
> +               );
> +    if (EFI_ERROR (Status) ||
> +        (GTBlockTimerFrameCount != GTBlockInfo-
> >GTBlockTimerFrameCount)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: GTDT: Failed to get Generic Timer Frames. Status = %r\n",
> +        Status
> +        ));
> +      return Status;
> +    }
> +
> +    GTBlock->Type = EFI_ACPI_6_2_GTDT_GT_BLOCK;
> +    GTBlock->Length = sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE)
> +
> +                        (sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE)
> *
> +                          GTBlockInfo->GTBlockTimerFrameCount);
> +
> +    GTBlock->Reserved = EFI_ACPI_RESERVED_BYTE;
> +    GTBlock->CntCtlBase = GTBlockInfo->GTBlockPhysicalAddress;
> +    GTBlock->GTBlockTimerCount = GTBlockInfo->GTBlockTimerFrameCount;
> +    GTBlock->GTBlockTimerOffset =
> +      sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE);
> +
> +    GtBlockFrame = (EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE*)
> +      ((UINT8*)GTBlock + GTBlock->GTBlockTimerOffset);
> +
> +    // Add GT Block Timer frames
> +    Status = AddGTBlockTimerFrames (
> +               GtBlockFrame,
> +               GTBlockTimerFrameList,
> +               GTBlockTimerFrameCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: GTDT: Failed to add Generic Timer Frames. Status = %r\n",
> +        Status
> +        ));
> +      return Status;
> +    }
> +
> +    // Next GTBlock
> +    GTBlock = (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE
> *)((UINT8*)GTBlock +
> +               GTBlock->Length);
> +    GTBlockInfo++;
> +  }// for
> +  return EFI_SUCCESS;
> +}
> +
> +/** Construct the GTDT ACPI table.
> +
> +  Called by the Dynamic Table Manager, this function invokes the
> +  Configuration Manager protocol interface to get the required hardware
> +  information for generating the ACPI table.
> +
> +  If this function allocates any resources then they must be freed
> +  in the FreeXXXXTableResources function.
> +
> +  @param [in]  This           Pointer to the table generator.
> +  @param [in]  AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +  @param [out] Table          Pointer to the constructed ACPI Table.
> +
> +  @retval EFI_SUCCESS           Table generated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildGtdtTable (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN  CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST AcpiTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  EFI_STATUS                                      Status;
> +  UINT32                                          TableSize;
> +  UINT32                                          PlatformTimerCount = 0;
> +  UINT32                                          WatchdogCount;
> +  UINT32                                          BlockTimerCount;
> +  CM_ARM_GENERIC_WATCHDOG_INFO                  * WatchdogInfoList;
> +  CM_ARM_GTBLOCK_INFO                           * GTBlockInfo;
> +  EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE  * Gtdt;
> +  UINT32                                          idx;
> +  UINT32                                          GTBlockOffset;
> +  UINT32                                          WatchdogOffset = 0;
> +
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Table != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  *Table = NULL;
> +  Status = GetEArmObjPlatformGTBlockInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &GTBlockInfo,
> +             &BlockTimerCount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: GTDT: Failed to Get Platform GT Block Information." \
> +      " Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  Status = GetEArmObjPlatformGenericWatchdogInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &WatchdogInfoList,
> +             &WatchdogCount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: GTDT: Failed to Get Platform Generic Watchdog Information."
> \
> +      " Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "GTDT: BlockTimerCount = %d, WatchdogCount = %d\n",
> +    BlockTimerCount,
> +    WatchdogCount
> +    ));
> +
> +  // Calculate the GTDT Table Size
> +  TableSize = sizeof (EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE);
> +  if (BlockTimerCount != 0) {
> +    GTBlockOffset = TableSize;
> +    PlatformTimerCount += BlockTimerCount;
> +    TableSize += (sizeof (EFI_ACPI_6_2_GTDT_GT_BLOCK_STRUCTURE) *
> +                  BlockTimerCount);
> +
> +    for (idx = 0; idx < BlockTimerCount; idx++) {
> +      if (GTBlockInfo[idx].GTBlockTimerFrameCount > 8) {
> +        Status = EFI_INVALID_PARAMETER;
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "GTDT: GTBockFrameCount cannot be more than 8." \
> +          " GTBockFrameCount = %d, Status = %r\n",
> +          GTBlockInfo[idx].GTBlockTimerFrameCount,
> +          Status
> +          ));
> +        goto error_handler;
> +      }
> +      TableSize += (sizeof
> (EFI_ACPI_6_2_GTDT_GT_BLOCK_TIMER_STRUCTURE) *
> +        GTBlockInfo[idx].GTBlockTimerFrameCount);
> +    }
> +
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "GTDT: GTBockOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
> +      GTBlockOffset,
> +      PlatformTimerCount
> +      ));
> +  }
> +
> +  if (WatchdogCount != 0) {
> +    WatchdogOffset = TableSize;
> +    PlatformTimerCount += WatchdogCount;
> +    TableSize += (sizeof
> (EFI_ACPI_6_2_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE) *
> +                  WatchdogCount);
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "GTDT: WatchdogOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
> +      WatchdogOffset,
> +      PlatformTimerCount
> +      ));
> +  }
> +
> +  *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
> +  if (*Table == NULL) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: GTDT: Failed to allocate memory for GTDT Table, Size = %d," \
> +      " Status = %r\n",
> +      TableSize,
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  Gtdt = (EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE*)*Table;
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "GTDT: Gtdt = 0x%p TableSize = 0x%x\n",
> +    Gtdt,
> +    TableSize
> +    ));
> +
> +  Status = AddAcpiHeader (CfgMgrProtocol, This, &Gtdt->Header,
> TableSize);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: GTDT: Failed to add ACPI header. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  Status = AddGenericTimerInfo (
> +             CfgMgrProtocol,
> +             Gtdt,
> +             PlatformTimerCount
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: GTDT: Failed to add Generic Timer Info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  if (BlockTimerCount != 0) {
> +    Status = AddGTBlockList (
> +               CfgMgrProtocol,
> +               Gtdt,
> +               GTBlockOffset,
> +               GTBlockInfo,
> +               BlockTimerCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: GTDT: Failed to add GT Block timers. Status = %r\n",
> +        Status
> +        ));
> +      goto error_handler;
> +    }
> +  }
> +
> +  if (WatchdogCount != 0) {
> +    AddGenericWatchdogList (
> +      Gtdt,
> +      WatchdogOffset,
> +      WatchdogInfoList,
> +      WatchdogCount
> +      );
> +  }
> +
> +  return Status;
> +
> +error_handler:
> +  if (*Table != NULL) {
> +    FreePool (*Table);
> +    *Table = NULL;
> +  }
> +  return Status;
> +}
> +
> +/** Free any resources allocated for constructing the GTDT.
> +
> +  @param [in]      This           Pointer to the table generator.
> +  @param [in]      AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]      CfgMgrProtocol Pointer to the Configuration Manager
> +                                  Protocol Interface.
> +  @param [in, out] Table          Pointer to the ACPI Table.
> +
> +  @retval EFI_SUCCESS           The resources were freed successfully.
> +  @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
> +*/
> +STATIC
> +EFI_STATUS
> +FreeGtdtTableResources (
> +  IN      CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN      CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST
> AcpiTableInfo,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN OUT        EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +)
> +{
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  if ((Table == NULL) || (*Table == NULL)) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: GTDT: Invalid Table Pointer\n"));
> +    ASSERT ((Table != NULL) && (*Table != NULL));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  FreePool (*Table);
> +  *Table = NULL;
> +  return EFI_SUCCESS;
> +}
> +
> +/** This macro defines the GTDT Table Generator revision.
> +*/
> +#define GTDT_GENERATOR_REVISION CREATE_REVISION (1, 0)
> +
> +/** The interface for the GTDT Table Generator.
> +*/
> +STATIC
> +CONST
> +ACPI_TABLE_GENERATOR GtdtGenerator = {
> +  // Generator ID
> +  CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_GTDT),
> +  // Generator Description
> +  L"ACPI.STD.GTDT.GENERATOR",
> +  // ACPI Table Signature
> +  EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE,
> +  // ACPI Table Revision
> +  EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,
> +  // Creator ID
> +  TABLE_GENERATOR_CREATOR_ID_ARM,
> +  // Creator Revision
> +  GTDT_GENERATOR_REVISION,
> +  // Build Table function
> +  BuildGtdtTable,
> +  // Free Resource function
> +  FreeGtdtTableResources
> +};
> +
> +/** Register the Generator with the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is registered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID
> +                                is already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiGtdtLibConstructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = RegisterAcpiTableGenerator (&GtdtGenerator);
> +  DEBUG ((DEBUG_INFO, "GTDT: Register Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> +
> +/** Deregister the Generator from the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is deregistered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The Generator is not registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiGtdtLibDestructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = DeregisterAcpiTableGenerator (&GtdtGenerator);
> +  DEBUG ((DEBUG_INFO, "GTDT: Deregister Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..1d77a3bb58cfa9643b
> 4c1b47b83e1ab4e53d26cb
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf
> @@ -0,0 +1,41 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x00010019
> +  BASE_NAME      = AcpiIortLibArm
> +  FILE_GUID      = 25682BA8-B41D-4403-B034-253769E0DAD5
> +  VERSION_STRING = 1.0
> +  MODULE_TYPE    = DXE_DRIVER
> +  LIBRARY_CLASS  = NULL|DXE_DRIVER
> +  CONSTRUCTOR    = AcpiIortLibConstructor
> +  DESTRUCTOR     = AcpiIortLibDestructor
> +
> +[Sources]
> +  IortGenerator.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +
> +[Pcd]
> +
> +[Protocols]
> +
> +[Guids]
> +
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..cee960fba4e4c19a9c5
> 2f2c38e887741a074e2a9
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
> @@ -0,0 +1,2046 @@
> +/** @file
> +  IORT Table Generator
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Reference(s):
> +  - IO Remapping Table, Platform Design Document,
> +    Document number: ARM DEN 0049C, Issue C, 15 May 2017
> +
> +**/
> +
> +#include <IndustryStandard/IoRemappingTable.h>
> +#include <Library/AcpiLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <Library/TableHelperLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +
> +#include "IortGenerator.h"
> +
> +/** ARM standard IORT Generator
> +
> +Requirements:
> +  The following Configuration Manager Object(s) are required by
> +  this Generator:
> +  - EArmObjItsGroup
> +  - EArmObjNamedComponent
> +  - EArmObjRootComplex
> +  - EArmObjSmmuV1SmmuV2
> +  - EArmObjSmmuV3
> +  - EArmObjPmcg
> +  - EArmObjGicItsIdentifierArray
> +  - EArmObjIdMapping
> +  - EArmObjGicItsIdentifierArray
> +*/
> +
> +/** This macro expands to a function that retrieves the ITS
> +    Group node information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjItsGroup,
> +  CM_ARM_ITS_GROUP_NODE
> +  );
> +
> +/** This macro expands to a function that retrieves the
> +    Named Component node information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjNamedComponent,
> +  CM_ARM_NAMED_COMPONENT_NODE
> +  );
> +
> +/** This macro expands to a function that retrieves the
> +     Root Complex node information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjRootComplex,
> +  CM_ARM_ROOT_COMPLEX_NODE
> +  );
> +
> +/** This macro expands to a function that retrieves the
> +    SMMU v1/v2 node information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjSmmuV1SmmuV2,
> +  CM_ARM_SMMUV1_SMMUV2_NODE
> +  );
> +
> +/** This macro expands to a function that retrieves the
> +    SMMU v3 node information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjSmmuV3,
> +  CM_ARM_SMMUV3_NODE
> +  );
> +
> +/** This macro expands to a function that retrieves the
> +    PMCG node information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjPmcg,
> +  CM_ARM_PMCG_NODE
> +  );
> +
> +/** This macro expands to a function that retrieves the
> +    ITS Identifier Array information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjGicItsIdentifierArray,
> +  CM_ARM_ITS_IDENTIFIER
> +  );
> +
> +/** This macro expands to a function that retrieves the
> +    Id Mapping Array information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjIdMapping,
> +  CM_ARM_ID_MAPPING
> +  );
> +
> +/** This macro expands to a function that retrieves the
> +    SMMU Interrupt Array information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjSmmuInterruptArray,
> +  CM_ARM_SMMU_INTERRUPT
> +  );
> +
> +/** Returns the size of the ITS Group node.
> +
> +    @param [in]  Node    Pointer to ITS Group node.
> +
> +    @retval Size of the ITS Group Node.
> +*/
> +STATIC
> +UINT32
> +GetItsGroupNodeSize (
> +  IN  CONST CM_ARM_ITS_GROUP_NODE * Node
> +  )
> +{
> +  ASSERT (Node != NULL);
> +
> +  // Size of ITS Group Node
> +  UINT32 Size = sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE);
> +
> +  // Size of ITS Identifier array
> +  Size += (Node->ItsIdCount * sizeof (UINT32));
> +  return Size;
> +}
> +
> +/** Returns the total size required for the ITS Group nodes and
> +    updates the Node Indexer.
> +
> +    This function calculates the size required for the node group
> +    and also populates the Node Indexer array with offsets for the
> +    individual nodes.
> +
> +    @param [in]       NodeStartOffset Offset from the start of the
> +                                      IORT where this node group starts.
> +    @param [in]       NodeList        Pointer to ITS Group node list.
> +    @param [in]       NodeCount       Count of the ITS Group nodes.
> +    @param [in, out]  NodeIndexer     Pointer to the next Node Indexer.
> +
> +    @retval Total size of the ITS Group Nodes.
> +*/
> +STATIC
> +UINT32
> +GetSizeofItsGroupNodes (
> +  IN      CONST UINT32                         NodeStartOffset,
> +  IN      CONST CM_ARM_ITS_GROUP_NODE  *       NodeList,
> +  IN            UINT32                         NodeCount,
> +  IN OUT        IORT_NODE_INDEXER     ** CONST NodeIndexer
> +  )
> +{
> +  UINT32  Size = 0;
> +
> +  ASSERT (NodeList != NULL);
> +
> +  while (NodeCount-- != 0) {
> +    (*NodeIndexer)->Token = NodeList->Token;
> +    (*NodeIndexer)->Object = (VOID*)NodeList;
> +    (*NodeIndexer)->Offset = Size + NodeStartOffset;
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
> +      *NodeIndexer,
> +      (*NodeIndexer)->Token,
> +      (*NodeIndexer)->Object,
> +      (*NodeIndexer)->Offset
> +      ));
> +
> +    Size += GetItsGroupNodeSize (NodeList);
> +    (*NodeIndexer)++;
> +    NodeList++;
> +  }
> +  return Size;
> +}
> +
> +/** Returns the size of the Named Component node.
> +
> +    @param [in]  Node    Pointer to Named Component node.
> +
> +    @retval Size of the Named Component node.
> +*/
> +STATIC
> +UINT32
> +GetNamedComponentNodeSize (
> +  IN  CONST CM_ARM_NAMED_COMPONENT_NODE * Node
> +  )
> +{
> +  ASSERT (Node != NULL);
> +
> +  // Size of Named Component node
> +  UINT32 Size = sizeof
> (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE);
> +
> +  // Size of ID mapping array
> +  Size += (Node->IdMappingCount * sizeof
> (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));
> +
> +  /* Size of ASCII string + NULL termination + 'padding to
> +     32-bit word aligned'.
> +  */
> +  Size += ALIGN32 (AsciiStrLen (Node->ObjectName) + 1);
> +  return Size;
> +}
> +
> +/** Returns the total size required for the Named Component nodes and
> +    updates the Node Indexer.
> +
> +    This function calculates the size required for the node group
> +    and also populates the Node Indexer array with offsets for the
> +    individual nodes.
> +
> +    @param [in]       NodeStartOffset Offset from the start of the
> +                                      IORT where this node group starts.
> +    @param [in]       NodeList        Pointer to Named Component node list.
> +    @param [in]       NodeCount       Count of the Named Component nodes.
> +    @param [in, out]  NodeIndexer     Pointer to the next Node Indexer.
> +
> +    @retval Total size of the Named Component nodes.
> +*/
> +STATIC
> +UINT32
> +GetSizeofNamedComponentNodes (
> +  IN      CONST UINT32                              NodeStartOffset,
> +  IN      CONST CM_ARM_NAMED_COMPONENT_NODE *       NodeList,
> +  IN            UINT32                              NodeCount,
> +  IN OUT        IORT_NODE_INDEXER          ** CONST NodeIndexer
> +  )
> +{
> +  UINT32  Size = 0;
> +
> +  ASSERT (NodeList != NULL);
> +
> +  while (NodeCount-- != 0) {
> +    (*NodeIndexer)->Token = NodeList->Token;
> +    (*NodeIndexer)->Object = (VOID*)NodeList;
> +    (*NodeIndexer)->Offset = Size + NodeStartOffset;
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
> +      *NodeIndexer,
> +      (*NodeIndexer)->Token,
> +      (*NodeIndexer)->Object,
> +      (*NodeIndexer)->Offset
> +      ));
> +
> +    Size += GetNamedComponentNodeSize (NodeList);
> +    (*NodeIndexer)++;
> +    NodeList++;
> +  }
> +
> +  return Size;
> +}
> +
> +/** Returns the size of the Root Complex node.
> +
> +    @param [in]  Node    Pointer to Root Complex node.
> +
> +    @retval Size of the Root Complex node.
> +*/
> +STATIC
> +UINT32
> +GetRootComplexNodeSize (
> +  IN  CONST CM_ARM_ROOT_COMPLEX_NODE  * Node
> +  )
> +{
> +  ASSERT (Node != NULL);
> +
> +  // Size of Root Complex node
> +  UINT32 Size = sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE);
> +
> +  // Size of ID mapping array
> +  Size += (Node->IdMappingCount *
> +           sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));
> +  return Size;
> +}
> +
> +/** Returns the total size required for the Root Complex nodes and
> +    updates the Node Indexer.
> +
> +    This function calculates the size required for the node group
> +    and also populates the Node Indexer array with offsets for the
> +    individual nodes.
> +
> +    @param [in]       NodeStartOffset Offset from the start of the
> +                                      IORT where this node group starts.
> +    @param [in]       NodeList        Pointer to Root Complex node list.
> +    @param [in]       NodeCount       Count of the Root Complex nodes.
> +    @param [in, out]  NodeIndexer     Pointer to the next Node Indexer.
> +
> +    @retval Total size of the Root Complex nodes.
> +*/
> +STATIC
> +UINT32
> +GetSizeofRootComplexNodes (
> +  IN      CONST UINT32                              NodeStartOffset,
> +  IN      CONST CM_ARM_ROOT_COMPLEX_NODE    *       NodeList,
> +  IN            UINT32                              NodeCount,
> +  IN OUT        IORT_NODE_INDEXER          ** CONST NodeIndexer
> +  )
> +{
> +  UINT32  Size = 0;
> +
> +  ASSERT (NodeList != NULL);
> +
> +  while (NodeCount-- != 0) {
> +    (*NodeIndexer)->Token = NodeList->Token;
> +    (*NodeIndexer)->Object = (VOID*)NodeList;
> +    (*NodeIndexer)->Offset = Size + NodeStartOffset;
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
> +      *NodeIndexer,
> +      (*NodeIndexer)->Token,
> +      (*NodeIndexer)->Object,
> +      (*NodeIndexer)->Offset
> +      ));
> +
> +    Size += GetRootComplexNodeSize (NodeList);
> +    (*NodeIndexer)++;
> +    NodeList++;
> +  }
> +
> +  return Size;
> +}
> +
> +/** Returns the size of the SMMUv1/SMMUv2 node.
> +
> +    @param [in]  Node    Pointer to SMMUv1/SMMUv2 node list.
> +
> +    @retval Size of the SMMUv1/SMMUv2 node.
> +*/
> +STATIC
> +UINT32
> +GetSmmuV1V2NodeSize (
> +  IN  CONST CM_ARM_SMMUV1_SMMUV2_NODE  * Node
> +  )
> +{
> +  ASSERT (Node != NULL);
> +
> +  // Size of SMMU v1/SMMU v2 node
> +  UINT32 Size = sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE);
> +
> +  // Size of ID mapping array
> +  Size += (Node->IdMappingCount *
> +           sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));
> +
> +  // Size of context interrupt array
> +  Size += (Node->ContextInterruptCount *
> +           sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
> +
> +  // Size of PMU interrupt array
> +  Size += (Node->PmuInterruptCount *
> +           sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
> +  return Size;
> +}
> +
> +/** Returns the total size required for the SMMUv1/SMMUv2 nodes and
> +    updates the Node Indexer.
> +
> +    This function calculates the size required for the node group
> +    and also populates the Node Indexer array with offsets for the
> +    individual nodes.
> +
> +    @param [in]       NodeStartOffset Offset from the start of the
> +                                      IORT where this node group starts.
> +    @param [in]       NodeList        Pointer to SMMUv1/SMMUv2 node list.
> +    @param [in]       NodeCount       Count of the SMMUv1/SMMUv2 nodes.
> +    @param [in, out]  NodeIndexer     Pointer to the next Node Indexer.
> +
> +    @retval Total size of the SMMUv1/SMMUv2 nodes.
> +*/
> +STATIC
> +UINT32
> +GetSizeofSmmuV1V2Nodes (
> +  IN      CONST UINT32                              NodeStartOffset,
> +  IN      CONST CM_ARM_SMMUV1_SMMUV2_NODE   *       NodeList,
> +  IN            UINT32                              NodeCount,
> +  IN OUT        IORT_NODE_INDEXER          ** CONST NodeIndexer
> +  )
> +{
> +  UINT32  Size = 0;
> +
> +  ASSERT (NodeList != NULL);
> +
> +  while (NodeCount-- != 0) {
> +    (*NodeIndexer)->Token = NodeList->Token;
> +    (*NodeIndexer)->Object = (VOID*)NodeList;
> +    (*NodeIndexer)->Offset = Size + NodeStartOffset;
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
> +      *NodeIndexer,
> +      (*NodeIndexer)->Token,
> +      (*NodeIndexer)->Object,
> +      (*NodeIndexer)->Offset
> +      ));
> +
> +    Size += GetSmmuV1V2NodeSize (NodeList);
> +    (*NodeIndexer)++;
> +    NodeList++;
> +  }
> +  return Size;
> +}
> +
> +/** Returns the size of the SMMUv3 node.
> +
> +    @param [in]  Node    Pointer to SMMUv3 node list.
> +
> +    @retval Total size of the SMMUv3 nodes.
> +*/
> +STATIC
> +UINT32
> +GetSmmuV3NodeSize (
> +  IN  CONST CM_ARM_SMMUV3_NODE  * Node
> +  )
> +{
> +  ASSERT (Node != NULL);
> +
> +  // Size of SMMU v1/SMMU v2 node
> +  UINT32 Size = sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE);
> +
> +  // Size of ID mapping array
> +  Size += (Node->IdMappingCount *
> +           sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));
> +  return Size;
> +}
> +
> +/** Returns the total size required for the SMMUv3 nodes and
> +    updates the Node Indexer.
> +
> +    This function calculates the size required for the node group
> +    and also populates the Node Indexer array with offsets for the
> +    individual nodes.
> +
> +    @param [in]       NodeStartOffset Offset from the start of the
> +                                      IORT where this node group starts.
> +    @param [in]       NodeList        Pointer to SMMUv3 node list.
> +    @param [in]       NodeCount       Count of the SMMUv3 nodes.
> +    @param [in, out]  NodeIndexer     Pointer to the next Node Indexer.
> +
> +    @retval Total size of the SMMUv3 nodes.
> +*/
> +STATIC
> +UINT32
> +GetSizeofSmmuV3Nodes (
> +  IN      CONST UINT32                       NodeStartOffset,
> +  IN      CONST CM_ARM_SMMUV3_NODE   *       NodeList,
> +  IN            UINT32                       NodeCount,
> +  IN OUT        IORT_NODE_INDEXER   ** CONST NodeIndexer
> +  )
> +{
> +  UINT32  Size = 0;
> +
> +  ASSERT (NodeList != NULL);
> +
> +  while (NodeCount-- != 0) {
> +    (*NodeIndexer)->Token = NodeList->Token;
> +    (*NodeIndexer)->Object = (VOID*)NodeList;
> +    (*NodeIndexer)->Offset = Size + NodeStartOffset;
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
> +      *NodeIndexer,
> +      (*NodeIndexer)->Token,
> +      (*NodeIndexer)->Object,
> +      (*NodeIndexer)->Offset
> +      ));
> +
> +    Size += GetSmmuV3NodeSize (NodeList);
> +    (*NodeIndexer)++;
> +    NodeList++;
> +  }
> +  return Size;
> +}
> +
> +/** Returns the size of the PMCG node.
> +
> +    @param [in]  Node    Pointer to PMCG node.
> +
> +    @retval Size of the PMCG node.
> +*/
> +STATIC
> +UINT32
> +GetPmcgNodeSize (
> +  IN  CONST CM_ARM_PMCG_NODE  * Node
> +  )
> +{
> +  ASSERT (Node != NULL);
> +
> +  // Size of PMCG node
> +  UINT32 Size = sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);
> +
> +  // Size of ID mapping array
> +  Size += (Node->IdMappingCount *
> +           sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE));
> +  return Size;
> +}
> +
> +/** Returns the total size required for the PMCG nodes and
> +    updates the Node Indexer.
> +
> +    This function calculates the size required for the node group
> +    and also populates the Node Indexer array with offsets for the
> +    individual nodes.
> +
> +    @param [in]       NodeStartOffset Offset from the start of the
> +                                      IORT where this node group starts.
> +    @param [in]       NodeList        Pointer to PMCG node list.
> +    @param [in]       NodeCount       Count of the PMCG nodes.
> +    @param [in, out]  NodeIndexer     Pointer to the next Node Indexer.
> +
> +    @retval Total size of the PMCG nodes.
> +*/
> +STATIC
> +UINT32
> +GetSizeofPmcgNodes (
> +  IN      CONST UINT32                     NodeStartOffset,
> +  IN      CONST CM_ARM_PMCG_NODE   *       NodeList,
> +  IN            UINT32                     NodeCount,
> +  IN OUT        IORT_NODE_INDEXER ** CONST NodeIndexer
> +  )
> +{
> +  UINT32  Size = 0;
> +
> +  ASSERT (NodeList != NULL);
> +
> +  while (NodeCount-- != 0) {
> +    (*NodeIndexer)->Token = NodeList->Token;
> +    (*NodeIndexer)->Object = (VOID*)NodeList;
> +    (*NodeIndexer)->Offset = Size + NodeStartOffset;
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
> +      *NodeIndexer,
> +      (*NodeIndexer)->Token,
> +      (*NodeIndexer)->Object,
> +      (*NodeIndexer)->Offset
> +      ));
> +
> +    Size += GetPmcgNodeSize (NodeList);
> +    (*NodeIndexer)++;
> +    NodeList++;
> +  }
> +  return Size;
> +}
> +
> +/** Returns the offset of the Node referenced by the Token.
> +
> +    @param [in]  NodeIndexer  Pointer to node indexer array.
> +    @param [in]  NodeCount    Count of the nodes.
> +    @param [in]  Token        Reference token for the node.
> +    @param [out] NodeOffset   Offset of the node from the
> +                              start of the IORT table.
> +
> +    @retval EFI_SUCCESS       Success.
> +    @retval EFI_NOT_FOUND     No matching token reference
> +                              found in node indexer array.
> +*/
> +STATIC
> +EFI_STATUS
> +GetNodeOffsetReferencedByToken (
> +  IN  IORT_NODE_INDEXER * NodeIndexer,
> +  IN  UINT32              NodeCount,
> +  IN  CM_OBJECT_TOKEN     Token,
> +  OUT UINT32            * NodeOffset
> +  )
> +{
> +  DEBUG ((
> +      DEBUG_INFO,
> +      "IORT: Node Indexer: Search Token = %p\n",
> +      Token
> +      ));
> +  while (NodeCount-- != 0) {
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "IORT: Node Indexer: NodeIndexer->Token = %p, Offset = %d\n",
> +      NodeIndexer->Token,
> +      NodeIndexer->Offset
> +      ));
> +    if (NodeIndexer->Token == Token) {
> +      *NodeOffset = NodeIndexer->Offset;
> +      DEBUG ((
> +        DEBUG_INFO,
> +        "IORT: Node Indexer: Token = %p, Found\n",
> +        Token
> +        ));
> +      return EFI_SUCCESS;
> +    }
> +    NodeIndexer++;
> +  }
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "IORT: Node Indexer: Token = %p, Not Found\n",
> +    Token
> +    ));
> +  return EFI_NOT_FOUND;
> +}
> +
> +/** Update the Id Mapping Array.
> +
> +    This function retrieves the Id Mapping Array object referenced by the
> +    IdMappingToken and updates the IdMapArray.
> +
> +    @param [in]     CfgMgrProtocol   Pointer to the Configuration Manager
> +                                     Protocol Interface.
> +    @param [in]     IdMapArray       Pointer to an array of Id Mappings.
> +    @param [in]     IdCount          Number of Id Mappings.
> +    @param [in]     IdMappingToken   Reference Token for retrieving the
> +                                     Id Mapping Array object.
> +
> +    @retval EFI_SUCCESS           Table generated successfully.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_NOT_FOUND         The required object was not found.
> +*/
> +STATIC
> +EFI_STATUS
> +AddIdMappingArray (
> +  IN      CONST ACPI_TABLE_GENERATOR                 * CONST This,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL   * CONST
> CfgMgrProtocol,
> +  IN            EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE   *       IdMapArray,
> +  IN            UINT32                                       IdCount,
> +  IN      CONST CM_OBJECT_TOKEN                              IdMappingToken
> +  )
> +{
> +  EFI_STATUS            Status;
> +  CM_ARM_ID_MAPPING   * IdMappings;
> +  UINT32                IdMappingCount;
> +  ACPI_IORT_GENERATOR * Generator = (ACPI_IORT_GENERATOR*)This;
> +
> +  ASSERT (IdMapArray != NULL);
> +
> +  // Get the Id Mapping Array
> +  Status = GetEArmObjIdMapping (
> +             CfgMgrProtocol,
> +             IdMappingToken,
> +             &IdMappings,
> +             &IdMappingCount
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to get Id Mapping array. Status = %r\n",
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  if (IdMappingCount < IdCount) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to get the required number of Id Mappings.\n"
> +      ));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  // Populate the Id Mapping array
> +  while (IdCount-- != 0) {
> +    Status = GetNodeOffsetReferencedByToken (
> +              Generator->NodeIndexer,
> +              Generator->IortNodeCount,
> +              IdMappings->OutputReferenceToken,
> +              &IdMapArray->OutputReference
> +              );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to get Output Reference for ITS Identifier array."
> +        "Reference Token = %p"
> +        " Status = %r\n",
> +        IdMappings->OutputReferenceToken,
> +        Status
> +        ));
> +      return Status;
> +    }
> +
> +    IdMapArray->InputBase = IdMappings->InputBase;
> +    IdMapArray->NumIds = IdMappings->NumIds;
> +    IdMapArray->OutputBase = IdMappings->OutputBase;
> +    IdMapArray->Flags = IdMappings->Flags;
> +
> +    IdMapArray++;
> +    IdMappings++;
> +  } // Id Mapping array
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Update the ITS Group Node Information.
> +
> +    @param [in]     CfgMgrProtocol   Pointer to the Configuration Manager
> +                                     Protocol Interface.
> +    @param [in]     Iort             Pointer to IORT table structure.
> +    @param [in]     NodesStartOffset Offset for the start of the ITS Group
> +                                     Nodes.
> +    @param [in]     NodeList         Pointer to an array of ITS Group Node
> +                                     Objects.
> +    @param [in]     NodeCount        Number of ITS Group Node Objects.
> +
> +    @retval EFI_SUCCESS           Table generated successfully.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_NOT_FOUND         The required object was not found.
> +*/
> +STATIC
> +EFI_STATUS
> +AddItsGroupNodes (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN  CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE     *       Iort,
> +  IN  CONST UINT32                                      NodesStartOffset,
> +  IN  CONST CM_ARM_ITS_GROUP_NODE               *       NodeList,
> +  IN        UINT32                                      NodeCount
> +  )
> +{
> +  EFI_STATUS                            Status;
> +  EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE  * ItsGroupNode;
> +  UINT32                              * ItsIds;
> +  CM_ARM_ITS_IDENTIFIER               * ItsIdentifier;
> +  UINT32                                ItsIdentifierCount;
> +  UINT32                                IdIndex;
> +
> +  ASSERT (Iort != NULL);
> +
> +  ItsGroupNode =
> (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE*)((UINT8*)Iort +
> +                  NodesStartOffset);
> +
> +  while (NodeCount-- != 0) {
> +    // Populate the node header
> +    ItsGroupNode->Node.Type = EFI_ACPI_IORT_TYPE_ITS_GROUP;
> +    ItsGroupNode->Node.Length = GetItsGroupNodeSize (NodeList);
> +    ItsGroupNode->Node.Revision = 0;
> +    ItsGroupNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
> +    ItsGroupNode->Node.NumIdMappings = 0;
> +    ItsGroupNode->Node.IdReference = 0;
> +
> +    // IORT specific data
> +    ItsGroupNode->NumItsIdentifiers = NodeList->ItsIdCount;
> +    ItsIds = (UINT32*)((UINT8*)ItsGroupNode +
> +      sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE));
> +
> +    Status = GetEArmObjGicItsIdentifierArray (
> +               CfgMgrProtocol,
> +               NodeList->ItsIdToken,
> +               &ItsIdentifier,
> +               &ItsIdentifierCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",
> +        Status
> +        ));
> +      return Status;
> +    }
> +
> +    if (ItsIdentifierCount < ItsGroupNode->NumItsIdentifiers) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"
> +        ));
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    // Populate the ITS identifier array
> +    for (IdIndex = 0; IdIndex < ItsGroupNode->NumItsIdentifiers; IdIndex++)
> {
> +      ItsIds[IdIndex] = ItsIdentifier[IdIndex].ItsId;
> +    } // ITS identifier array
> +
> +    // Next IORT Group Node
> +    ItsGroupNode =
> (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE*)((UINT8*)ItsGroupNode +
> +                    ItsGroupNode->Node.Length);
> +    NodeList++;
> +  } // IORT Group Node
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Update the Named Component Node Information.
> +
> +    This function updates the Named Component node information in the
> IORT
> +    table.
> +
> +    @param [in]     CfgMgrProtocol   Pointer to the Configuration Manager
> +                                     Protocol Interface.
> +    @param [in]     Iort             Pointer to IORT table structure.
> +    @param [in]     NodesStartOffset Offset for the start of the Named
> +                                     Component Nodes.
> +    @param [in]     NodeList         Pointer to an array of Named Component
> +                                     Node Objects.
> +    @param [in]     NodeCount        Number of Named Component Node
> Objects.
> +
> +    @retval EFI_SUCCESS           Table generated successfully.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_NOT_FOUND         The required object was not found.
> +*/
> +STATIC
> +EFI_STATUS
> +AddNamedComponentNodes (
> +  IN      CONST ACPI_TABLE_GENERATOR                 * CONST This,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL   * CONST
> CfgMgrProtocol,
> +  IN      CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE      *       Iort,
> +  IN      CONST UINT32                                       NodesStartOffset,
> +  IN      CONST CM_ARM_NAMED_COMPONENT_NODE          *       NodeList,
> +  IN            UINT32                                       NodeCount
> +  )
> +{
> +  EFI_STATUS                                   Status;
> +  EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE  * NcNode;
> +  EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE         * IdMapArray;
> +  UINT32                                       ObjectNameLenght;
> +  CHAR8                                      * ObjectName;
> +
> +  ASSERT (Iort != NULL);
> +
> +  NcNode =
> (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE*)((UINT8*)Iort +
> +            NodesStartOffset);
> +
> +  while (NodeCount-- != 0) {
> +    // Populate the node header
> +    NcNode->Node.Type = EFI_ACPI_IORT_TYPE_NAMED_COMP;
> +    NcNode->Node.Length =
> +      GetNamedComponentNodeSize (NodeList);
> +    NcNode->Node.Revision = 1;
> +    NcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
> +    NcNode->Node.NumIdMappings = NodeList->IdMappingCount;
> +
> +    ObjectNameLenght = AsciiStrLen (NodeList->ObjectName) + 1;
> +    NcNode->Node.IdReference =
> +      sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +
> +      (ALIGN32 (ObjectNameLenght));
> +
> +    // Named Component specific data
> +    NcNode->Flags = NodeList->Flags;
> +    NcNode->CacheCoherent = NodeList->CacheCoherent;
> +    NcNode->AllocationHints = NodeList->AllocationHints;
> +    NcNode->Reserved = EFI_ACPI_RESERVED_WORD;
> +    NcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;
> +    NcNode->AddressSizeLimit = NodeList->AddressSizeLimit;
> +
> +    // Copy the object name
> +    ObjectName = (CHAR8*)((UINT8*)NcNode +
> +      sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE));
> +    Status = AsciiStrCpyS (
> +               ObjectName,
> +               ObjectNameLenght,
> +               NodeList->ObjectName
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to copy Object Name. Status = %r\n",
> +        Status
> +        ));
> +      return Status;
> +    }
> +
> +    if ((NodeList->IdMappingCount > 0) &&
> +        (NodeList->IdMappingToken != CM_NULL_TOKEN)) {
> +      // Ids for Named Component
> +      IdMapArray =
> (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)NcNode +
> +                    NcNode->Node.IdReference);
> +
> +      Status = AddIdMappingArray (
> +                 This,
> +                 CfgMgrProtocol,
> +                 IdMapArray,
> +                 NodeList->IdMappingCount,
> +                 NodeList->IdMappingToken
> +                 );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
> +          Status
> +          ));
> +        return Status;
> +      }
> +    }
> +
> +    // Next Named Component Node
> +    NcNode =
> (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE*)((UINT8*)NcNode
> +
> +              NcNode->Node.Length);
> +    NodeList++;
> +  } // Named Component Node
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Update the Root Complex Node Information.
> +
> +    This function updates the Root Complex node information in the IORT
> table.
> +
> +    @param [in]     CfgMgrProtocol   Pointer to the Configuration Manager
> +                                     Protocol Interface.
> +    @param [in]     Iort             Pointer to IORT table structure.
> +    @param [in]     NodesStartOffset Offset for the start of the Root
> Complex
> +                                     Nodes.
> +    @param [in]     NodeList         Pointer to an array of Root Complex Node
> +                                     Objects.
> +    @param [in]     NodeCount        Number of Root Complex Node Objects.
> +
> +    @retval EFI_SUCCESS           Table generated successfully.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_NOT_FOUND         The required object was not found.
> +*/
> +STATIC
> +EFI_STATUS
> +AddRootComplexNodes (
> +  IN      CONST ACPI_TABLE_GENERATOR                 * CONST This,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL   * CONST
> CfgMgrProtocol,
> +  IN      CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE      *       Iort,
> +  IN      CONST UINT32                                       NodesStartOffset,
> +  IN      CONST CM_ARM_ROOT_COMPLEX_NODE             *       NodeList,
> +  IN            UINT32                                       NodeCount
> +  )
> +{
> +  EFI_STATUS                           Status;
> +  EFI_ACPI_6_0_IO_REMAPPING_RC_NODE  * RcNode;
> +  EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE * IdMapArray;
> +
> +  ASSERT (Iort != NULL);
> +
> +  RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE*)((UINT8*)Iort +
> +            NodesStartOffset);
> +
> +  while (NodeCount-- != 0) {
> +    // Populate the node header
> +    RcNode->Node.Type = EFI_ACPI_IORT_TYPE_ROOT_COMPLEX;
> +    RcNode->Node.Length = GetRootComplexNodeSize (NodeList);
> +    RcNode->Node.Revision = 0;
> +    RcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
> +    RcNode->Node.NumIdMappings = NodeList->IdMappingCount;
> +    RcNode->Node.IdReference = sizeof
> (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE);
> +
> +    // Root Complex specific data
> +    RcNode->CacheCoherent = NodeList->CacheCoherent;
> +    RcNode->AllocationHints = NodeList->AllocationHints;
> +    RcNode->Reserved = EFI_ACPI_RESERVED_WORD;
> +    RcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;
> +    RcNode->AtsAttribute = NodeList->AtsAttribute;
> +    RcNode->PciSegmentNumber = NodeList->PciSegmentNumber;
> +
> +    if ((NodeList->IdMappingCount > 0) &&
> +        (NodeList->IdMappingToken != CM_NULL_TOKEN)) {
> +      // Ids for Root Complex
> +      IdMapArray =
> (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)RcNode +
> +                    RcNode->Node.IdReference);
> +      Status = AddIdMappingArray (
> +                 This,
> +                 CfgMgrProtocol,
> +                 IdMapArray,
> +                 NodeList->IdMappingCount,
> +                 NodeList->IdMappingToken
> +                 );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
> +          Status
> +          ));
> +        return Status;
> +      }
> +    }
> +
> +    // Next Root Complex Node
> +    RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE*)((UINT8*)RcNode
> +
> +              RcNode->Node.Length);
> +    NodeList++;
> +  } // Root Complex Node
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Update the SMMU Interrupt Array.
> +
> +    This function retrieves the InterruptArray object referenced by the
> +    InterruptToken and updates the SMMU InterruptArray.
> +
> +    @param [in]     CfgMgrProtocol   Pointer to the Configuration Manager
> +                                     Protocol Interface.
> +    @param [in]     InterruptArray   Pointer to an array of Interrupts.
> +    @param [in]     InterruptCount   Number of entries in the InterruptArray.
> +    @param [in]     InterruptToken   Reference Token for retrieving the
> SMMU
> +                                     InterruptArray object.
> +
> +    @retval EFI_SUCCESS           Table generated successfully.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_NOT_FOUND         The required object was not found.
> +*/
> +STATIC
> +EFI_STATUS
> +AddSmmuInterrruptArray (
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL   * CONST
> CfgMgrProtocol,
> +  IN OUT        EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT   *
> InterruptArray,
> +  IN            UINT32                                 InterruptCount,
> +  IN      CONST CM_OBJECT_TOKEN                        InterruptToken
> +  )
> +{
> +  EFI_STATUS              Status;
> +  CM_ARM_SMMU_INTERRUPT * SmmuInterrupt;
> +  UINT32                  SmmuInterruptCount;
> +
> +  ASSERT (InterruptArray != NULL);
> +
> +  // Get the SMMU Interrupt Array
> +  Status = GetEArmObjSmmuInterruptArray (
> +             CfgMgrProtocol,
> +             InterruptToken,
> +             &SmmuInterrupt,
> +             &SmmuInterruptCount
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  if (SmmuInterruptCount < InterruptCount) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to get the required number of SMMU
> Interrupts.\n"
> +      ));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  // Populate the Id Mapping array
> +  while (InterruptCount-- != 0) {
> +    InterruptArray->Interrupt = SmmuInterrupt->Interrupt;
> +    InterruptArray->InterruptFlags = SmmuInterrupt->Flags;
> +    InterruptArray++;
> +    SmmuInterrupt++;
> +  } // Id Mapping array
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Update the SMMU v1/v2 Node Information.
> +
> +    @param [in]     CfgMgrProtocol   Pointer to the Configuration Manager
> +                                     Protocol Interface.
> +    @param [in]     Iort             Pointer to IORT table structure.
> +    @param [in]     NodesStartOffset Offset for the start of the SMMU v1/v2
> +                                     Nodes.
> +    @param [in]     NodeList         Pointer to an array of SMMU v1/v2 Node
> +                                     Objects.
> +    @param [in]     NodeCount        Number of SMMU v1/v2 Node Objects.
> +
> +    @retval EFI_SUCCESS           Table generated successfully.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_NOT_FOUND         The required object was not found.
> +*/
> +STATIC
> +EFI_STATUS
> +AddSmmuV1V2Nodes (
> +  IN      CONST ACPI_TABLE_GENERATOR                 * CONST This,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL   * CONST
> CfgMgrProtocol,
> +  IN      CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE      * Iort,
> +  IN      CONST UINT32                                 NodesStartOffset,
> +  IN      CONST CM_ARM_SMMUV1_SMMUV2_NODE            * NodeList,
> +  IN            UINT32                                 NodeCount
> +  )
> +{
> +  EFI_STATUS                            Status;
> +  EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE * SmmuNode;
> +  EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE  * IdMapArray;
> +
> +  EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT  * ContextInterruptArray;
> +  EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT  * PmuInterruptArray;
> +
> +  ASSERT (Iort != NULL);
> +
> +  SmmuNode =
> (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE*)((UINT8*)Iort +
> +              NodesStartOffset);
> +
> +  while (NodeCount-- != 0) {
> +    // Populate the node header
> +    SmmuNode->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv1v2;
> +    SmmuNode->Node.Length = GetSmmuV1V2NodeSize (NodeList);
> +    SmmuNode->Node.Revision = 0;
> +    SmmuNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
> +    SmmuNode->Node.NumIdMappings = NodeList->IdMappingCount;
> +    SmmuNode->Node.IdReference = sizeof
> (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +
> +      (NodeList->ContextInterruptCount *
> +      sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +
> +      (NodeList->PmuInterruptCount *
> +      sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
> +
> +    // SMMU v1/v2 specific data
> +    SmmuNode->Base = NodeList->BaseAddress;
> +    SmmuNode->Span = NodeList->Span;
> +    SmmuNode->Model = NodeList->Model;
> +    SmmuNode->Flags = NodeList->Flags;
> +
> +    // Reference to Global Interrupt Array
> +    SmmuNode->GlobalInterruptArrayRef =
> +      OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE,
> SMMU_NSgIrpt);
> +
> +    // Context Interrupt
> +    SmmuNode->NumContextInterrupts = NodeList-
> >ContextInterruptCount;
> +    SmmuNode->ContextInterruptArrayRef =
> +      sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE);
> +    ContextInterruptArray =
> +      (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT*)((UINT8*)SmmuNode +
> +      sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE));
> +
> +    // PMU Interrupt
> +    SmmuNode->NumPmuInterrupts = NodeList->PmuInterruptCount;
> +    SmmuNode->PmuInterruptArrayRef = SmmuNode-
> >ContextInterruptArrayRef +
> +      (NodeList->ContextInterruptCount *
> +      sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
> +    PmuInterruptArray =
> +      (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT*)((UINT8*)SmmuNode +
> +      SmmuNode->PmuInterruptArrayRef);
> +
> +    SmmuNode->SMMU_NSgIrpt = NodeList->SMMU_NSgIrpt;
> +    SmmuNode->SMMU_NSgIrptFlags = NodeList->SMMU_NSgIrptFlags;
> +    SmmuNode->SMMU_NSgCfgIrpt = NodeList->SMMU_NSgCfgIrpt;
> +    SmmuNode->SMMU_NSgCfgIrptFlags = NodeList-
> >SMMU_NSgCfgIrptFlags;
> +
> +    // Add Context Interrupt Array
> +    Status = AddSmmuInterrruptArray (
> +               CfgMgrProtocol,
> +               ContextInterruptArray,
> +               SmmuNode->NumContextInterrupts,
> +               NodeList->ContextInterruptToken
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",
> +        Status
> +        ));
> +      return Status;
> +    }
> +
> +    // Add PMU Interrupt Array
> +    if ((SmmuNode->NumPmuInterrupts > 0) &&
> +        (NodeList->PmuInterruptToken != CM_NULL_TOKEN)) {
> +      Status = AddSmmuInterrruptArray (
> +                 CfgMgrProtocol,
> +                 PmuInterruptArray,
> +                 SmmuNode->NumPmuInterrupts,
> +                 NodeList->PmuInterruptToken
> +                 );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",
> +          Status
> +          ));
> +        return Status;
> +      }
> +    }
> +
> +    if ((NodeList->IdMappingCount > 0) &&
> +        (NodeList->IdMappingToken != CM_NULL_TOKEN)) {
> +      // Ids for SMMU v1/v2 Node
> +      IdMapArray =
> (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)SmmuNode +
> +                    SmmuNode->Node.IdReference);
> +      Status = AddIdMappingArray (
> +                 This,
> +                 CfgMgrProtocol,
> +                 IdMapArray,
> +                 NodeList->IdMappingCount,
> +                 NodeList->IdMappingToken
> +                 );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
> +          Status
> +          ));
> +        return Status;
> +      }
> +    }
> +    // Next SMMU v1/v2 Node
> +    SmmuNode =
> (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE*)((UINT8*)SmmuNode +
> +                SmmuNode->Node.Length);
> +    NodeList++;
> +  } // SMMU v1/v2 Node
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Update the SMMUv3 Node Information.
> +
> +    This function updates the SMMUv3 node information in the IORT table.
> +
> +    @param [in]     CfgMgrProtocol   Pointer to the Configuration Manager
> +                                     Protocol Interface.
> +    @param [in]     Iort             Pointer to IORT table structure.
> +    @param [in]     NodesStartOffset Offset for the start of the SMMUv3
> Nodes.
> +    @param [in]     NodeList         Pointer to an array of SMMUv3 Node
> Objects.
> +    @param [in]     NodeCount        Number of SMMUv3 Node Objects.
> +
> +    @retval EFI_SUCCESS           Table generated successfully.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_NOT_FOUND         The required object was not found.
> +*/
> +STATIC
> +EFI_STATUS
> +AddSmmuV3Nodes (
> +  IN      CONST ACPI_TABLE_GENERATOR                 * CONST This,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL   * CONST
> CfgMgrProtocol,
> +  IN      CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE      *       Iort,
> +  IN      CONST UINT32                                       NodesStartOffset,
> +  IN      CONST CM_ARM_SMMUV3_NODE                   *       NodeList,
> +  IN            UINT32                                       NodeCount
> +  )
> +{
> +  EFI_STATUS                             Status;
> +  EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE * SmmuV3Node;
> +  EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE   * IdMapArray;
> +
> +  ASSERT (Iort != NULL);
> +
> +  SmmuV3Node =
> (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE*)((UINT8*)Iort +
> +                NodesStartOffset);
> +
> +  while (NodeCount-- != 0) {
> +    // Populate the node header
> +    SmmuV3Node->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv3;
> +    SmmuV3Node->Node.Length = GetSmmuV3NodeSize (NodeList);
> +    SmmuV3Node->Node.Revision = 1;
> +    SmmuV3Node->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
> +    SmmuV3Node->Node.NumIdMappings = NodeList->IdMappingCount;
> +    SmmuV3Node->Node.IdReference =
> +      sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE);
> +
> +    // SMMUv3 specific data
> +    SmmuV3Node->Base = NodeList->BaseAddress;
> +    SmmuV3Node->Flags = NodeList->Flags;
> +    SmmuV3Node->Reserved = EFI_ACPI_RESERVED_WORD;
> +    SmmuV3Node->VatosAddress = NodeList->VatosAddress;
> +    SmmuV3Node->Model = NodeList->Model;
> +    SmmuV3Node->Event = NodeList->EventInterrupt;
> +    SmmuV3Node->Pri = NodeList->PriInterrupt;
> +    SmmuV3Node->Gerr = NodeList->GerrInterrupt;
> +    SmmuV3Node->Sync = NodeList->SyncInterrupt;
> +
> +    if ((SmmuV3Node->Flags &
> EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN) != 0) {
> +      // The Proximity Domain Valid flag is set to 1
> +      SmmuV3Node->ProximityDomain = NodeList->ProximityDomain;
> +    } else {
> +      SmmuV3Node->ProximityDomain = 0;
> +    }
> +
> +    SmmuV3Node->Reserved1[0] = EFI_ACPI_RESERVED_BYTE;
> +    SmmuV3Node->Reserved1[1] = EFI_ACPI_RESERVED_BYTE;
> +    SmmuV3Node->Reserved1[2] = EFI_ACPI_RESERVED_BYTE;
> +
> +    if ((SmmuV3Node->Event != 0) && (SmmuV3Node->Pri != 0) &&
> +        (SmmuV3Node->Gerr != 0) && (SmmuV3Node->Sync != 0)) {
> +      // If all the SMMU control interrupts are GSIV based,
> +      // the DeviceID mapping index field is ignored.
> +      SmmuV3Node->DeviceIdMappingIndex = 0;
> +    } else {
> +      SmmuV3Node->DeviceIdMappingIndex = NodeList-
> >DeviceIdMappingIndex;
> +    }
> +
> +    if ((NodeList->IdMappingCount > 0) &&
> +        (NodeList->IdMappingToken != CM_NULL_TOKEN)) {
> +      // Ids for SMMUv3 node
> +      IdMapArray =
> (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)SmmuV3Node +
> +                    SmmuV3Node->Node.IdReference);
> +      Status = AddIdMappingArray (
> +                 This,
> +                 CfgMgrProtocol,
> +                 IdMapArray,
> +                 NodeList->IdMappingCount,
> +                 NodeList->IdMappingToken
> +                 );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
> +          Status
> +          ));
> +        return Status;
> +      }
> +    }
> +
> +    // Next SMMUv3 Node
> +    SmmuV3Node =
> (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE*)((UINT8*)SmmuV3Node
> +
> +                  SmmuV3Node->Node.Length);
> +    NodeList++;
> +  } // SMMUv3 Node
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Update the PMCG Node Information.
> +
> +    This function updates the PMCG node information in the IORT table.
> +
> +    @param [in]     CfgMgrProtocol   Pointer to the Configuration Manager
> +                                     Protocol Interface.
> +    @param [in]     Iort             Pointer to IORT table structure.
> +    @param [in]     NodesStartOffset Offset for the start of the PMCG Nodes.
> +    @param [in]     NodeList         Pointer to an array of PMCG Node Objects.
> +    @param [in]     NodeCount        Number of PMCG Node Objects.
> +
> +    @retval EFI_SUCCESS           Table generated successfully.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_NOT_FOUND         The required object was not found.
> +*/
> +STATIC
> +EFI_STATUS
> +AddPmcgNodes (
> +  IN      CONST ACPI_TABLE_GENERATOR                 * CONST This,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL   * CONST
> CfgMgrProtocol,
> +  IN      CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE      *       Iort,
> +  IN      CONST UINT32                                       NodesStartOffset,
> +  IN      CONST CM_ARM_PMCG_NODE                     *       NodeList,
> +  IN            UINT32                                       NodeCount
> +  )
> +{
> +  EFI_STATUS                             Status;
> +  EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE  * PmcgNode;
> +  EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE   * IdMapArray;
> +  ACPI_IORT_GENERATOR                  * Generator =
> (ACPI_IORT_GENERATOR*)This;
> +
> +  ASSERT (Iort != NULL);
> +
> +  PmcgNode =
> (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE*)((UINT8*)Iort +
> +              NodesStartOffset);
> +
> +  while (NodeCount-- != 0) {
> +    // Populate the node header
> +    PmcgNode->Node.Type = EFI_ACPI_IORT_TYPE_PMCG;
> +    PmcgNode->Node.Length = GetPmcgNodeSize (NodeList);
> +    PmcgNode->Node.Revision = 0;
> +    PmcgNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
> +    PmcgNode->Node.NumIdMappings = NodeList->IdMappingCount;
> +    PmcgNode->Node.IdReference = sizeof
> (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);
> +
> +    // PMCG specific data
> +    PmcgNode->Base = NodeList->BaseAddress;
> +    PmcgNode->OverflowInterruptGsiv = NodeList->OverflowInterrupt;
> +
> +    Status = GetNodeOffsetReferencedByToken (
> +              Generator->NodeIndexer,
> +              Generator->IortNodeCount,
> +              NodeList->ReferenceToken,
> +              &PmcgNode->NodeReference
> +              );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to get Output Reference for PMCG Node."
> +        "Reference Token = %p"
> +        " Status = %r\n",
> +        NodeList->ReferenceToken,
> +        Status
> +        ));
> +      return Status;
> +    }
> +
> +    if ((NodeList->IdMappingCount > 0) &&
> +        (NodeList->IdMappingToken != CM_NULL_TOKEN)) {
> +      // Ids for PMCG node
> +      IdMapArray =
> (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE*)((UINT8*)PmcgNode +
> +                    PmcgNode->Node.IdReference);
> +
> +      Status = AddIdMappingArray (
> +                This,
> +                CfgMgrProtocol,
> +                IdMapArray,
> +                NodeList->IdMappingCount,
> +                NodeList->IdMappingToken
> +                );
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
> +          Status
> +          ));
> +        return Status;
> +      }
> +    }
> +
> +    // Next PMCG Node
> +    PmcgNode =
> (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE*)((UINT8*)PmcgNode +
> +                PmcgNode->Node.Length);
> +    NodeList++;
> +  } // PMCG Node
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Construct the IORT ACPI table.
> +
> +    This function invokes the Configuration Manager protocol interface
> +    to get the required hardware information for generating the ACPI
> +    table.
> +
> +    If this function allocates any resources then they must be freed
> +    in the FreeXXXXTableResources function.
> +
> +    @param [in]  This           Pointer to the table generator.
> +    @param [in]  AcpiTableInfo  Pointer to the ACPI Table Info.
> +    @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                                Protocol Interface.
> +    @param [out] Table          Pointer to the constructed ACPI Table.
> +
> +    @retval EFI_SUCCESS           Table generated successfully.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_NOT_FOUND         The required object was not found.
> +    @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                  Manager is less than the Object size for the
> +                                  requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildIortTable (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN  CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST AcpiTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  EFI_STATUS                             Status;
> +  UINT32                                 TableSize;
> +  UINT32                                 IortNodeCount;
> +
> +  UINT32                                 ItsGroupNodeCount;
> +  UINT32                                 NamedComponentNodeCount;
> +  UINT32                                 RootComplexNodeCount;
> +  UINT32                                 SmmuV1V2NodeCount;
> +  UINT32                                 SmmuV3NodeCount;
> +  UINT32                                 PmcgNodeCount;
> +
> +  UINT32                                 ItsGroupOffset;
> +  UINT32                                 NamedComponentOffset;
> +  UINT32                                 RootComplexOffset;
> +  UINT32                                 SmmuV1V2Offset;
> +  UINT32                                 SmmuV3Offset;
> +  UINT32                                 PmcgOffset;
> +
> +  CM_ARM_ITS_GROUP_NODE                * ItsGroupNodeList;
> +  CM_ARM_NAMED_COMPONENT_NODE          *
> NamedComponentNodeList;
> +  CM_ARM_ROOT_COMPLEX_NODE             * RootComplexNodeList;
> +  CM_ARM_SMMUV1_SMMUV2_NODE            * SmmuV1V2NodeList;
> +  CM_ARM_SMMUV3_NODE                   * SmmuV3NodeList;
> +  CM_ARM_PMCG_NODE                     * PmcgNodeList;
> +
> +  EFI_ACPI_6_0_IO_REMAPPING_TABLE      * Iort;
> +  IORT_NODE_INDEXER                    * NodeIndexer;
> +  ACPI_IORT_GENERATOR                  * Generator;
> +
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Table != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  Generator = (ACPI_IORT_GENERATOR*)This;
> +  *Table = NULL;
> +
> +  // Get the ITS group node info
> +  Status = GetEArmObjItsGroup (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &ItsGroupNodeList,
> +             &ItsGroupNodeCount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // Add the ITS group node count
> +  IortNodeCount = ItsGroupNodeCount;
> +
> +  // Get the Named component node info
> +  Status = GetEArmObjNamedComponent (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &NamedComponentNodeList,
> +             &NamedComponentNodeCount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to get Named Component Node Info. Status
> = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // Add the Named Component group count
> +  IortNodeCount += NamedComponentNodeCount;
> +
> +  // Get the Root complex node info
> +  Status = GetEArmObjRootComplex (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &RootComplexNodeList,
> +             &RootComplexNodeCount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // Add the Root Complex node count
> +  IortNodeCount += RootComplexNodeCount;
> +
> +  // Get the SMMU v1/v2 node info
> +  Status = GetEArmObjSmmuV1SmmuV2 (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &SmmuV1V2NodeList,
> +             &SmmuV1V2NodeCount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status
> = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // Add the SMMU v1/v2 node count
> +  IortNodeCount += SmmuV1V2NodeCount;
> +
> +  // Get the SMMUv3 node info
> +  Status = GetEArmObjSmmuV3 (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &SmmuV3NodeList,
> +             &SmmuV3NodeCount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // Add the SMMUv3 node count
> +  IortNodeCount += SmmuV3NodeCount;
> +
> +  // Get the PMCG node info
> +  Status = GetEArmObjPmcg (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &PmcgNodeList,
> +             &PmcgNodeCount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // Add the PMCG node count
> +  IortNodeCount += PmcgNodeCount;
> +
> +  // Allocate Node Indexer array
> +  NodeIndexer = (IORT_NODE_INDEXER*)AllocateZeroPool (
> +                                      (sizeof (IORT_NODE_INDEXER) *
> +                                       IortNodeCount)
> +                                      );
> +  if (NodeIndexer == NULL) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to allocate memory for Node Indexer" \
> +      " Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));
> +  Generator->IortNodeCount = IortNodeCount;
> +  Generator->NodeIndexer = NodeIndexer;
> +
> +  // Calculate the size of the IORT table
> +  TableSize = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
> +
> +  // ITS Group Nodes
> +  if (ItsGroupNodeCount > 0) {
> +    ItsGroupOffset = TableSize;
> +    // Size of ITS Group node list.
> +    TableSize += GetSizeofItsGroupNodes (
> +                   ItsGroupOffset,
> +                   ItsGroupNodeList,
> +                   ItsGroupNodeCount,
> +                   &NodeIndexer
> +                   );
> +  }
> +
> +  // Named Component Nodes
> +  if (NamedComponentNodeCount > 0) {
> +    NamedComponentOffset = TableSize;
> +    // Size of Named Component node list.
> +    TableSize += GetSizeofNamedComponentNodes (
> +                   NamedComponentOffset,
> +                   NamedComponentNodeList,
> +                   NamedComponentNodeCount,
> +                   &NodeIndexer
> +                   );
> +  }
> +
> +  // Root Complex Nodes
> +  if (RootComplexNodeCount > 0) {
> +    RootComplexOffset = TableSize;
> +    // Size of Root Complex node list.
> +    TableSize += GetSizeofRootComplexNodes (
> +                   RootComplexOffset,
> +                   RootComplexNodeList,
> +                   RootComplexNodeCount,
> +                   &NodeIndexer
> +                   );
> +  }
> +
> +  // SMMUv1/SMMUv2 Nodes
> +  if (SmmuV1V2NodeCount > 0) {
> +    SmmuV1V2Offset = TableSize;
> +    // Size of SMMUv1/SMMUv2 node list.
> +    TableSize += GetSizeofSmmuV1V2Nodes (
> +                   SmmuV1V2Offset,
> +                   SmmuV1V2NodeList,
> +                   SmmuV1V2NodeCount,
> +                   &NodeIndexer
> +                   );
> +  }
> +
> +  // SMMUv3 Nodes
> +  if (SmmuV3NodeCount > 0) {
> +    SmmuV3Offset = TableSize;
> +    // Size of SMMUv3 node list.
> +    TableSize += GetSizeofSmmuV3Nodes (
> +                   SmmuV3Offset,
> +                   SmmuV3NodeList,
> +                   SmmuV3NodeCount,
> +                   &NodeIndexer
> +                   );
> +  }
> +
> +  // PMCG Nodes
> +  if (PmcgNodeCount > 0) {
> +    PmcgOffset = TableSize;
> +    // Size of PMCG node list.
> +    TableSize += GetSizeofPmcgNodes (
> +                   PmcgOffset,
> +                   PmcgNodeList,
> +                   PmcgNodeCount,
> +                   &NodeIndexer
> +                   );
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "INFO: IORT:\n" \
> +    " IortNodeCount = %d\n" \
> +    " TableSize = %d\n",
> +    IortNodeCount,
> +    TableSize
> +    ));
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    " ItsGroupNodeCount = %d\n" \
> +    " ItsGroupOffset = %d\n",
> +    ItsGroupNodeCount,
> +    ItsGroupOffset
> +    ));
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    " NamedComponentNodeCount = %d\n" \
> +    " NamedComponentOffset = %d\n",
> +    NamedComponentNodeCount,
> +    NamedComponentOffset
> +    ));
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    " RootComplexNodeCount = %d\n" \
> +    " RootComplexOffset = %d\n",
> +    RootComplexNodeCount,
> +    RootComplexOffset
> +    ));
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    " SmmuV1V2NodeCount = %d\n" \
> +    " SmmuV1V2Offset = %d\n",
> +    SmmuV1V2NodeCount,
> +    SmmuV1V2Offset
> +    ));
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    " SmmuV3NodeCount = %d\n" \
> +    " SmmuV3Offset = %d\n",
> +    SmmuV3NodeCount,
> +    SmmuV3Offset
> +    ));
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    " PmcgNodeCount = %d\n" \
> +    " PmcgOffset = %d\n",
> +    PmcgNodeCount,
> +    PmcgOffset
> +    ));
> +
> +  // Allocate the Buffer for IORT table
> +  *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
> +  if (*Table == NULL) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \
> +      " Status = %r\n",
> +      TableSize,
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE*)*Table;
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "IORT: Iort = 0x%p TableSize = 0x%x\n",
> +    Iort,
> +    TableSize
> +    ));
> +
> +  Status = AddAcpiHeader (CfgMgrProtocol, This, &Iort->Header, TableSize);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: IORT: Failed to add ACPI header. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // Update IORT table
> +  Iort->NumNodes = IortNodeCount;
> +  Iort->NodeOffset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
> +  Iort->Reserved = EFI_ACPI_RESERVED_DWORD;
> +
> +  if (ItsGroupNodeCount > 0) {
> +    Status = AddItsGroupNodes (
> +               This,
> +               CfgMgrProtocol,
> +               Iort,
> +               ItsGroupOffset,
> +               ItsGroupNodeList,
> +               ItsGroupNodeCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",
> +        Status
> +        ));
> +      goto error_handler;
> +    }
> +  }
> +
> +  if (NamedComponentNodeCount > 0) {
> +    Status = AddNamedComponentNodes (
> +               This,
> +               CfgMgrProtocol,
> +               Iort,
> +               NamedComponentOffset,
> +               NamedComponentNodeList,
> +               NamedComponentNodeCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to add Named Component Node. Status = %r\n",
> +        Status
> +        ));
> +      goto error_handler;
> +    }
> +  }
> +
> +  if (RootComplexNodeCount > 0) {
> +    Status = AddRootComplexNodes (
> +               This,
> +               CfgMgrProtocol,
> +               Iort,
> +               RootComplexOffset,
> +               RootComplexNodeList,
> +               RootComplexNodeCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",
> +        Status
> +        ));
> +      goto error_handler;
> +    }
> +  }
> +
> +  if (SmmuV1V2NodeCount > 0) {
> +    Status = AddSmmuV1V2Nodes (
> +               This,
> +               CfgMgrProtocol,
> +               Iort,
> +               SmmuV1V2Offset,
> +               SmmuV1V2NodeList,
> +               SmmuV1V2NodeCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",
> +        Status
> +        ));
> +      goto error_handler;
> +    }
> +  }
> +
> +  if (SmmuV3NodeCount > 0) {
> +    Status = AddSmmuV3Nodes (
> +               This,
> +               CfgMgrProtocol,
> +               Iort,
> +               SmmuV3Offset,
> +               SmmuV3NodeList,
> +               SmmuV3NodeCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
> +        Status
> +        ));
> +      goto error_handler;
> +    }
> +  }
> +
> +  if (PmcgNodeCount > 0) {
> +    Status = AddPmcgNodes (
> +               This,
> +               CfgMgrProtocol,
> +               Iort,
> +               PmcgOffset,
> +               PmcgNodeList,
> +               PmcgNodeCount
> +               );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
> +        Status
> +        ));
> +      goto error_handler;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +error_handler:
> +  if (Generator->NodeIndexer != NULL) {
> +    FreePool (Generator->NodeIndexer);
> +    Generator->NodeIndexer = NULL;
> +  }
> +
> +  if (*Table != NULL) {
> +    FreePool (*Table);
> +    *Table = NULL;
> +  }
> +  return Status;
> +}
> +
> +/** Free any resources allocated for constructing the IORT
> +
> +  @param [in]      This           Pointer to the table generator.
> +  @param [in]      AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]      CfgMgrProtocol Pointer to the Configuration Manager
> +                                  Protocol Interface.
> +  @param [in, out] Table          Pointer to the ACPI Table.
> +
> +  @retval EFI_SUCCESS           The resources were freed successfully.
> +  @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
> +*/
> +STATIC
> +EFI_STATUS
> +FreeIortTableResources (
> +  IN      CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN      CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST
> AcpiTableInfo,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN OUT        EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  ACPI_IORT_GENERATOR   * Generator;
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  Generator = (ACPI_IORT_GENERATOR*)This;
> +
> +  // Free any memory allocated by the generator
> +  if (Generator->NodeIndexer != NULL) {
> +    FreePool (Generator->NodeIndexer);
> +    Generator->NodeIndexer = NULL;
> +  }
> +
> +  if ((Table == NULL) || (*Table == NULL)) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: IORT: Invalid Table Pointer\n"));
> +    ASSERT ((Table != NULL) && (*Table != NULL));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  FreePool (*Table);
> +  *Table = NULL;
> +  return EFI_SUCCESS;
> +}
> +
> +/** The IORT Table Generator revision.
> +*/
> +#define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)
> +
> +/** The interface for the MADT Table Generator.
> +*/
> +STATIC
> +ACPI_IORT_GENERATOR IortGenerator = {
> +  // ACPI table generator header
> +  {
> +    // Generator ID
> +    CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_IORT),
> +    // Generator Description
> +    L"ACPI.STD.IORT.GENERATOR",
> +    // ACPI Table Signature
> +    EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE,
> +    // ACPI Table Revision
> +    EFI_ACPI_IO_REMAPPING_TABLE_REVISION,
> +    // Creator ID
> +    TABLE_GENERATOR_CREATOR_ID_ARM,
> +    // Creator Revision
> +    IORT_GENERATOR_REVISION,
> +    // Build Table function
> +    BuildIortTable,
> +    // Free Resource function
> +    FreeIortTableResources
> +  },
> +
> +  // IORT Generator private data
> +
> +  // Iort Node count
> +  0,
> +  // Pointer to Iort node indexer
> +  NULL
> +};
> +
> +/** Register the Generator with the ACPI Table Factory.
> +
> +    @param [in]  ImageHandle  The handle to the image.
> +    @param [in]  SystemTable  Pointer to the System Table.
> +
> +    @retval EFI_SUCCESS           The Generator is registered.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_ALREADY_STARTED   The Generator for the Table ID
> +                                  is already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiIortLibConstructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = RegisterAcpiTableGenerator
> (&IortGenerator.Header);
> +  DEBUG ((DEBUG_INFO, "IORT: Register Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> +
> +/** Deregister the Generator from the ACPI Table Factory.
> +
> +    @param [in]  ImageHandle  The handle to the image.
> +    @param [in]  SystemTable  Pointer to the System Table.
> +
> +    @retval EFI_SUCCESS           The Generator is deregistered.
> +    @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +    @retval EFI_NOT_FOUND         The Generator is not registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiIortLibDestructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = DeregisterAcpiTableGenerator
> (&IortGenerator.Header);
> +  DEBUG ((DEBUG_INFO, "Iort: Deregister Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..44c89042e23d50ca73
> 70ee6cae0761e692b78d31
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h
> @@ -0,0 +1,50 @@
> +/** @file
> +
> +  Copyright (c) 2018, ARM Limited. All rights reserved.
> +
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Glossary:
> +    - Cm or CM   - Configuration Manager
> +    - Obj or OBJ - Object
> +    - Std or STD - Standard
> +**/
> +
> +#ifndef IORT_GENERATOR_H_
> +#define IORT_GENERATOR_H_
> +
> +#pragma pack(1)
> +
> +/** A structure that describes the Node indexer
> +    used for indexing the IORT nodes.
> +*/
> +typedef struct IortNodeIndexer {
> +  /// Index token for the Node
> +  CM_OBJECT_TOKEN    Token;
> +  /// Pointer to the node
> +  VOID             * Object;
> +  /// Node offset from the start of the IORT table
> +  UINT32             Offset;
> +} IORT_NODE_INDEXER;
> +
> +typedef struct AcpiIortGenerator {
> +  /// ACPI Table generator header
> +  ACPI_TABLE_GENERATOR  Header;
> +
> +  // IORT Generator private data
> +
> +  /// IORT node count
> +  UINT32                IortNodeCount;
> +  /// Pointer to the node indexer array
> +  IORT_NODE_INDEXER   * NodeIndexer;
> +} ACPI_IORT_GENERATOR;
> +
> +#pragma pack()
> +
> +#endif // IORT_GENERATOR_H_
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/AcpiMadtLibArm.
> inf
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/AcpiMadtLibArm.
> inf
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..03be5a2ab6e8df5029
> d1c823f51ff01a4293f694
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/AcpiMadtLibArm.
> inf
> @@ -0,0 +1,41 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x00010019
> +  BASE_NAME      = AcpiMadtLibArm
> +  FILE_GUID      = AF76C93B-41B5-454D-83CD-D2A80A1C1E38
> +  VERSION_STRING = 1.0
> +  MODULE_TYPE    = DXE_DRIVER
> +  LIBRARY_CLASS  = NULL|DXE_DRIVER
> +  CONSTRUCTOR    = AcpiMadtLibConstructor
> +  DESTRUCTOR     = AcpiMadtLibDestructor
> +
> +[Sources]
> +  MadtGenerator.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +
> +[Pcd]
> +
> +[Protocols]
> +
> +[Guids]
> +
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..a08832aa813a6df0df5
> 1f82741084f81d511b30a
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c
> @@ -0,0 +1,717 @@
> +/** @file
> +  MADT Table Generator
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Reference(s):
> +  - ACPI 6.2 Specification - Errata A, September 2017
> +
> +**/
> +
> +#include <Library/AcpiLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <Library/TableHelperLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +
> +/** ARM standard MADT Generator
> +
> +Requirements:
> +  The following Configuration Manager Object(s) are required by
> +  this Generator:
> +  - EArmObjGicCInfo
> +  - EArmObjGicDInfo
> +  - EArmObjGicMsiFrameInfo (OPTIONAL)
> +  - EArmObjGicRedistributorInfo (OPTIONAL)
> +  - EArmObjGicItsInfo (OPTIONAL)
> +*/
> +
> +/** This macro expands to a function that retrieves the GIC
> +    CPU interface Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjGicCInfo,
> +  CM_ARM_GICC_INFO
> +  );
> +
> +/** This macro expands to a function that retrieves the GIC
> +    Distributor Information from the Configuration Manager.
> +*/
> +
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjGicDInfo,
> +  CM_ARM_GICD_INFO
> +  );
> +
> +/** This macro expands to a function that retrieves the GIC
> +    MSI Frame Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjGicMsiFrameInfo,
> +  CM_ARM_GIC_MSI_FRAME_INFO
> +  );
> +
> +/** This macro expands to a function that retrieves the GIC
> +    Redistributor Information from the Configuration Manager.
> +*/
> +
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjGicRedistributorInfo,
> +  CM_ARM_GIC_REDIST_INFO
> +  );
> +
> +/** This macro expands to a function that retrieves the GIC
> +    Interrupt Translation Service Information from the
> +    Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjGicItsInfo,
> +  CM_ARM_GIC_ITS_INFO
> +  );
> +
> +/** This function updates the GIC CPU Interface Information in the
> +    EFI_ACPI_6_2_GIC_STRUCTURE structure.
> +
> +  @param [in]  Gicc      Pointer to GIC CPU Interface structure.
> +  @param [in]  GicCInfo  Pointer to the GIC CPU Interface Information.
> +*/
> +STATIC
> +VOID
> +AddGICC (
> +  IN  EFI_ACPI_6_2_GIC_STRUCTURE  * CONST Gicc,
> +  IN  CONST CM_ARM_GICC_INFO      * CONST GicCInfo
> +  )
> +{
> +  ASSERT (Gicc != NULL);
> +  ASSERT (GicCInfo != NULL);
> +
> +  // UINT8 Type
> +  Gicc->Type = EFI_ACPI_6_2_GIC;
> +  // UINT8 Length
> +  Gicc->Length = sizeof (EFI_ACPI_6_2_GIC_STRUCTURE);
> +  // UINT16 Reserved
> +  Gicc->Reserved = EFI_ACPI_RESERVED_WORD;
> +
> +  // UINT32 CPUInterfaceNumber
> +  Gicc->CPUInterfaceNumber = GicCInfo->CPUInterfaceNumber;
> +  // UINT32 AcpiProcessorUid
> +  Gicc->AcpiProcessorUid = GicCInfo->AcpiProcessorUid;
> +  // UINT32 Flags
> +  Gicc->Flags = GicCInfo->Flags;
> +  // UINT32 ParkingProtocolVersion
> +  Gicc->ParkingProtocolVersion = GicCInfo->ParkingProtocolVersion;
> +  // UINT32 PerformanceInterruptGsiv
> +  Gicc->PerformanceInterruptGsiv = GicCInfo->PerformanceInterruptGsiv;
> +  // UINT64 ParkedAddress
> +  Gicc->ParkedAddress = GicCInfo->ParkedAddress;
> +
> +  // UINT64 PhysicalBaseAddress
> +  Gicc->PhysicalBaseAddress = GicCInfo->PhysicalBaseAddress;
> +  // UINT64 GICV
> +  Gicc->GICV = GicCInfo->GICV;
> +  // UINT64 GICH
> +  Gicc->GICH = GicCInfo->GICH;
> +
> +  // UINT32 VGICMaintenanceInterrupt
> +  Gicc->VGICMaintenanceInterrupt = GicCInfo->VGICMaintenanceInterrupt;
> +  // UINT64 GICRBaseAddress
> +  Gicc->GICRBaseAddress = GicCInfo->GICRBaseAddress;
> +
> +  // UINT64 MPIDR
> +  Gicc->MPIDR = GicCInfo->MPIDR;
> +  // UINT8 ProcessorPowerEfficiencyClass
> +  Gicc->ProcessorPowerEfficiencyClass =
> +    GicCInfo->ProcessorPowerEfficiencyClass;
> +  // UINT8 Reserved2[3]
> +  Gicc->Reserved2[0] = EFI_ACPI_RESERVED_BYTE;
> +  Gicc->Reserved2[1] = EFI_ACPI_RESERVED_BYTE;
> +  Gicc->Reserved2[2] = EFI_ACPI_RESERVED_BYTE;
> +}
> +
> +/** Add the GIC CPU Interface Information to the MADT Table.
> +
> +  @param [in]  Gicc      Pointer to GIC CPU Interface
> +                         structure list.
> +  @param [in]  GicCInfo  Pointer to the GIC CPU
> +                         Information list.
> +  @param [in]  GicCCount Count of GIC CPU Interfaces.
> +*/
> +STATIC
> +VOID
> +AddGICCList (
> +  IN  EFI_ACPI_6_2_GIC_STRUCTURE  * Gicc,
> +  IN  CONST CM_ARM_GICC_INFO      * GicCInfo,
> +  IN        UINT32                  GicCCount
> +  )
> +{
> +  ASSERT (Gicc != NULL);
> +  ASSERT (GicCInfo != NULL);
> +
> +  while (GicCCount-- != 0) {
> +    AddGICC (Gicc++, GicCInfo++);
> +  }
> +}
> +
> +/** Update the GIC Distributor Information in the MADT Table.
> +
> +  @param [in]  Gicd      Pointer to GIC Distributor structure.
> +  @param [in]  GicDInfo  Pointer to the GIC Distributor Information.
> +*/
> +STATIC
> +VOID
> +AddGICD (
> +  EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE  * CONST Gicd,
> +  CONST CM_ARM_GICD_INFO                  * CONST GicDInfo
> +)
> +{
> +  ASSERT (Gicd != NULL);
> +  ASSERT (GicDInfo != NULL);
> +
> +  // UINT8 Type
> +  Gicd->Type = EFI_ACPI_6_2_GICD;
> +  // UINT8 Length
> +  Gicd->Length = sizeof (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE);
> +  // UINT16 Reserved
> +  Gicd->Reserved1 = EFI_ACPI_RESERVED_WORD;
> +  // UINT32 Identifier
> +  Gicd->GicId = GicDInfo->GicId;
> +  // UINT64 PhysicalBaseAddress
> +  Gicd->PhysicalBaseAddress = GicDInfo->PhysicalBaseAddress;
> +  // UINT32 VectorBase
> +  Gicd->SystemVectorBase = EFI_ACPI_RESERVED_DWORD;
> +  // UINT8  GicVersion
> +  Gicd->GicVersion = GicDInfo->GicVersion;
> +  // UINT8  Reserved2[3]
> +  Gicd->Reserved2[0] = EFI_ACPI_RESERVED_BYTE;
> +  Gicd->Reserved2[1] = EFI_ACPI_RESERVED_BYTE;
> +  Gicd->Reserved2[2] = EFI_ACPI_RESERVED_BYTE;
> +}
> +
> +/** Update the GIC MSI Frame Information.
> +
> +  @param [in]  GicMsiFrame      Pointer to GIC MSI Frame structure.
> +  @param [in]  GicMsiFrameInfo  Pointer to the GIC MSI Frame
> Information.
> +*/
> +STATIC
> +VOID
> +AddGICMsiFrame (
> +  IN  EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE  * CONST GicMsiFrame,
> +  IN  CONST CM_ARM_GIC_MSI_FRAME_INFO       * CONST
> GicMsiFrameInfo
> +)
> +{
> +  ASSERT (GicMsiFrame != NULL);
> +  ASSERT (GicMsiFrameInfo != NULL);
> +
> +  GicMsiFrame->Type = EFI_ACPI_6_2_GIC_MSI_FRAME;
> +  GicMsiFrame->Length = sizeof
> (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE);
> +  GicMsiFrame->Reserved1 = EFI_ACPI_RESERVED_WORD;
> +  GicMsiFrame->GicMsiFrameId = GicMsiFrameInfo->GicMsiFrameId;
> +  GicMsiFrame->PhysicalBaseAddress = GicMsiFrameInfo-
> >PhysicalBaseAddress;
> +
> +  GicMsiFrame->Flags = GicMsiFrameInfo->Flags;
> +  GicMsiFrame->SPICount = GicMsiFrameInfo->SPICount;
> +  GicMsiFrame->SPIBase = GicMsiFrameInfo->SPIBase;
> +}
> +
> +/** Add the GIC MSI Frame Information to the MADT Table.
> +
> +  @param [in]  GicMsiFrame      Pointer to GIC MSI Frame structure list.
> +  @param [in]  GicMsiFrameInfo  Pointer to the GIC MSI Frame info list.
> +  @param [in]  GicMsiFrameCount Count of GIC MSI Frames.
> +*/
> +STATIC
> +VOID
> +AddGICMsiFrameInfoList (
> +  IN  EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE  * GicMsiFrame,
> +  IN  CONST CM_ARM_GIC_MSI_FRAME_INFO       * GicMsiFrameInfo,
> +  IN        UINT32                            GicMsiFrameCount
> +)
> +{
> +  ASSERT (GicMsiFrame != NULL);
> +  ASSERT (GicMsiFrameInfo != NULL);
> +
> +  while (GicMsiFrameCount-- != 0) {
> +    AddGICMsiFrame (GicMsiFrame++, GicMsiFrameInfo++);
> +  }
> +}
> +
> +/** Update the GIC Redistributor Information.
> +
> +  @param [in]  Gicr                 Pointer to GIC Redistributor structure.
> +  @param [in]  GicRedisributorInfo  Pointer to the GIC Redistributor Info.
> +*/
> +STATIC
> +VOID
> +AddGICRedistributor (
> +  IN  EFI_ACPI_6_2_GICR_STRUCTURE   * CONST Gicr,
> +  IN  CONST CM_ARM_GIC_REDIST_INFO  * CONST GicRedisributorInfo
> +  )
> +{
> +  ASSERT (Gicr != NULL);
> +  ASSERT (GicRedisributorInfo != NULL);
> +
> +  Gicr->Type = EFI_ACPI_6_2_GICR;
> +  Gicr->Length = sizeof (EFI_ACPI_6_2_GICR_STRUCTURE);
> +  Gicr->Reserved = EFI_ACPI_RESERVED_WORD;
> +  Gicr->DiscoveryRangeBaseAddress =
> +    GicRedisributorInfo->DiscoveryRangeBaseAddress;
> +  Gicr->DiscoveryRangeLength = GicRedisributorInfo-
> >DiscoveryRangeLength;
> +}
> +
> +/** Add the GIC Redistributor Information to the MADT Table.
> +
> +  @param [in]  Gicr      Pointer to GIC Redistributor structure list.
> +  @param [in]  GicRInfo  Pointer to the GIC Distributor info list.
> +  @param [in]  GicRCount Count of GIC Distributors.
> +*/
> +STATIC
> +VOID
> +AddGICRedistributorList (
> +  IN  EFI_ACPI_6_2_GICR_STRUCTURE   * Gicr,
> +  IN  CONST CM_ARM_GIC_REDIST_INFO  * GicRInfo,
> +  IN        UINT32                    GicRCount
> +)
> +{
> +  ASSERT (Gicr != NULL);
> +  ASSERT (GicRInfo != NULL);
> +
> +  while (GicRCount-- != 0) {
> +    AddGICRedistributor (Gicr++, GicRInfo++);
> +  }
> +}
> +
> +/** Update the GIC Interrupt Translation Service Information
> +
> +  @param [in]  GicIts      Pointer to GIC ITS structure.
> +  @param [in]  GicItsInfo  Pointer to the GIC ITS Information.
> +*/
> +STATIC
> +VOID
> +AddGICInterruptTranslationService (
> +  IN  EFI_ACPI_6_2_GIC_ITS_STRUCTURE  * CONST GicIts,
> +  IN  CONST CM_ARM_GIC_ITS_INFO       * CONST GicItsInfo
> +)
> +{
> +  ASSERT (GicIts != NULL);
> +  ASSERT (GicItsInfo != NULL);
> +
> +  GicIts->Type = EFI_ACPI_6_2_GIC_ITS;
> +  GicIts->Length = sizeof (EFI_ACPI_6_2_GIC_ITS_STRUCTURE);
> +  GicIts->Reserved = EFI_ACPI_RESERVED_WORD;
> +  GicIts->GicItsId = GicItsInfo->GicItsId;
> +  GicIts->PhysicalBaseAddress = GicItsInfo->PhysicalBaseAddress;
> +  GicIts->Reserved2 = EFI_ACPI_RESERVED_DWORD;
> +}
> +
> +/** Add the GIC Interrupt Translation Service Information
> +    to the MADT Table.
> +
> +  @param [in]  GicIts       Pointer to GIC ITS structure list.
> +  @param [in]  GicItsInfo   Pointer to the GIC ITS list.
> +  @param [in]  GicItsCount  Count of GIC ITS.
> +*/
> +STATIC
> +VOID
> +AddGICItsList (
> +  IN  EFI_ACPI_6_2_GIC_ITS_STRUCTURE  * GicIts,
> +  IN  CONST CM_ARM_GIC_ITS_INFO       * GicItsInfo,
> +  IN        UINT32                      GicItsCount
> +)
> +{
> +  ASSERT (GicIts != NULL);
> +  ASSERT (GicItsInfo != NULL);
> +
> +  while (GicItsCount-- != 0) {
> +    AddGICInterruptTranslationService (GicIts++, GicItsInfo++);
> +  }
> +}
> +
> +/** Construct the MADT ACPI table.
> +
> +  This function invokes the Configuration Manager protocol interface
> +  to get the required hardware information for generating the ACPI
> +  table.
> +
> +  If this function allocates any resources then they must be freed
> +  in the FreeXXXXTableResources function.
> +
> +  @param [in]  This           Pointer to the table generator.
> +  @param [in]  AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +  @param [out] Table          Pointer to the constructed ACPI Table.
> +
> +  @retval EFI_SUCCESS           Table generated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildMadtTable (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN  CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST AcpiTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  EFI_STATUS                   Status;
> +  UINT32                       TableSize;
> +  UINT32                       GicCCount;
> +  UINT32                       GicDCount;
> +  UINT32                       GicMSICount;
> +  UINT32                       GicRedistCount;
> +  UINT32                       GicItsCount;
> +  CM_ARM_GICC_INFO           * GicCInfo;
> +  CM_ARM_GICD_INFO           * GicDInfo;
> +  CM_ARM_GIC_MSI_FRAME_INFO  * GicMSIInfo;
> +  CM_ARM_GIC_REDIST_INFO     * GicRedistInfo;
> +  CM_ARM_GIC_ITS_INFO        * GicItsInfo;
> +  UINT32                       GicCOffset;
> +  UINT32                       GicDOffset;
> +  UINT32                       GicMSIOffset;
> +  UINT32                       GicRedistOffset;
> +  UINT32                       GicItsOffset;
> +
> +  EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER  * Madt;
> +
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Table != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  *Table = NULL;
> +
> +  Status = GetEArmObjGicCInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &GicCInfo,
> +             &GicCCount
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MADT: Failed to get GICC Info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  if (GicCCount == 0) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MADT: GIC CPU Interface information not provided.\n"
> +      ));
> +    ASSERT (GicCCount != 0);
> +    Status = EFI_INVALID_PARAMETER;
> +    goto error_handler;
> +  }
> +
> +  Status = GetEArmObjGicDInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &GicDInfo,
> +             &GicDCount
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MADT: Failed to get GICD Info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  if (GicDCount == 0) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MADT: GIC Distributor information not provided.\n"
> +      ));
> +    ASSERT (GicDCount != 0);
> +    Status = EFI_INVALID_PARAMETER;
> +    goto error_handler;
> +  }
> +
> +  if (GicDCount > 1) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MADT: One, and only one, GIC distributor must be present."
> +      "GicDCount = %d\n",
> +      GicDCount
> +      ));
> +    ASSERT (GicDCount <= 1);
> +    Status = EFI_INVALID_PARAMETER;
> +    goto error_handler;
> +  }
> +
> +  Status = GetEArmObjGicMsiFrameInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &GicMSIInfo,
> +             &GicMSICount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MADT: Failed to get GIC MSI Info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  Status = GetEArmObjGicRedistributorInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &GicRedistInfo,
> +             &GicRedistCount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MADT: Failed to get GIC Redistributor Info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  Status = GetEArmObjGicItsInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &GicItsInfo,
> +             &GicItsCount
> +             );
> +  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MADT: Failed to get GIC ITS Info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  TableSize = sizeof
> (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER);
> +
> +  GicCOffset = TableSize;
> +  TableSize += (sizeof (EFI_ACPI_6_2_GIC_STRUCTURE) * GicCCount);
> +
> +  GicDOffset = TableSize;
> +  TableSize += (sizeof (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE) *
> GicDCount);
> +
> +  GicMSIOffset = TableSize;
> +  TableSize += (sizeof (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE) *
> GicMSICount);
> +
> +  GicRedistOffset = TableSize;
> +  TableSize += (sizeof (EFI_ACPI_6_2_GICR_STRUCTURE) * GicRedistCount);
> +
> +  GicItsOffset = TableSize;
> +  TableSize += (sizeof (EFI_ACPI_6_2_GIC_ITS_STRUCTURE) * GicItsCount);
> +
> +  // Allocate the Buffer for MADT table
> +  *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
> +  if (*Table == NULL) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MADT: Failed to allocate memory for MADT Table, Size = %d,"
> \
> +      " Status = %r\n",
> +      TableSize,
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  Madt =
> (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER*)*Table;
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "MADT: Madt = 0x%p TableSize = 0x%x\n",
> +    Madt,
> +    TableSize
> +    ));
> +
> +  Status = AddAcpiHeader (CfgMgrProtocol, This, &Madt->Header,
> TableSize);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MADT: Failed to add ACPI header. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  AddGICCList (
> +    (EFI_ACPI_6_2_GIC_STRUCTURE*)((UINT8*)Madt + GicCOffset),
> +    GicCInfo,
> +    GicCCount
> +    );
> +
> +  AddGICD (
> +    (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE*)((UINT8*)Madt +
> GicDOffset),
> +    GicDInfo
> +    );
> +
> +  if (GicMSICount != 0) {
> +    AddGICMsiFrameInfoList (
> +      (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE*)((UINT8*)Madt +
> GicMSIOffset),
> +      GicMSIInfo,
> +      GicMSICount
> +      );
> +  }
> +
> +  if (GicRedistCount != 0) {
> +    AddGICRedistributorList (
> +      (EFI_ACPI_6_2_GICR_STRUCTURE*)((UINT8*)Madt + GicRedistOffset),
> +      GicRedistInfo,
> +      GicRedistCount
> +      );
> +  }
> +
> +  if (GicItsCount != 0) {
> +    AddGICItsList (
> +      (EFI_ACPI_6_2_GIC_ITS_STRUCTURE*)((UINT8*)Madt + GicItsOffset),
> +      GicItsInfo,
> +      GicItsCount
> +      );
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +error_handler:
> +  if (*Table != NULL) {
> +    FreePool (*Table);
> +    *Table = NULL;
> +  }
> +  return Status;
> +}
> +
> +/** Free any resources allocated for constructing the MADT
> +
> +  @param [in]      This           Pointer to the table generator.
> +  @param [in]      AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]      CfgMgrProtocol Pointer to the Configuration Manager
> +                                  Protocol Interface.
> +  @param [in, out] Table          Pointer to the ACPI Table.
> +
> +  @retval EFI_SUCCESS           The resources were freed successfully.
> +  @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
> +*/
> +STATIC
> +EFI_STATUS
> +FreeMadtTableResources (
> +  IN      CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN      CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST
> AcpiTableInfo,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN OUT        EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  if ((Table == NULL) || (*Table == NULL)) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: MADT: Invalid Table Pointer\n"));
> +    ASSERT ((Table != NULL) && (*Table != NULL));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  FreePool (*Table);
> +  *Table = NULL;
> +  return EFI_SUCCESS;
> +}
> +
> +/** The MADT Table Generator revision.
> +*/
> +#define MADT_GENERATOR_REVISION CREATE_REVISION (1, 0)
> +
> +/** The interface for the MADT Table Generator.
> +*/
> +STATIC
> +CONST
> +ACPI_TABLE_GENERATOR MadtGenerator = {
> +  // Generator ID
> +  CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_MADT),
> +  // Generator Description
> +  L"ACPI.STD.MADT.GENERATOR",
> +  // ACPI Table Signature
> +  EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,
> +  // ACPI Table Revision
> +  EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,
> +  // Creator ID
> +  TABLE_GENERATOR_CREATOR_ID_ARM,
> +  // Creator Revision
> +  MADT_GENERATOR_REVISION,
> +  // Build Table function
> +  BuildMadtTable,
> +  // Free Resource function
> +  FreeMadtTableResources
> +};
> +
> +/** Register the Generator with the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is registered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID
> +                                is already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiMadtLibConstructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = RegisterAcpiTableGenerator (&MadtGenerator);
> +  DEBUG ((DEBUG_INFO, "MADT: Register Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> +
> +/** Deregister the Generator from the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is deregistered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The Generator is not registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiMadtLibDestructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = DeregisterAcpiTableGenerator (&MadtGenerator);
> +  DEBUG ((DEBUG_INFO, "MADT: Deregister Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/AcpiMcfgLibArm.i
> nf
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/AcpiMcfgLibArm.i
> nf
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..dfd20dbb86ff1cf9150e
> 8f6a219b2d1008f2116f
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/AcpiMcfgLibArm.i
> nf
> @@ -0,0 +1,41 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x00010019
> +  BASE_NAME      = AcpiMcfgLibArm
> +  FILE_GUID      = 8C9BDCB2-72D4-4F30-A12D-1145C3807FF7
> +  VERSION_STRING = 1.0
> +  MODULE_TYPE    = DXE_DRIVER
> +  LIBRARY_CLASS  = NULL|DXE_DRIVER
> +  CONSTRUCTOR    = AcpiMcfgLibConstructor
> +  DESTRUCTOR     = AcpiMcfgLibDestructor
> +
> +[Sources]
> +  McfgGenerator.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +
> +[Pcd]
> +
> +[Protocols]
> +
> +[Guids]
> +
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/McfgGenerator.c
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/McfgGenerator.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..8b95fd3d5c7f97e9cf7c
> cd956fcba56d46fc6cf1
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/McfgGenerator.c
> @@ -0,0 +1,342 @@
> +/** @file
> +  MCFG Table Generator
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Reference(s):
> +  - PCI Firmware Specification - Revision 3.2, January 26, 2015.
> +
> +**/
> +
> +#include
> <IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h>
> +#include <Library/AcpiLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <Library/TableHelperLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +
> +/** ARM standard MCFG Generator
> +
> +Requirements:
> +  The following Configuration Manager Object(s) are required by
> +  this Generator:
> +  - EArmObjPciConfigSpaceInfo
> +*/
> +
> +#pragma pack(1)
> +
> +/** This typedef is used to shorten the name of the MCFG Table
> +    header structure.
> +*/
> +typedef
> +
> EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HE
> ADER
> +  MCFG_TABLE;
> +
> +/** This typedef is used to shorten the name of the Enhanced
> +    Configuration Space address structure.
> +*/
> +typedef
> +
> EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_
> ADDRESS_ALLOCATION_STRUCTURE
> +  MCFG_CFG_SPACE_ADDR;
> +
> +#pragma pack()
> +
> +/** Retrieve the PCI Configuration Space Information.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjPciConfigSpaceInfo,
> +  CM_ARM_PCI_CONFIG_SPACE_INFO
> +  );
> +
> +/** Add the PCI Enhanced Configuration Space Information to the MCFG
> Table.
> +
> +  @param [in]  Mcfg                Pointer to MCFG Table.
> +  @param [in]  PciCfgSpaceOffset   Offset for the PCI Configuration Space
> +                                   Info structure in the MCFG Table.
> +  @param [in]  PciCfgSpaceInfoList Pointer to the PCI Configuration Space
> +                                   Info List.
> +  @param [in]  PciCfgSpaceCount    Count of PCI Configuration Space Info.
> +*/
> +STATIC
> +VOID
> +AddPciConfigurationSpaceList (
> +  IN       MCFG_TABLE                   * CONST Mcfg,
> +  IN CONST UINT32                               PciCfgSpaceOffset,
> +  IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO *       PciCfgSpaceInfoList,
> +  IN       UINT32                               PciCfgSpaceCount
> +)
> +{
> +  MCFG_CFG_SPACE_ADDR  * PciCfgSpace;
> +
> +  ASSERT (Mcfg != NULL);
> +  ASSERT (PciCfgSpaceInfoList != NULL);
> +
> +  PciCfgSpace = (MCFG_CFG_SPACE_ADDR *)((UINT8*)Mcfg +
> PciCfgSpaceOffset);
> +
> +  while (PciCfgSpaceCount-- != 0) {
> +    // Add PCI Configuration Space entry
> +    PciCfgSpace->BaseAddress = PciCfgSpaceInfoList->BaseAddress;
> +    PciCfgSpace->PciSegmentGroupNumber =
> +      PciCfgSpaceInfoList->PciSegmentGroupNumber;
> +    PciCfgSpace->StartBusNumber = PciCfgSpaceInfoList->StartBusNumber;
> +    PciCfgSpace->EndBusNumber = PciCfgSpaceInfoList->EndBusNumber;
> +    PciCfgSpace->Reserved = EFI_ACPI_RESERVED_DWORD;
> +    PciCfgSpace++;
> +    PciCfgSpaceInfoList++;
> +  }
> +}
> +
> +/** Construct the MCFG ACPI table.
> +
> +  This function invokes the Configuration Manager protocol interface
> +  to get the required hardware information for generating the ACPI
> +  table.
> +
> +  If this function allocates any resources then they must be freed
> +  in the FreeXXXXTableResources function.
> +
> +  @param [in]  This           Pointer to the table generator.
> +  @param [in]  AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +  @param [out] Table          Pointer to the constructed ACPI Table.
> +
> +  @retval EFI_SUCCESS           Table generated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildMcfgTable (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN  CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST AcpiTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  UINT32                          TableSize;
> +  UINT32                          ConfigurationSpaceCount;
> +  CM_ARM_PCI_CONFIG_SPACE_INFO  * PciConfigSpaceInfoList;
> +  MCFG_TABLE                    * Mcfg;
> +
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Table != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  *Table = NULL;
> +  Status = GetEArmObjPciConfigSpaceInfo (
> +              CfgMgrProtocol,
> +              CM_NULL_TOKEN,
> +              &PciConfigSpaceInfoList,
> +              &ConfigurationSpaceCount
> +              );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR,
> +      "ERROR: MCFG: Failed to get PCI Configuration Space Information." \
> +      " Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  if (ConfigurationSpaceCount == 0) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MCFG: Configuration Space Count = %d\n",
> +      ConfigurationSpaceCount
> +      ));
> +    Status = EFI_INVALID_PARAMETER;
> +    ASSERT (ConfigurationSpaceCount != 0);
> +    goto error_handler;
> +  }
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "MCFG: Configuration Space Count = %d\n",
> +    ConfigurationSpaceCount
> +    ));
> +
> +  // Calculate the MCFG Table Size
> +  TableSize = sizeof (MCFG_TABLE) +
> +    ((sizeof (MCFG_CFG_SPACE_ADDR) * ConfigurationSpaceCount));
> +
> +  *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
> +  if (*Table == NULL) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MCFG: Failed to allocate memory for MCFG Table, Size = %d,"
> \
> +      " Status = %r\n",
> +      TableSize,
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  Mcfg = (MCFG_TABLE*)*Table;
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "MCFG: Mcfg = 0x%p TableSize = 0x%x\n",
> +    Mcfg,
> +    TableSize
> +    ));
> +
> +  Status = AddAcpiHeader (CfgMgrProtocol, This, &Mcfg->Header,
> TableSize);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: MCFG: Failed to add ACPI header. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  Mcfg->Reserved = EFI_ACPI_RESERVED_QWORD;
> +
> +  AddPciConfigurationSpaceList (
> +    Mcfg,
> +    sizeof (MCFG_TABLE),
> +    PciConfigSpaceInfoList,
> +    ConfigurationSpaceCount
> +    );
> +
> +  return EFI_SUCCESS;
> +
> +error_handler:
> +  if (*Table != NULL) {
> +    FreePool (*Table);
> +    *Table = NULL;
> +  }
> +  return Status;
> +}
> +
> +/** Free any resources allocated for constructing the MCFG
> +
> +  @param [in]      This           Pointer to the table generator.
> +  @param [in]      AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]      CfgMgrProtocol Pointer to the Configuration Manager
> +                                  Protocol Interface.
> +  @param [in, out] Table          Pointer to the ACPI Table.
> +
> +  @retval EFI_SUCCESS           The resources were freed successfully.
> +  @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
> +*/
> +STATIC
> +EFI_STATUS
> +FreeMcfgTableResources (
> +  IN      CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN      CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST
> AcpiTableInfo,
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN OUT        EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  if ((Table == NULL) || (*Table == NULL)) {
> +    DEBUG ((DEBUG_ERROR, "ERROR: MCFG: Invalid Table Pointer\n"));
> +    ASSERT ((Table != NULL) && (*Table != NULL));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  FreePool (*Table);
> +  *Table = NULL;
> +  return EFI_SUCCESS;
> +}
> +
> +/** This macro defines the MCFG Table Generator revision.
> +*/
> +#define MCFG_GENERATOR_REVISION CREATE_REVISION (1, 0)
> +
> +/** The interface for the MCFG Table Generator.
> +*/
> +STATIC
> +CONST
> +ACPI_TABLE_GENERATOR McfgGenerator = {
> +  // Generator ID
> +  CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_MCFG),
> +  // Generator Description
> +  L"ACPI.STD.MCFG.GENERATOR",
> +  // ACPI Table Signature
> +
> EFI_ACPI_6_2_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE
> _BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE,
> +  // ACPI Table Revision
> +
> EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_RE
> VISION,
> +  // Creator ID
> +  TABLE_GENERATOR_CREATOR_ID_ARM,
> +  // Creator Revision
> +  MCFG_GENERATOR_REVISION,
> +  // Build Table function
> +  BuildMcfgTable,
> +  // Free Resource function
> +  FreeMcfgTableResources
> +};
> +
> +/** Register the Generator with the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is registered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID
> +                                is already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiMcfgLibConstructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = RegisterAcpiTableGenerator (&McfgGenerator);
> +  DEBUG ((DEBUG_INFO, "MCFG: Register Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> +
> +/** Deregister the Generator from the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is deregistered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The Generator is not registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiMcfgLibDestructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = DeregisterAcpiTableGenerator (&McfgGenerator);
> +  DEBUG ((DEBUG_INFO, "MCFG: Deregister Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibArm.inf
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibArm.inf
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..cbb53ecef6b5b16405b
> 03bebf28a664259928518
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibArm.inf
> @@ -0,0 +1,41 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x00010019
> +  BASE_NAME      = AcpiRawLibArm
> +  FILE_GUID      = 20F31568-D687-49BA-B326-CCD9D38EDE16
> +  VERSION_STRING = 1.0
> +  MODULE_TYPE    = DXE_DRIVER
> +  LIBRARY_CLASS  = NULL|DXE_DRIVER
> +  CONSTRUCTOR    = AcpiRawLibConstructor
> +  DESTRUCTOR     = AcpiRawLibDestructor
> +
> +[Sources]
> +  RawGenerator.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +
> +[Pcd]
> +
> +[Protocols]
> +
> +[Guids]
> +
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/RawGenerator.c
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/RawGenerator.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..974b2993c24ae148ee
> b88342c5e32fa997a31c0e
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/RawGenerator.c
> @@ -0,0 +1,142 @@
> +/** @file
> +  MCFG Table Generator
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +**/
> +
> +#include <Library/AcpiLib.h>
> +#include <Library/DebugLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <Library/TableHelperLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +
> +/** Construct the ACPI table using the ACPI table data provided.
> +
> +  This function invokes the Configuration Manager protocol interface
> +  to get the required hardware information for generating the ACPI
> +  table.
> +
> +  If this function allocates any resources then they must be freed
> +  in the FreeXXXXTableResources function.
> +
> +  @param [in]  This           Pointer to the table generator.
> +  @param [in]  AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +  @param [out] Table          Pointer to the constructed ACPI Table.
> +
> +  @retval EFI_SUCCESS           Table generated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildRawTable (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN  CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST AcpiTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Table != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableData != NULL);
> +
> +  if (AcpiTableInfo->AcpiTableData == NULL) {
> +    *Table = NULL;
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *Table = AcpiTableInfo->AcpiTableData;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** This macro defines the Raw Generator revision.
> +*/
> +#define RAW_GENERATOR_REVISION CREATE_REVISION (1, 0)
> +
> +/** The interface for the Raw Table Generator.
> +*/
> +STATIC
> +CONST
> +ACPI_TABLE_GENERATOR RawGenerator = {
> +  // Generator ID
> +  CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_RAW),
> +  // Generator Description
> +  L"ACPI.STD.RAW.GENERATOR",
> +  // ACPI Table Signature - Unused
> +  0,
> +  // ACPI Table Revision - Unused
> +  0,
> +  // Creator ID
> +  TABLE_GENERATOR_CREATOR_ID_ARM,
> +  // Creator Revision
> +  RAW_GENERATOR_REVISION,
> +  // Build Table function
> +  BuildRawTable,
> +  // No additional resources are allocated by the generator.
> +  // Hence the Free Resource function is not required.
> +  NULL
> +};
> +
> +/** Register the Generator with the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is registered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID
> +                                is already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiRawLibConstructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = RegisterAcpiTableGenerator (&RawGenerator);
> +  DEBUG ((DEBUG_INFO, "RAW: Register Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> +
> +/** Deregister the Generator from the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is deregistered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The Generator is not registered.
> +*/
> +
> +EFI_STATUS
> +EFIAPI
> +AcpiRawLibDestructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = DeregisterAcpiTableGenerator (&RawGenerator);
> +  DEBUG ((DEBUG_INFO, "RAW: Deregister Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibArm.inf
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibArm.in
> f
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..35c17089986f728a55
> 3d73849744e3f904f28b24
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibArm.in
> f
> @@ -0,0 +1,41 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x00010019
> +  BASE_NAME      = AcpiSpcrLibArm
> +  FILE_GUID      = 55088136-7B78-4974-B1EE-F630150D0DE7
> +  VERSION_STRING = 1.0
> +  MODULE_TYPE    = DXE_DRIVER
> +  LIBRARY_CLASS  = NULL|DXE_DRIVER
> +  CONSTRUCTOR    = AcpiSpcrLibConstructor
> +  DESTRUCTOR     = AcpiSpcrLibDestructor
> +
> +[Sources]
> +  SpcrGenerator.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +
> +[Pcd]
> +
> +[Protocols]
> +
> +[Guids]
> +
> diff --git
> a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/SpcrGenerator.c
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/SpcrGenerator.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..04b64b2c91951d3047
> a01bb5a807a3adb321ca50
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/SpcrGenerator.c
> @@ -0,0 +1,324 @@
> +/** @file
> +  SPCR Table Generator
> +
> +  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the
> BSD License
> +  which accompanies this distribution.  The full text of the license may be
> found at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +  @par Reference(s):
> +  - Microsoft Serial Port Console Redirection Table
> +    Specification - Version 1.03 - August 10, 2015.
> +
> +**/
> +
> +#include <IndustryStandard/DebugPort2Table.h>
> +#include <IndustryStandard/SerialPortConsoleRedirectionTable.h>
> +#include <Library/AcpiLib.h>
> +#include <Library/DebugLib.h>
> +#include <Protocol/AcpiTable.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <ConfigurationManagerHelper.h>
> +#include <Library/TableHelperLib.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +
> +/** ARM standard SPCR Table Generator
> +
> +  Constructs the SPCR table for PL011 or SBSA UART peripherals.
> +
> +Requirements:
> +  The following Configuration Manager Object(s) are required by
> +  this Generator:
> +  - EArmObjSerialConsolePortInfo
> +
> +NOTE: This implementation ignores the possibility that the Serial settings
> may
> +      be modified from the UEFI Shell.  A more complex handler would be
> needed
> +      to (e.g.) recover serial port settings from the UART, or non-volatile
> +      storage.
> +*/
> +
> +#pragma pack(1)
> +
> +/** This macro defines the no flow control option.
> +*/
> +#define SPCR_FLOW_CONTROL_NONE           0
> +
> +/**A template for generating the SPCR Table.
> +
> +  Note: fields marked "{Template}" will be updated dynamically.
> +*/
> +STATIC
> +EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE AcpiSpcr = {
> +  ACPI_HEADER (
> +
> EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE,
> +    EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE,
> +    EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_REVISION
> +    ),
> +  0, // {Template}: Serial Port Subtype
> +  {
> +    EFI_ACPI_RESERVED_BYTE,
> +    EFI_ACPI_RESERVED_BYTE,
> +    EFI_ACPI_RESERVED_BYTE
> +  },
> +  ARM_GAS32 (0), // {Template}: Serial Port Base Address
> +
> EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_
> GIC,
> +  0, // Not used on ARM
> +  0, // {Template}: Serial Port Interrupt
> +  0, // {Template}: Serial Port Baudrate
> +
> EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_PARITY_NO_PARIT
> Y,
> +  EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_STOP_BITS_1,
> +  SPCR_FLOW_CONTROL_NONE,
> +
> EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_A
> NSI,
> +  EFI_ACPI_RESERVED_BYTE,
> +  0xFFFF,
> +  0xFFFF,
> +  0x00,
> +  0x00,
> +  0x00,
> +  0x00000000,
> +  0x00,
> +  EFI_ACPI_RESERVED_DWORD
> +};
> +
> +#pragma pack()
> +
> +/** This macro expands to a function that retrieves the Serial
> +    Port Information from the Configuration Manager.
> +*/
> +GET_OBJECT_LIST (
> +  EObjNameSpaceArm,
> +  EArmObjSerialConsolePortInfo,
> +  CM_ARM_SERIAL_PORT_INFO
> +  )
> +
> +/** Construct the SPCR ACPI table.
> +
> +  This function invokes the Configuration Manager protocol interface
> +  to get the required hardware information for generating the ACPI
> +  table.
> +
> +  If this function allocates any resources then they must be freed
> +  in the FreeXXXXTableResources function.
> +
> +  @param [in]  This           Pointer to the table generator.
> +  @param [in]  AcpiTableInfo  Pointer to the ACPI Table Info.
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> +                              Protocol Interface.
> +  @param [out] Table          Pointer to the constructed ACPI Table.
> +
> +  @retval EFI_SUCCESS           Table generated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object was not found.
> +  @retval EFI_UNSUPPORTED       An unsupported baudrate was specified
> by the
> +                                Configuration Manager.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +BuildSpcrTable (
> +  IN  CONST ACPI_TABLE_GENERATOR                * CONST This,
> +  IN  CONST CM_STD_OBJ_ACPI_TABLE_INFO          * CONST AcpiTableInfo,
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  OUT       EFI_ACPI_DESCRIPTION_HEADER        ** CONST Table
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  CM_ARM_SERIAL_PORT_INFO  * SerialPortInfo;
> +
> +  ASSERT (This != NULL);
> +  ASSERT (AcpiTableInfo != NULL);
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Table != NULL);
> +  ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
> +  ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
> +
> +  *Table = NULL;
> +
> +  Status = GetEArmObjSerialConsolePortInfo (
> +             CfgMgrProtocol,
> +             CM_NULL_TOKEN,
> +             &SerialPortInfo,
> +             NULL
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: SPCR: Failed to get serial port information. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  if (SerialPortInfo->BaseAddress == 0) {
> +    Status = EFI_INVALID_PARAMETER;
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: SPCR: Uart port base address is invalid. BaseAddress =
> 0x%lx\n",
> +      SerialPortInfo->BaseAddress
> +      ));
> +    goto error_handler;
> +  }
> +
> +  if ((SerialPortInfo->PortSubtype !=
> +      EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART) &&
> +      (SerialPortInfo->PortSubtype !=
> +
> EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X)
> &&
> +      (SerialPortInfo->PortSubtype !=
> +      EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART)
> &&
> +      (SerialPortInfo->PortSubtype !=
> +      EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_DCC)) {
> +    Status = EFI_INVALID_PARAMETER;
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: SPCR: Uart port sybtype is invalid. PortSubtype = 0x%x\n",
> +      SerialPortInfo->PortSubtype
> +      ));
> +    goto error_handler;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "SPCR UART Configuration:\n"));
> +  DEBUG ((DEBUG_INFO, "  UART Base  = 0x%lx\n", SerialPortInfo-
> >BaseAddress));
> +  DEBUG ((DEBUG_INFO, "  Clock      = %d\n", SerialPortInfo->Clock));
> +  DEBUG ((DEBUG_INFO, "  Baudrate   = %ld\n", SerialPortInfo->BaudRate));
> +  DEBUG ((DEBUG_INFO, "  Interrupt  = %d\n", SerialPortInfo->Interrupt));
> +
> +  Status = AddAcpiHeader (
> +             CfgMgrProtocol,
> +             This,
> +             (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiSpcr,
> +             sizeof (EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE)
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: SPCR: Failed to add ACPI header. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // Update the serial port subtype
> +  AcpiSpcr.InterfaceType = SerialPortInfo->PortSubtype;
> +
> +  // Update the base address
> +  AcpiSpcr.BaseAddress.Address = SerialPortInfo->BaseAddress;
> +
> +  // Update the UART interrupt
> +  AcpiSpcr.GlobalSystemInterrupt = SerialPortInfo->Interrupt;
> +
> +  switch (SerialPortInfo->BaudRate) {
> +    case 9600:
> +      AcpiSpcr.BaudRate =
> +
> EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_9600;
> +      break;
> +    case 19200:
> +      AcpiSpcr.BaudRate =
> +
> EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_1920
> 0;
> +      break;
> +    case 57600:
> +      AcpiSpcr.BaudRate =
> +
> EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_5760
> 0;
> +      break;
> +    case 115200:
> +      AcpiSpcr.BaudRate =
> +
> EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_1152
> 00;
> +      break;
> +    default:
> +      Status = EFI_UNSUPPORTED;
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "ERROR: SPCR: Invalid Baud Rate %ld, Status = %r\n",
> +        SerialPortInfo->BaudRate,
> +        Status
> +        ));
> +      goto error_handler;
> +  } // switch
> +
> +  *Table = (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiSpcr;
> +
> +error_handler:
> +  return Status;
> +}
> +
> +/** This macro defines the SPCR Table Generator revision.
> +*/
> +#define SPCR_GENERATOR_REVISION CREATE_REVISION (1, 0)
> +
> +/** The interface for the SPCR Table Generator.
> +*/
> +STATIC
> +CONST
> +ACPI_TABLE_GENERATOR SpcrGenerator = {
> +  // Generator ID
> +  CREATE_STD_ACPI_TABLE_GEN_ID (ESTD_ACPI_TABLE_ID_SPCR),
> +  // Generator Description
> +  L"ACPI.STD.SPCR.GENERATOR",
> +  // ACPI Table Signature
> +  EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE,
> +  // ACPI Table Revision
> +  EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_REVISION,
> +  // Creator ID
> +  TABLE_GENERATOR_CREATOR_ID_ARM,
> +  // Creator Revision
> +  SPCR_GENERATOR_REVISION,
> +  // Build Table function
> +  BuildSpcrTable,
> +  // No additional resources are allocated by the generator.
> +  // Hence the Free Resource function is not required.
> +  NULL
> +};
> +
> +/** Register the Generator with the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is registered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_ALREADY_STARTED   The Generator for the Table ID
> +                                is already registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiSpcrLibConstructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = RegisterAcpiTableGenerator (&SpcrGenerator);
> +  DEBUG ((DEBUG_INFO, "SPCR: Register Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> +
> +/** Deregister the Generator from the ACPI Table Factory.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS           The Generator is deregistered.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The Generator is not registered.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AcpiSpcrLibDestructor (
> +  IN CONST EFI_HANDLE                ImageHandle,
> +  IN       EFI_SYSTEM_TABLE  * CONST SystemTable
> +  )
> +{
> +  EFI_STATUS  Status = DeregisterAcpiTableGenerator (&SpcrGenerator);
> +  DEBUG ((DEBUG_INFO, "SPCR: Deregister Generator. Status = %r\n",
> Status));
> +  ASSERT_EFI_ERROR (Status);
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c
> b/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..16bce37e4c0cb2666e
> 8f2d0895c4fa55f350f2f1
> --- /dev/null
> +++ b/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c
> @@ -0,0 +1,164 @@
> +/** @file
> +  Table Helper
> +
> +Copyright (c) 2017, ARM Limited. All rights reserved.
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD
> License
> +which accompanies this distribution.  The full text of the license may be
> found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +**/
> +
> +#include <Protocol/AcpiTable.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +
> +// Module specific include files.
> +#include <AcpiTableGenerator.h>
> +#include <ConfigurationManagerObject.h>
> +#include <Protocol/ConfigurationManagerProtocol.h>
> +
> +/** The GetCgfMgrInfo function gets the
> CM_STD_OBJ_CONFIGURATION_MANAGER_INFO
> +    object from the Configuration Manager.
> +
> +  @param [in]  CfgMgrProtocol Pointer to the Configuration Manager
> protocol
> +                              interface.
> +  @param [out] CfgMfrInfo     Pointer to the Configuration Manager Info
> +                              object structure.
> +
> +  @retval EFI_SUCCESS           The object is returned.
> +  @retval EFI_INVALID_PARAMETER The Object ID is invalid.
> +  @retval EFI_NOT_FOUND         The requested Object is not found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size.
> +*/
> +EFI_STATUS
> +EFIAPI
> +GetCgfMgrInfo (
> +  IN  CONST EFI_CONFIGURATION_MANAGER_PROTOCOL      * CONST
> CfgMgrProtocol,
> +  OUT       CM_STD_OBJ_CONFIGURATION_MANAGER_INFO  **
> CfgMfrInfo
> +  )
> +{
> +  EFI_STATUS         Status;
> +  CM_OBJ_DESCRIPTOR  CmObjectDesc;
> +
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (CfgMfrInfo != NULL);
> +
> +  *CfgMfrInfo = NULL;
> +  Status = CfgMgrProtocol->GetObject (
> +                             CfgMgrProtocol,
> +                             CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo),
> +                             CM_NULL_TOKEN,
> +                             &CmObjectDesc
> +                             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to Get Configuration Manager Info. Status = %r\n",
> +      Status
> +      ));
> +    return Status;
> +  }
> +
> +  if (CmObjectDesc.Size < sizeof
> (CM_STD_OBJ_CONFIGURATION_MANAGER_INFO)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: EStdObjCfgMgrInfo: Buffer too small, size  = 0x%x\n",
> +      CmObjectDesc.Size
> +      ));
> +    ASSERT (
> +      CmObjectDesc.Size >= sizeof
> (CM_STD_OBJ_CONFIGURATION_MANAGER_INFO)
> +      );
> +    return EFI_BAD_BUFFER_SIZE;
> +  }
> +
> +  *CfgMfrInfo =
> (CM_STD_OBJ_CONFIGURATION_MANAGER_INFO*)CmObjectDesc.Data;
> +  return Status;
> +}
> +
> +/** The AddAcpiHeader function updates the ACPI header structure
> pointed by
> +    the AcpiHeader. It utilizes the ACPI table Generator and the
> Configuration
> +    Manager protocol to obtain any information required for constructing
> the
> +    header.
> +
> +  @param [in]     CfgMgrProtocol Pointer to the Configuration Manager
> +                                 protocol interface.
> +  @param [in]     Generator      Pointer to the ACPI table Generator.
> +  @param [in,out] AcpiHeader     Pointer to the ACPI table header to be
> +                                 updated.
> +  @param [in]     Length         Length of the ACPI table.
> +
> +  @retval EFI_SUCCESS           The ACPI table is updated successfully.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_NOT_FOUND         The required object information is not
> found.
> +  @retval EFI_BAD_BUFFER_SIZE   The size returned by the Configuration
> +                                Manager is less than the Object size for the
> +                                requested object.
> +*/
> +EFI_STATUS
> +EFIAPI
> +AddAcpiHeader (
> +  IN      CONST EFI_CONFIGURATION_MANAGER_PROTOCOL  * CONST
> CfgMgrProtocol,
> +  IN      CONST ACPI_TABLE_GENERATOR                * CONST Generator,
> +  IN OUT  EFI_ACPI_DESCRIPTION_HEADER               * CONST AcpiHeader,
> +  IN      CONST UINT32                                      Length
> +  )
> +{
> +  EFI_STATUS                               Status;
> +  CM_STD_OBJ_CONFIGURATION_MANAGER_INFO  * CfgMfrInfo;
> +
> +  ASSERT (CfgMgrProtocol != NULL);
> +  ASSERT (Generator != NULL);
> +  ASSERT (AcpiHeader != NULL);
> +  ASSERT (Length >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
> +
> +  if ((CfgMgrProtocol == NULL) ||
> +      (Generator == NULL) ||
> +      (AcpiHeader == NULL) ||
> +      (Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER))
> +    ) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = GetCgfMgrInfo (CfgMgrProtocol, &CfgMfrInfo);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "ERROR: Failed to get Configuration Manager info. Status = %r\n",
> +      Status
> +      ));
> +    goto error_handler;
> +  }
> +
> +  // UINT32  Signature
> +  AcpiHeader->Signature = Generator->AcpiTableSignature;
> +  // UINT32  Length
> +  AcpiHeader->Length = Length;
> +  // UINT8   Revision
> +  AcpiHeader->Revision = Generator->AcpiTableRevision;
> +  // UINT8   Checksum
> +  AcpiHeader->Checksum = 0;
> +
> +  // UINT8   OemId[6]
> +  CopyMem (AcpiHeader->OemId, CfgMfrInfo->OemId, sizeof (AcpiHeader-
> >OemId));
> +
> +  // UINT64  OemTableId
> +  AcpiHeader->OemTableId = Generator->CreatorId;
> +  AcpiHeader->OemTableId <<= 32;
> +  AcpiHeader->OemTableId |= Generator->AcpiTableSignature;
> +
> +  // UINT32  OemRevision
> +  AcpiHeader->OemRevision = CfgMfrInfo->Revision;
> +
> +  // UINT32  CreatorId
> +  AcpiHeader->CreatorId = Generator->CreatorId;
> +  // UINT32  CreatorRevision
> +  AcpiHeader->CreatorRevision = Generator->CreatorRevision;
> +
> +error_handler:
> +  return Status;
> +}
> diff --git
> a/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf
> b/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..5faadd198f053d3f628
> 1019aff97466932917b8d
> --- /dev/null
> +++
> b/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf
> @@ -0,0 +1,35 @@
> +## @file
> +#
> +#  Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the
> BSD License
> +#  which accompanies this distribution.  The full text of the license may be
> found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
> BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  INF_VERSION    = 0x00010019
> +  BASE_NAME      = DynamicTableHelperLib
> +  FILE_GUID      = E315C738-3A39-4D0D-A0AF-8EDFA770AB39
> +  VERSION_STRING = 1.0
> +  MODULE_TYPE    = DXE_DRIVER
> +  LIBRARY_CLASS  = TableHelperLib
> +
> +[Sources]
> +  TableHelper.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +  DynamicTablesPkg/DynamicTablesPkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +
> +[Protocols]
> +
> +[Guids]
> +
> --
> 'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'
> 



  reply	other threads:[~2018-03-19 16:10 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-19 15:18 [staging/dynamictables PATCH 0/2] Dynamic Tables Framework core Sami Mujawar
2018-03-19 15:18 ` [staging/dynamictables PATCH 1/2] MdePkg: SMMUv3 updates for IORT table definitions Sami Mujawar
2018-03-19 15:21   ` Ard Biesheuvel
2018-03-19 15:27     ` Sami Mujawar
2018-03-19 16:16   ` Evan Lloyd
2018-03-19 15:18 ` [staging/dynamictables PATCH 2/2] DynamicTablesPkg: Dynamic Tables Framework Sami Mujawar
2018-03-19 16:16   ` Evan Lloyd [this message]
2018-03-20 22:07 ` [staging/dynamictables PATCH 0/2] Dynamic Tables Framework core Desimone, Nathaniel L
2018-03-21 13:23   ` Evan Lloyd
2018-03-23 23:46     ` Desimone, Nathaniel L
2018-03-21  2:56 ` Leif Lindholm

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=HE1PR0801MB17717C3E7021546A0FE652248BD40@HE1PR0801MB1771.eurprd08.prod.outlook.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox