summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi')
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/AcpiDbg2LibArm.inf43
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/Dbg2Generator.c577
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/AcpiFadtLibArm.inf36
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/FadtGenerator.c683
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/AcpiGtdtLibArm.inf36
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c780
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf37
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c2229
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h44
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/AcpiMadtLibArm.inf36
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c830
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/AcpiMcfgLibArm.inf36
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/McfgGenerator.c364
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/AcpiPpttLibArm.inf30
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c1540
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.h189
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibArm.inf36
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/RawGenerator.c144
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibArm.inf37
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/SpcrGenerator.c477
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/AcpiSratLibArm.inf29
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/SratGenerator.c835
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c708
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.h51
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf34
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Template.asl81
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortGenerator.c371
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortLibArm.inf33
28 files changed, 10326 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/AcpiDbg2LibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/AcpiDbg2LibArm.inf
new file mode 100644
index 00000000..d0c863e6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/AcpiDbg2LibArm.inf
@@ -0,0 +1,43 @@
+## @file
+# DBG2 Table Generator
+#
+# Copyright (c) 2017 - 2020, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[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
+ PL011UartLib
+ SsdtSerialPortFixupLib
+
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
+
+[Protocols]
+
+[Guids]
+
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/Dbg2Generator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/Dbg2Generator.c
new file mode 100644
index 00000000..7b4e9f4a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiDbg2LibArm/Dbg2Generator.c
@@ -0,0 +1,577 @@
+/** @file
+ DBG2 Table Generator
+
+ Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @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/MemoryAllocationLib.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/SsdtSerialPortFixupLib.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 0 in the Debug port information list.
+*/
+#define INDEX_DBG_PORT0 0
+
+/** A string representing the name of the debug port 0.
+*/
+#define NAME_STR_DBG_PORT0 "COM0"
+
+/** An UID representing the debug port 0.
+*/
+#define UID_DBG_PORT0 0
+
+/** The length of the namespace string.
+*/
+#define DBG2_NAMESPACESTRING_FIELD_SIZE sizeof (NAME_STR_DBG_PORT0)
+
+/** 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] 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( \
+ SubType, \
+ UartBase, \
+ UartAddrLen, \
+ UartNameStr \
+ ) { \
+ { \
+ /* UINT8 Revision */ \
+ EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION, \
+ /* UINT16 Length */ \
+ sizeof (DBG2_DEBUG_DEVICE_INFORMATION), \
+ /* UINT8 NumberofGenericAddressRegisters */ \
+ DBG2_NUMBER_OF_GENERIC_ADDRESS_REGISTERS, \
+ /* 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 (
+ 0, // {Template}: Serial Port Subtype
+ 0, // {Template}: Serial Port Base Address
+ PL011_UART_LENGTH,
+ NAME_STR_DBG_PORT0
+ )
+ }
+};
+
+#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/SBSA 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
+ );
+
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/** Free any resources allocated for constructing the tables.
+
+ @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 an array of pointers
+ to ACPI Table(s).
+ @param [in] TableCount Number of ACPI table(s).
+
+ @retval EFI_SUCCESS The resources were freed successfully.
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FreeDbg2TableEx (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,
+ IN CONST UINTN TableCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((Table == NULL) ||
+ (*Table == NULL) ||
+ (TableCount != 2)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: DBG2: Invalid Table Pointer\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TableList = *Table;
+
+ if ((TableList[1] == NULL) ||
+ (TableList[1]->Signature !=
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: DBG2: Invalid SSDT table pointer.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Only need to free the SSDT table at index 1. The DBG2 table is static.
+ Status = FreeSsdtSerialPortTable (TableList[1]);
+ ASSERT_EFI_ERROR (Status);
+
+ // Free the table list.
+ FreePool (*Table);
+
+ return Status;
+}
+
+/** Construct the DBG2 ACPI table and its associated SSDT 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 FreeXXXXTableResourcesEx function.
+
+ @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 a list of generated ACPI table(s).
+ @param [out] TableCount Number of generated ACPI table(s).
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for
+ the requested object.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+ @retval EFI_UNSUPPORTED Unsupported configuration.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildDbg2TableEx (
+ IN CONST ACPI_TABLE_GENERATOR * This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,
+ OUT UINTN * CONST TableCount
+ )
+{
+ EFI_STATUS Status;
+ CM_ARM_SERIAL_PORT_INFO * SerialPortInfo;
+ UINT32 SerialPortCount;
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (TableCount != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: DBG2: Requested table revision = %d, is not supported."
+ "Supported table revision: Minimum = %d, Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Table = NULL;
+
+ Status = GetEArmObjSerialDebugPortInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &SerialPortInfo,
+ &SerialPortCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: DBG2: Failed to get serial port information. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ if (SerialPortCount == 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: DBG2: Serial port information not found. Status = %r\n",
+ EFI_NOT_FOUND
+ ));
+ return EFI_NOT_FOUND;
+ }
+
+ // Only use the first DBG2 port information.
+ Status = ValidateSerialPortInfo (SerialPortInfo, 1);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: DBG2: Invalid serial port information. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Allocate a table to store pointers to the DBG2 and SSDT tables.
+ TableList = (EFI_ACPI_DESCRIPTION_HEADER**)
+ AllocateZeroPool (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * 2);
+ if (TableList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: DBG2: Failed to allocate memory for Table List," \
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiDbg2,
+ AcpiTableInfo,
+ 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[INDEX_DBG_PORT0].BaseAddressRegister.Address =
+ SerialPortInfo->BaseAddress;
+
+ // Set the access size
+ if (SerialPortInfo->AccessSize >= EFI_ACPI_6_3_QWORD) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: DBG2: Access size must be <= 3 (DWORD). Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ } else if (SerialPortInfo->AccessSize == EFI_ACPI_6_3_UNDEFINED) {
+ // 0 Undefined (legacy reasons)
+ // Default to DWORD access size as the access
+ // size field was introduced at a later date
+ // and some ConfigurationManager implementations
+ // may not be providing this field data
+ AcpiDbg2.Dbg2DeviceInfo[INDEX_DBG_PORT0].BaseAddressRegister.AccessSize =
+ EFI_ACPI_6_3_DWORD;
+ } else {
+ AcpiDbg2.Dbg2DeviceInfo[INDEX_DBG_PORT0].BaseAddressRegister.AccessSize =
+ SerialPortInfo->AccessSize;
+ }
+
+ // Update the serial port subtype
+ AcpiDbg2.Dbg2DeviceInfo[INDEX_DBG_PORT0].Dbg2Device.PortSubtype =
+ SerialPortInfo->PortSubtype;
+
+ 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)) {
+ // 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;
+ }
+ }
+
+ TableList[0] = (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiDbg2;
+
+ // Build a SSDT table describing the serial port.
+ Status = BuildSsdtSerialPortTable (
+ AcpiTableInfo,
+ SerialPortInfo,
+ NAME_STR_DBG_PORT0,
+ UID_DBG_PORT0,
+ &TableList[1]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: DBG2: Failed to build associated SSDT table. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ *TableCount = 2;
+ *Table = TableList;
+
+ return Status;
+
+error_handler:
+ if (TableList != NULL) {
+ FreePool (TableList);
+ }
+
+ 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 (EStdAcpiTableIdDbg2),
+ // Generator Description
+ L"ACPI.STD.DBG2.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_DEBUG_PORT_2_TABLE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_DBG2_DEBUG_DEVICE_INFORMATION_STRUCT_REVISION,
+ // Minimum supported 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. Use the extended version instead.
+ NULL,
+ // Free table function. Use the extended version instead.
+ NULL,
+ // Extended Build table function.
+ BuildDbg2TableEx,
+ // Extended free function.
+ FreeDbg2TableEx
+};
+
+/** 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&Dbg2Generator);
+ DEBUG ((DEBUG_INFO, "DBG2: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/AcpiFadtLibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/AcpiFadtLibArm.inf
new file mode 100644
index 00000000..deaf7d20
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/AcpiFadtLibArm.inf
@@ -0,0 +1,36 @@
+## @file
+# FADT Table Generator
+#
+# Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[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/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/FadtGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/FadtGenerator.c
new file mode 100644
index 00000000..27b0257d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiFadtLibArm/FadtGenerator.c
@@ -0,0 +1,683 @@
+/** @file
+ FADT Table Generator
+
+ Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.3 Specification, January 2019
+
+**/
+
+#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_3_HW_REDUCED_ACPI | \
+ EFI_ACPI_6_3_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_3_WBINVD BIT0
+ EFI_ACPI_6_3_PWR_BUTTON BIT4
+ EFI_ACPI_6_3_SLP_BUTTON BIT5
+ EFI_ACPI_6_3_FIX_RTC BIT6
+ EFI_ACPI_6_3_DCK_CAP BIT9
+ EFI_ACPI_6_3_RESET_REG_SUP BIT10
+ EFI_ACPI_6_3_SEALED_CASE BIT11
+ EFI_ACPI_6_3_HEADLESS BIT12
+ EFI_ACPI_6_3_USE_PLATFORM_CLOCK BIT15
+ EFI_ACPI_6_3_FORCE_APIC_CLUSTER_MODEL BIT18
+ EFI_ACPI_6_3_FORCE_APIC_PHYSICAL_DESTINATION_MODE BIT19
+ EFI_ACPI_6_3_HW_REDUCED_ACPI BIT20
+ EFI_ACPI_6_3_LOW_POWER_S0_IDLE_CAPABLE BIT21
+*/
+#define VALID_HARDWARE_REDUCED_FLAG_MASK ( \
+ EFI_ACPI_6_3_WBINVD | \
+ EFI_ACPI_6_3_PWR_BUTTON | \
+ EFI_ACPI_6_3_SLP_BUTTON | \
+ EFI_ACPI_6_3_FIX_RTC | \
+ EFI_ACPI_6_3_DCK_CAP | \
+ EFI_ACPI_6_3_RESET_REG_SUP | \
+ EFI_ACPI_6_3_SEALED_CASE | \
+ EFI_ACPI_6_3_HEADLESS | \
+ EFI_ACPI_6_3_USE_PLATFORM_CLOCK | \
+ EFI_ACPI_6_3_FORCE_APIC_CLUSTER_MODEL | \
+ EFI_ACPI_6_3_FORCE_APIC_PHYSICAL_DESTINATION_MODE | \
+ EFI_ACPI_6_3_HW_REDUCED_ACPI | \
+ EFI_ACPI_6_3_LOW_POWER_S0_IDLE_CAPABLE)
+
+#pragma pack(1)
+
+/** The AcpiFadt is a template EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE
+ structure used for generating the FADT Table.
+ Note: fields marked with "{Template}" will be updated dynamically.
+*/
+STATIC
+EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE AcpiFadt = {
+ ACPI_HEADER (
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE,
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_REVISION
+ ),
+ // UINT32 FirmwareCtrl
+ 0,
+ // UINT32 Dsdt
+ 0,
+ // UINT8 Reserved0
+ EFI_ACPI_RESERVED_BYTE,
+ // UINT8 PreferredPmProfile
+ EFI_ACPI_6_3_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_3_GENERIC_ADDRESS_STRUCTURE ResetReg
+ NULL_GAS,
+ // UINT8 ResetValue
+ 0,
+ // UINT16 ArmBootArch
+ EFI_ACPI_6_3_ARM_PSCI_COMPLIANT, // {Template}: ARM Boot Architecture Flags
+ // UINT8 MinorRevision
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION,
+ // UINT64 XFirmwareCtrl
+ 0,
+ // UINT64 XDsdt
+ 0,
+ // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1aEvtBlk
+ NULL_GAS,
+ // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1bEvtBlk
+ NULL_GAS,
+ // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1aCntBlk
+ NULL_GAS,
+ // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm1bCntBlk
+ NULL_GAS,
+ // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPm2CntBlk
+ NULL_GAS,
+ // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XPmTmrBlk
+ NULL_GAS,
+ // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XGpe0Blk
+ NULL_GAS,
+ // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE XGpe1Blk
+ NULL_GAS,
+ // EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE SleepControlReg
+ NULL_GAS,
+ // EFI_ACPI_6_3_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 EDKII_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 EDKII_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 EDKII_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 EDKII_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 EDKII_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);
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: FADT: Requested table revision = %d, is not supported."
+ "Supported table revision: Minimum = %d, Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Table = NULL;
+
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiFadt,
+ AcpiTableInfo,
+ sizeof (EFI_ACPI_6_3_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 (EStdAcpiTableIdFadt),
+ // Generator Description
+ L"ACPI.STD.FADT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_REVISION,
+ // Minimum supported 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,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&FadtGenerator);
+ DEBUG ((DEBUG_INFO, "FADT: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/AcpiGtdtLibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/AcpiGtdtLibArm.inf
new file mode 100644
index 00000000..ef449603
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/AcpiGtdtLibArm.inf
@@ -0,0 +1,36 @@
+## @file
+# GTDT Table Generator
+#
+# Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[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/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
new file mode 100644
index 00000000..27dccab5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiGtdtLibArm/GtdtGenerator.c
@@ -0,0 +1,780 @@
+/** @file
+ GTDT Table Generator
+
+ Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.3 Specification - January 2019
+
+**/
+
+#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.
+ @param [in] AcpiTableRevision Acpi Revision targeted by the platform.
+
+ @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 EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,
+ IN CONST UINT32 PlatformTimerCount,
+ IN CONST UINT32 AcpiTableRevision
+)
+{
+ 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_3_GENERIC_TIMER_DESCRIPTION_TABLE);
+
+ if (AcpiTableRevision > EFI_ACPI_6_2_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION) {
+ Gtdt->VirtualPL2TimerGSIV = GenericTimerInfo->VirtualPL2TimerGSIV;
+ Gtdt->VirtualPL2TimerFlags = GenericTimerInfo->VirtualPL2TimerFlags;
+ }
+
+ return Status;
+}
+
+/** 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_3_GENERIC_TIMER_DESCRIPTION_TABLE * CONST Gtdt,
+ IN CONST UINT32 WatchdogOffset,
+ IN CONST CM_ARM_GENERIC_WATCHDOG_INFO * WatchdogInfoList,
+ IN UINT32 WatchdogCount
+ )
+{
+ EFI_ACPI_6_3_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE * Watchdog;
+
+ ASSERT (Gtdt != NULL);
+ ASSERT (WatchdogInfoList != NULL);
+
+ Watchdog = (EFI_ACPI_6_3_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_3_GTDT_SBSA_GENERIC_WATCHDOG;
+ Watchdog->Length =
+ sizeof (EFI_ACPI_6_3_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
+}
+
+/**
+ Function to test if two Generic Timer Block Frame Info structures have the
+ same frame number.
+
+ @param [in] Frame1 Pointer to the first GT Block Frame Info
+ structure.
+ @param [in] Frame2 Pointer to the second GT Block Frame Info
+ structure.
+ @param [in] Index1 Index of Frame1 in the shared GT Block Frame
+ Information List.
+ @param [in] Index2 Index of Frame2 in the shared GT Block Frame
+ Information List.
+
+ @retval TRUE Frame1 and Frame2 have the same frame number.
+ @return FALSE Frame1 and Frame2 have different frame numbers.
+
+**/
+BOOLEAN
+EFIAPI
+IsGtFrameNumberEqual (
+ IN CONST VOID * Frame1,
+ IN CONST VOID * Frame2,
+ IN UINTN Index1,
+ IN UINTN Index2
+ )
+{
+ UINT8 FrameNumber1;
+ UINT8 FrameNumber2;
+
+ ASSERT ((Frame1 != NULL) && (Frame2 != NULL));
+
+ FrameNumber1 = ((CM_ARM_GTBLOCK_TIMER_FRAME_INFO*)Frame1)->FrameNumber;
+ FrameNumber2 = ((CM_ARM_GTBLOCK_TIMER_FRAME_INFO*)Frame2)->FrameNumber;
+
+ if (FrameNumber1 == FrameNumber2) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: GT Block Frame Info Structures %d and %d have the same " \
+ "frame number: 0x%x.\n",
+ Index1,
+ Index2,
+ FrameNumber1
+ ));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/** 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_3_GTDT_GT_BLOCK_TIMER_STRUCTURE * GtBlockFrame,
+ IN CONST CM_ARM_GTBLOCK_TIMER_FRAME_INFO * GTBlockTimerFrameList,
+ IN UINT32 GTBlockFrameCount
+)
+{
+ BOOLEAN IsFrameNumberDuplicated;
+
+ ASSERT (GtBlockFrame != NULL);
+ ASSERT (GTBlockTimerFrameList != NULL);
+
+ IsFrameNumberDuplicated = FindDuplicateValue (
+ GTBlockTimerFrameList,
+ GTBlockFrameCount,
+ sizeof (CM_ARM_GTBLOCK_TIMER_FRAME_INFO),
+ IsGtFrameNumberEqual
+ );
+ // Duplicate entry was found so timer frame numbers provided are invalid
+ if (IsFrameNumberDuplicated) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ while (GTBlockFrameCount-- != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "GTDT: GtBlockFrame = 0x%p\n",
+ GtBlockFrame
+ ));
+
+ if (GTBlockTimerFrameList->FrameNumber >= 8) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Frame number %d is not in the range 0-7\n",
+ GTBlockTimerFrameList->FrameNumber
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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 EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN EFI_ACPI_6_3_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_3_GTDT_GT_BLOCK_STRUCTURE * GTBlock;
+ EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE * GtBlockFrame;
+ CM_ARM_GTBLOCK_TIMER_FRAME_INFO * GTBlockTimerFrameList;
+ UINT32 GTBlockTimerFrameCount;
+ UINTN Length;
+
+ ASSERT (Gtdt != NULL);
+ ASSERT (GTBlockInfo != NULL);
+
+ GTBlock = (EFI_ACPI_6_3_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;
+ }
+
+ Length = sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE) +
+ (sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_TIMER_STRUCTURE) *
+ GTBlockInfo->GTBlockTimerFrameCount);
+
+ // Check that the length of the GT block does not
+ // exceed MAX_UINT16
+ if (Length > MAX_UINT16) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Too many GT Frames. Count = %d. " \
+ "Maximum supported GT Block size exceeded. " \
+ "Status = %r\n",
+ GTBlockInfo->GTBlockTimerFrameCount,
+ Status
+ ));
+ return Status;
+ }
+
+ GTBlock->Type = EFI_ACPI_6_3_GTDT_GT_BLOCK;
+ GTBlock->Length = (UINT16)Length;
+ GTBlock->Reserved = EFI_ACPI_RESERVED_BYTE;
+ GTBlock->CntCtlBase = GTBlockInfo->GTBlockPhysicalAddress;
+ GTBlock->GTBlockTimerCount = GTBlockInfo->GTBlockTimerFrameCount;
+ GTBlock->GTBlockTimerOffset =
+ sizeof (EFI_ACPI_6_3_GTDT_GT_BLOCK_STRUCTURE);
+
+ GtBlockFrame = (EFI_ACPI_6_3_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_3_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 EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TableSize;
+ UINT32 PlatformTimerCount;
+ UINT32 WatchdogCount;
+ UINT32 BlockTimerCount;
+ CM_ARM_GENERIC_WATCHDOG_INFO * WatchdogInfoList;
+ CM_ARM_GTBLOCK_INFO * GTBlockInfo;
+ EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE * Gtdt;
+ UINT32 Idx;
+ UINT32 GTBlockOffset;
+ UINT32 WatchdogOffset;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: GTDT: Requested table revision = %d, is not supported."
+ "Supported table revision: Minimum = %d, Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *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
+ PlatformTimerCount = 0;
+ TableSize = sizeof (EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE);
+ if (BlockTimerCount != 0) {
+ GTBlockOffset = TableSize;
+ PlatformTimerCount += BlockTimerCount;
+ TableSize += (sizeof (EFI_ACPI_6_3_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_3_GTDT_GT_BLOCK_TIMER_STRUCTURE) *
+ GTBlockInfo[Idx].GTBlockTimerFrameCount);
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "GTDT: GTBockOffset = 0x%x, PLATFORM_TIMER_COUNT = %d\n",
+ GTBlockOffset,
+ PlatformTimerCount
+ ));
+ }
+
+ WatchdogOffset = 0;
+ if (WatchdogCount != 0) {
+ WatchdogOffset = TableSize;
+ PlatformTimerCount += WatchdogCount;
+ TableSize += (sizeof (EFI_ACPI_6_3_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_3_GENERIC_TIMER_DESCRIPTION_TABLE*)*Table;
+ DEBUG ((
+ DEBUG_INFO,
+ "GTDT: Gtdt = 0x%p TableSize = 0x%x\n",
+ Gtdt,
+ TableSize
+ ));
+
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ &Gtdt->Header,
+ AcpiTableInfo,
+ 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,
+ AcpiTableInfo->AcpiTableRevision
+ );
+ 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 EDKII_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 (EStdAcpiTableIdGtdt),
+ // Generator Description
+ L"ACPI.STD.GTDT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_6_3_GENERIC_TIMER_DESCRIPTION_TABLE_REVISION,
+ // Minimum ACPI Table Revision supported by this Generator
+ 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,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended 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
+AcpiGtdtLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&GtdtGenerator);
+ DEBUG ((DEBUG_INFO, "GTDT: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf
new file mode 100644
index 00000000..f7fa6e2d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/AcpiIortLibArm.inf
@@ -0,0 +1,37 @@
+## @file
+# IORT Table Generator
+#
+# Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[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
+ IortGenerator.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ DynamicTablesPkg/DynamicTablesPkg.dec
+
+[LibraryClasses]
+ BaseLib
+
+[Pcd]
+
+[Protocols]
+
+[Guids]
+
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
new file mode 100644
index 00000000..3dac52c0
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.c
@@ -0,0 +1,2229 @@
+/** @file
+ IORT Table Generator
+
+ Copyright (c) 2017 - 2020, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - IO Remapping Table, Platform Design Document,
+ Document number: ARM DEN 0049D, Issue D, March 2018
+
+**/
+
+#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
+ - EArmObjIdMappingArray
+ - 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,
+ EArmObjIdMappingArray,
+ 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 +
+ Size of ITS Identifier array
+ */
+ return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) +
+ (Node->ItsIdCount * sizeof (UINT32)));
+}
+
+/** 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
+UINT64
+GetSizeofItsGroupNodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_ITS_GROUP_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT64 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = (UINT32)(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 +
+ Size of ID mapping array +
+ Size of ASCII string + 'padding to 32-bit word aligned'.
+ */
+ return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +
+ (Node->IdMappingCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +
+ ALIGN_VALUE (AsciiStrSize (Node->ObjectName), 4));
+}
+
+/** 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
+UINT64
+GetSizeofNamedComponentNodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_NAMED_COMPONENT_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT64 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = (UINT32)(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 +
+ Size of ID mapping array
+ */
+ return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE) +
+ (Node->IdMappingCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
+}
+
+/** 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
+UINT64
+GetSizeofRootComplexNodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_ROOT_COMPLEX_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT64 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = (UINT32)(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 +
+ Size of ID mapping array +
+ Size of context interrupt array +
+ Size of PMU interrupt array
+ */
+ return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +
+ (Node->IdMappingCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +
+ (Node->ContextInterruptCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +
+ (Node->PmuInterruptCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)));
+}
+
+/** 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
+UINT64
+GetSizeofSmmuV1V2Nodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_SMMUV1_SMMUV2_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT64 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = (UINT32)(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 +
+ Size of ID mapping array
+ */
+ return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE) +
+ (Node->IdMappingCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
+}
+
+/** 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
+UINT64
+GetSizeofSmmuV3Nodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_SMMUV3_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT64 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = (UINT32)(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 +
+ Size of ID mapping array
+ */
+ return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE) +
+ (Node->IdMappingCount *
+ sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
+}
+
+/** 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
+UINT64
+GetSizeofPmcgNodes (
+ IN CONST UINT32 NodeStartOffset,
+ IN CONST CM_ARM_PMCG_NODE * NodeList,
+ IN UINT32 NodeCount,
+ IN OUT IORT_NODE_INDEXER ** CONST NodeIndexer
+ )
+{
+ UINT64 Size;
+
+ ASSERT (NodeList != NULL);
+
+ Size = 0;
+ while (NodeCount-- != 0) {
+ (*NodeIndexer)->Token = NodeList->Token;
+ (*NodeIndexer)->Object = (VOID*)NodeList;
+ (*NodeIndexer)->Offset = (UINT32)(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] This Pointer to the table Generator.
+ @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 EDKII_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;
+
+ ASSERT (IdMapArray != NULL);
+
+ Generator = (ACPI_IORT_GENERATOR*)This;
+
+ // Get the Id Mapping Array
+ Status = GetEArmObjIdMappingArray (
+ 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] This Pointer to the table Generator.
+ @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 EDKII_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;
+ UINT64 NodeLength;
+
+ ASSERT (Iort != NULL);
+
+ ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ NodeLength = GetItsGroupNodeSize (NodeList);
+ if (NodeLength > MAX_UINT16) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: ITS Id Array Node length 0x%lx > MAX_UINT16."
+ " Status = %r\n",
+ NodeLength,
+ Status
+ ));
+ return Status;
+ }
+
+ // Populate the node header
+ ItsGroupNode->Node.Type = EFI_ACPI_IORT_TYPE_ITS_GROUP;
+ ItsGroupNode->Node.Length = (UINT16)NodeLength;
+ 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] This Pointer to the table Generator.
+ @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 EDKII_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;
+ CHAR8 * ObjectName;
+ UINTN ObjectNameLength;
+ UINT64 NodeLength;
+
+ ASSERT (Iort != NULL);
+
+ NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ NodeLength = GetNamedComponentNodeSize (NodeList);
+ if (NodeLength > MAX_UINT16) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Named Component Node length 0x%lx > MAX_UINT16."
+ " Status = %r\n",
+ NodeLength,
+ Status
+ ));
+ return Status;
+ }
+
+ // Populate the node header
+ NcNode->Node.Type = EFI_ACPI_IORT_TYPE_NAMED_COMP;
+ NcNode->Node.Length = (UINT16)NodeLength;
+ NcNode->Node.Revision = 2;
+ NcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
+ NcNode->Node.NumIdMappings = NodeList->IdMappingCount;
+
+ ObjectNameLength = AsciiStrLen (NodeList->ObjectName) + 1;
+ NcNode->Node.IdReference =
+ (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +
+ (ALIGN_VALUE (ObjectNameLength, 4)));
+
+ // 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,
+ ObjectNameLength,
+ 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] This Pointer to the table Generator.
+ @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 EDKII_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;
+ UINT64 NodeLength;
+
+ ASSERT (Iort != NULL);
+
+ RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ NodeLength = GetRootComplexNodeSize (NodeList);
+ if (NodeLength > MAX_UINT16) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Root Complex Node length 0x%lx > MAX_UINT16."
+ " Status = %r\n",
+ NodeLength,
+ Status
+ ));
+ return Status;
+ }
+
+ // Populate the node header
+ RcNode->Node.Type = EFI_ACPI_IORT_TYPE_ROOT_COMPLEX;
+ RcNode->Node.Length = (UINT16)NodeLength;
+ RcNode->Node.Revision = 1;
+ 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;
+ RcNode->MemoryAddressSize = NodeList->MemoryAddressSize;
+ RcNode->Reserved1[0] = EFI_ACPI_RESERVED_BYTE;
+ RcNode->Reserved1[1] = EFI_ACPI_RESERVED_BYTE;
+ RcNode->Reserved1[2] = EFI_ACPI_RESERVED_BYTE;
+
+ 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, out] 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
+AddSmmuInterruptArray (
+ IN CONST EDKII_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] This Pointer to the table Generator.
+ @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 EDKII_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;
+ UINT64 NodeLength;
+
+ ASSERT (Iort != NULL);
+
+ SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ NodeLength = GetSmmuV1V2NodeSize (NodeList);
+ if (NodeLength > MAX_UINT16) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: SMMU V1/V2 Node length 0x%lx > MAX_UINT16. Status = %r\n",
+ NodeLength,
+ Status
+ ));
+ return Status;
+ }
+
+ // Populate the node header
+ SmmuNode->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv1v2;
+ SmmuNode->Node.Length = (UINT16)NodeLength;
+ 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 = AddSmmuInterruptArray (
+ 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 = AddSmmuInterruptArray (
+ 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] This Pointer to the table Generator.
+ @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 EDKII_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;
+ UINT64 NodeLength;
+
+ ASSERT (Iort != NULL);
+
+ SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ NodeLength = GetSmmuV3NodeSize (NodeList);
+ if (NodeLength > MAX_UINT16) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: SMMU V3 Node length 0x%lx > MAX_UINT16. Status = %r\n",
+ NodeLength,
+ Status
+ ));
+ return Status;
+ }
+
+ // Populate the node header
+ SmmuV3Node->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv3;
+ SmmuV3Node->Node.Length = (UINT16)NodeLength;
+ SmmuV3Node->Node.Revision = 2;
+ 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;
+ }
+
+ 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] This Pointer to the table Generator.
+ @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 EDKII_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;
+ UINT64 NodeLength;
+
+ ASSERT (Iort != NULL);
+
+ Generator = (ACPI_IORT_GENERATOR*)This;
+ PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE*)((UINT8*)Iort +
+ NodesStartOffset);
+
+ while (NodeCount-- != 0) {
+ NodeLength = GetPmcgNodeSize (NodeList);
+ if (NodeLength > MAX_UINT16) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: PMCG Node length 0x%lx > MAX_UINT16. Status = %r\n",
+ NodeLength,
+ Status
+ ));
+ return Status;
+ }
+
+ // Populate the node header
+ PmcgNode->Node.Type = EFI_ACPI_IORT_TYPE_PMCG;
+ PmcgNode->Node.Length = (UINT16)NodeLength;
+ PmcgNode->Node.Revision = 1;
+ 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;
+ PmcgNode->Page1Base = NodeList->Page1BaseAddress;
+
+ 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 EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
+ )
+{
+ EFI_STATUS Status;
+
+ UINT64 TableSize;
+ UINT64 NodeSize;
+
+ 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);
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Requested table revision = %d, is not supported."
+ "Supported table revision: Minimum = %d, Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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 = (UINT32)TableSize;
+ // Size of ITS Group node list.
+ NodeSize = GetSizeofItsGroupNodes (
+ ItsGroupOffset,
+ ItsGroupNodeList,
+ ItsGroupNodeCount,
+ &NodeIndexer
+ );
+ if (NodeSize > MAX_UINT32) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Invalid Size of Group Nodes. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ TableSize += NodeSize;
+
+ DEBUG ((
+ DEBUG_INFO,
+ " ItsGroupNodeCount = %d\n" \
+ " ItsGroupOffset = %d\n",
+ ItsGroupNodeCount,
+ ItsGroupOffset
+ ));
+ }
+
+ // Named Component Nodes
+ if (NamedComponentNodeCount > 0) {
+ NamedComponentOffset = (UINT32)TableSize;
+ // Size of Named Component node list.
+ NodeSize = GetSizeofNamedComponentNodes (
+ NamedComponentOffset,
+ NamedComponentNodeList,
+ NamedComponentNodeCount,
+ &NodeIndexer
+ );
+ if (NodeSize > MAX_UINT32) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Invalid Size of Named Component Nodes. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ TableSize += NodeSize;
+
+ DEBUG ((
+ DEBUG_INFO,
+ " NamedComponentNodeCount = %d\n" \
+ " NamedComponentOffset = %d\n",
+ NamedComponentNodeCount,
+ NamedComponentOffset
+ ));
+ }
+
+ // Root Complex Nodes
+ if (RootComplexNodeCount > 0) {
+ RootComplexOffset = (UINT32)TableSize;
+ // Size of Root Complex node list.
+ NodeSize = GetSizeofRootComplexNodes (
+ RootComplexOffset,
+ RootComplexNodeList,
+ RootComplexNodeCount,
+ &NodeIndexer
+ );
+ if (NodeSize > MAX_UINT32) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Invalid Size of Root Complex Nodes. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ TableSize += NodeSize;
+
+ DEBUG ((
+ DEBUG_INFO,
+ " RootComplexNodeCount = %d\n" \
+ " RootComplexOffset = %d\n",
+ RootComplexNodeCount,
+ RootComplexOffset
+ ));
+ }
+
+ // SMMUv1/SMMUv2 Nodes
+ if (SmmuV1V2NodeCount > 0) {
+ SmmuV1V2Offset = (UINT32)TableSize;
+ // Size of SMMUv1/SMMUv2 node list.
+ NodeSize = GetSizeofSmmuV1V2Nodes (
+ SmmuV1V2Offset,
+ SmmuV1V2NodeList,
+ SmmuV1V2NodeCount,
+ &NodeIndexer
+ );
+ if (NodeSize > MAX_UINT32) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Invalid Size of SMMUv1/v2 Nodes. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ TableSize += NodeSize;
+
+ DEBUG ((
+ DEBUG_INFO,
+ " SmmuV1V2NodeCount = %d\n" \
+ " SmmuV1V2Offset = %d\n",
+ SmmuV1V2NodeCount,
+ SmmuV1V2Offset
+ ));
+ }
+
+ // SMMUv3 Nodes
+ if (SmmuV3NodeCount > 0) {
+ SmmuV3Offset = (UINT32)TableSize;
+ // Size of SMMUv3 node list.
+ NodeSize = GetSizeofSmmuV3Nodes (
+ SmmuV3Offset,
+ SmmuV3NodeList,
+ SmmuV3NodeCount,
+ &NodeIndexer
+ );
+ if (NodeSize > MAX_UINT32) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Invalid Size of SMMUv3 Nodes. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ TableSize += NodeSize;
+
+ DEBUG ((
+ DEBUG_INFO,
+ " SmmuV3NodeCount = %d\n" \
+ " SmmuV3Offset = %d\n",
+ SmmuV3NodeCount,
+ SmmuV3Offset
+ ));
+ }
+
+ // PMCG Nodes
+ if (PmcgNodeCount > 0) {
+ PmcgOffset = (UINT32)TableSize;
+ // Size of PMCG node list.
+ NodeSize = GetSizeofPmcgNodes (
+ PmcgOffset,
+ PmcgNodeList,
+ PmcgNodeCount,
+ &NodeIndexer
+ );
+ if (NodeSize > MAX_UINT32) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: Invalid Size of PMCG Nodes. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ TableSize += NodeSize;
+
+ DEBUG ((
+ DEBUG_INFO,
+ " PmcgNodeCount = %d\n" \
+ " PmcgOffset = %d\n",
+ PmcgNodeCount,
+ PmcgOffset
+ ));
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: IORT:\n" \
+ " IortNodeCount = %d\n" \
+ " TableSize = 0x%lx\n",
+ IortNodeCount,
+ TableSize
+ ));
+
+ if (TableSize > MAX_UINT32) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: IORT: IORT Table Size 0x%lx > MAX_UINT32," \
+ " Status = %r\n",
+ TableSize,
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // 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%lx\n",
+ Iort,
+ TableSize
+ ));
+
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ &Iort->Header,
+ AcpiTableInfo,
+ (UINT32)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 EDKII_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 (EStdAcpiTableIdIort),
+ // Generator Description
+ L"ACPI.STD.IORT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_IO_REMAPPING_TABLE_REVISION,
+ // Minimum supported 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,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended free resource function is not required.
+ NULL
+ },
+
+ // 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&IortGenerator.Header);
+ DEBUG ((DEBUG_INFO, "Iort: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h
new file mode 100644
index 00000000..7b61f0b8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiIortLibArm/IortGenerator.h
@@ -0,0 +1,44 @@
+/** @file
+
+ Copyright (c) 2018, ARM Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @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/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/AcpiMadtLibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/AcpiMadtLibArm.inf
new file mode 100644
index 00000000..850c3f6b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/AcpiMadtLibArm.inf
@@ -0,0 +1,36 @@
+## @file
+# MADT Table Generator
+#
+# Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[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/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c
new file mode 100644
index 00000000..fa7654a4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c
@@ -0,0 +1,830 @@
+/** @file
+ MADT Table Generator
+
+ Copyright (c) 2017 - 2020, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.3 Specification - January 2019
+
+**/
+
+#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_3_GIC_STRUCTURE structure.
+
+ @param [in] Gicc Pointer to GIC CPU Interface structure.
+ @param [in] GicCInfo Pointer to the GIC CPU Interface Information.
+ @param [in] MadtRev MADT table revision.
+**/
+STATIC
+VOID
+AddGICC (
+ IN EFI_ACPI_6_3_GIC_STRUCTURE * CONST Gicc,
+ IN CONST CM_ARM_GICC_INFO * CONST GicCInfo,
+ IN CONST UINT8 MadtRev
+ )
+{
+ ASSERT (Gicc != NULL);
+ ASSERT (GicCInfo != NULL);
+
+ // UINT8 Type
+ Gicc->Type = EFI_ACPI_6_3_GIC;
+ // UINT8 Length
+ Gicc->Length = sizeof (EFI_ACPI_6_3_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
+ Gicc->Reserved2 = EFI_ACPI_RESERVED_BYTE;
+
+ // UINT16 SpeOverflowInterrupt
+ if (MadtRev > EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) {
+ Gicc->SpeOverflowInterrupt = GicCInfo->SpeOverflowInterrupt;
+ } else {
+ // Setting SpeOverflowInterrupt to 0 ensures backward compatibility with
+ // ACPI 6.2 by also clearing the Reserved2[1] and Reserved2[2] fields
+ // in EFI_ACPI_6_2_GIC_STRUCTURE.
+ Gicc->SpeOverflowInterrupt = 0;
+ }
+}
+
+/**
+ Function to test if two GIC CPU Interface information structures have the
+ same ACPI Processor UID.
+
+ @param [in] GicCInfo1 Pointer to the first GICC info structure.
+ @param [in] GicCInfo2 Pointer to the second GICC info structure.
+ @param [in] Index1 Index of GicCInfo1 in the shared list of GIC
+ CPU Interface Info structures.
+ @param [in] Index2 Index of GicCInfo2 in the shared list of GIC
+ CPU Interface Info structures.
+
+ @retval TRUE GicCInfo1 and GicCInfo2 have the same UID.
+ @retval FALSE GicCInfo1 and GicCInfo2 have different UIDs.
+**/
+BOOLEAN
+EFIAPI
+IsAcpiUidEqual (
+ IN CONST VOID * GicCInfo1,
+ IN CONST VOID * GicCInfo2,
+ IN UINTN Index1,
+ IN UINTN Index2
+ )
+{
+ UINT32 Uid1;
+ UINT32 Uid2;
+
+ ASSERT ((GicCInfo1 != NULL) && (GicCInfo2 != NULL));
+
+ Uid1 = ((CM_ARM_GICC_INFO*)GicCInfo1)->AcpiProcessorUid;
+ Uid2 = ((CM_ARM_GICC_INFO*)GicCInfo2)->AcpiProcessorUid;
+
+ if (Uid1 == Uid2) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: MADT: GICC Info Structures %d and %d have the same ACPI " \
+ "Processor UID: 0x%x.\n",
+ Index1,
+ Index2,
+ Uid1
+ ));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/** Add the GIC CPU Interface Information to the MADT Table.
+
+ This function also checks for duplicate ACPI Processor UIDs.
+
+ @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.
+ @param [in] MadtRev MADT table revision.
+
+ @retval EFI_SUCCESS GIC CPU Interface Information was added
+ successfully.
+ @retval EFI_INVALID_PARAMETER One or more invalid GIC CPU Info values were
+ provided and the generator failed to add the
+ information to the table.
+**/
+STATIC
+EFI_STATUS
+AddGICCList (
+ IN EFI_ACPI_6_3_GIC_STRUCTURE * Gicc,
+ IN CONST CM_ARM_GICC_INFO * GicCInfo,
+ IN UINT32 GicCCount,
+ IN CONST UINT8 MadtRev
+ )
+{
+ BOOLEAN IsAcpiProcUidDuplicated;
+
+ ASSERT (Gicc != NULL);
+ ASSERT (GicCInfo != NULL);
+
+ IsAcpiProcUidDuplicated = FindDuplicateValue (
+ GicCInfo,
+ GicCCount,
+ sizeof (CM_ARM_GICC_INFO),
+ IsAcpiUidEqual
+ );
+ // Duplicate ACPI Processor UID was found so the GICC info provided
+ // is invalid
+ if (IsAcpiProcUidDuplicated) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ while (GicCCount-- != 0) {
+ AddGICC (Gicc++, GicCInfo++, MadtRev);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** 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_3_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_3_GICD;
+ // UINT8 Length
+ Gicd->Length = sizeof (EFI_ACPI_6_3_GIC_DISTRIBUTOR_STRUCTURE);
+ // UINT16 Reserved
+ Gicd->Reserved1 = EFI_ACPI_RESERVED_WORD;
+ // UINT32 Identifier
+ // One, and only one, GIC distributor structure must be present
+ // in the MADT for an ARM based system
+ Gicd->GicId = 0;
+ // 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_3_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_3_GIC_MSI_FRAME;
+ GicMsiFrame->Length = sizeof (EFI_ACPI_6_3_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_3_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] GicRedistributorInfo Pointer to the GIC Redistributor Info.
+**/
+STATIC
+VOID
+AddGICRedistributor (
+ IN EFI_ACPI_6_3_GICR_STRUCTURE * CONST Gicr,
+ IN CONST CM_ARM_GIC_REDIST_INFO * CONST GicRedistributorInfo
+ )
+{
+ ASSERT (Gicr != NULL);
+ ASSERT (GicRedistributorInfo != NULL);
+
+ Gicr->Type = EFI_ACPI_6_3_GICR;
+ Gicr->Length = sizeof (EFI_ACPI_6_3_GICR_STRUCTURE);
+ Gicr->Reserved = EFI_ACPI_RESERVED_WORD;
+ Gicr->DiscoveryRangeBaseAddress =
+ GicRedistributorInfo->DiscoveryRangeBaseAddress;
+ Gicr->DiscoveryRangeLength = GicRedistributorInfo->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_3_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_3_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_3_GIC_ITS;
+ GicIts->Length = sizeof (EFI_ACPI_6_3_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_3_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 EDKII_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_3_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);
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: MADT: Requested table revision = %d, is not supported."
+ "Supported table revision: Minimum = %d, Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *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_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER);
+
+ GicCOffset = TableSize;
+ TableSize += (sizeof (EFI_ACPI_6_3_GIC_STRUCTURE) * GicCCount);
+
+ GicDOffset = TableSize;
+ TableSize += (sizeof (EFI_ACPI_6_3_GIC_DISTRIBUTOR_STRUCTURE) * GicDCount);
+
+ GicMSIOffset = TableSize;
+ TableSize += (sizeof (EFI_ACPI_6_3_GIC_MSI_FRAME_STRUCTURE) * GicMSICount);
+
+ GicRedistOffset = TableSize;
+ TableSize += (sizeof (EFI_ACPI_6_3_GICR_STRUCTURE) * GicRedistCount);
+
+ GicItsOffset = TableSize;
+ TableSize += (sizeof (EFI_ACPI_6_3_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_3_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,
+ AcpiTableInfo,
+ TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: MADT: Failed to add ACPI header. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ Status = AddGICCList (
+ (EFI_ACPI_6_3_GIC_STRUCTURE*)((UINT8*)Madt + GicCOffset),
+ GicCInfo,
+ GicCCount,
+ Madt->Header.Revision
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: MADT: Failed to add GICC structures. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ AddGICD (
+ (EFI_ACPI_6_3_GIC_DISTRIBUTOR_STRUCTURE*)((UINT8*)Madt + GicDOffset),
+ GicDInfo
+ );
+
+ if (GicMSICount != 0) {
+ AddGICMsiFrameInfoList (
+ (EFI_ACPI_6_3_GIC_MSI_FRAME_STRUCTURE*)((UINT8*)Madt + GicMSIOffset),
+ GicMSIInfo,
+ GicMSICount
+ );
+ }
+
+ if (GicRedistCount != 0) {
+ AddGICRedistributorList (
+ (EFI_ACPI_6_3_GICR_STRUCTURE*)((UINT8*)Madt + GicRedistOffset),
+ GicRedistInfo,
+ GicRedistCount
+ );
+ }
+
+ if (GicItsCount != 0) {
+ AddGICItsList (
+ (EFI_ACPI_6_3_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 EDKII_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 (EStdAcpiTableIdMadt),
+ // Generator Description
+ L"ACPI.STD.MADT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,
+ // Minimum supported 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,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended 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
+AcpiMadtLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&MadtGenerator);
+ DEBUG ((DEBUG_INFO, "MADT: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/AcpiMcfgLibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/AcpiMcfgLibArm.inf
new file mode 100644
index 00000000..60cf8f3d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/AcpiMcfgLibArm.inf
@@ -0,0 +1,36 @@
+## @file
+# MCFG Table Generator
+#
+# Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[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/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/McfgGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/McfgGenerator.c
new file mode 100644
index 00000000..9412b423
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMcfgLibArm/McfgGenerator.c
@@ -0,0 +1,364 @@
+/** @file
+ MCFG Table Generator
+
+ Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @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_HEADER
+ 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 EDKII_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);
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: MCFG: Requested table revision = %d, is not supported."
+ "Supported table revision: Minimum = %d, Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *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,
+ AcpiTableInfo,
+ 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 EDKII_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 (EStdAcpiTableIdMcfg),
+ // 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 supported by this Generator
+ EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION,
+ // Minimum supported ACPI Table Revision
+ EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ MCFG_GENERATOR_REVISION,
+ // Build Table function
+ BuildMcfgTable,
+ // Free Resource function
+ FreeMcfgTableResources,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended 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
+AcpiMcfgLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&McfgGenerator);
+ DEBUG ((DEBUG_INFO, "MCFG: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/AcpiPpttLibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/AcpiPpttLibArm.inf
new file mode 100644
index 00000000..8c56efde
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/AcpiPpttLibArm.inf
@@ -0,0 +1,30 @@
+## @file
+# PPTT Table Generator
+#
+# Copyright (c) 2019, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = AcpiPpttLibArm
+ FILE_GUID = FA102D52-5A92-4F95-A097-1D53F9CF5959
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL|DXE_DRIVER
+ CONSTRUCTOR = AcpiPpttLibConstructor
+ DESTRUCTOR = AcpiPpttLibDestructor
+
+[Sources]
+ PpttGenerator.c
+ PpttGenerator.h
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ DynamicTablesPkg/DynamicTablesPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c
new file mode 100644
index 00000000..13c932dd
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.c
@@ -0,0 +1,1540 @@
+/** @file
+ PPTT Table Generator
+
+ Copyright (c) 2019, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.3 Specification, January 2019
+
+ @par Glossary:
+ - Cm or CM - Configuration Manager
+ - Obj or OBJ - Object
+**/
+
+#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 "PpttGenerator.h"
+
+/**
+ ARM standard PPTT Generator
+
+ Requirements:
+ The following Configuration Manager Object(s) are used by this Generator:
+ - EArmObjProcHierarchyInfo (REQUIRED)
+ - EArmObjCacheInfo
+ - EArmObjProcNodeIdInfo
+ - EArmObjCmRef
+ - EArmObjGicCInfo (REQUIRED)
+*/
+
+/**
+ This macro expands to a function that retrieves the Processor Hierarchy
+ information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjProcHierarchyInfo,
+ CM_ARM_PROC_HIERARCHY_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the cache information
+ from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjCacheInfo,
+ CM_ARM_CACHE_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the ID information for
+ Processor Hierarchy Nodes from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjProcNodeIdInfo,
+ CM_ARM_PROC_NODE_ID_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the cross-CM-object-
+ reference information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjCmRef,
+ CM_ARM_OBJ_REF
+ );
+
+/**
+ 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
+ );
+
+/**
+ Returns the size of the PPTT Processor Hierarchy Node (Type 0) given a
+ Processor Hierarchy Info CM object.
+
+ @param [in] Node Pointer to Processor Hierarchy Info CM object which
+ represents the Processor Hierarchy Node to be generated.
+
+ @retval Size of the Processor Hierarchy Node in bytes.
+**/
+STATIC
+UINT32
+GetProcHierarchyNodeSize (
+ IN CONST CM_ARM_PROC_HIERARCHY_INFO * Node
+ )
+{
+ ASSERT (Node != NULL);
+
+ // <size of Processor Hierarchy Node> + <size of Private Resources array>
+ return sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR) +
+ (Node->NoOfPrivateResources * sizeof (UINT32));
+}
+
+/**
+ This macro expands to a function that retrieves the amount of memory required
+ to store the Processor Hierarchy Nodes (Type 0) and updates the Node Indexer.
+*/
+GET_SIZE_OF_PPTT_STRUCTS (
+ ProcHierarchyNodes,
+ GetProcHierarchyNodeSize (NodesToIndex),
+ CM_ARM_PROC_HIERARCHY_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the amount of memory required
+ to store the Cache Type Structures (Type 1) and updates the Node Indexer.
+*/
+GET_SIZE_OF_PPTT_STRUCTS (
+ CacheTypeStructs,
+ sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE),
+ CM_ARM_CACHE_INFO
+ );
+
+/** This macro expands to a function that retrieves the amount of memory
+ required to store the ID Structures (Type 2) and updates the Node Indexer.
+*/
+GET_SIZE_OF_PPTT_STRUCTS (
+ IdStructs,
+ sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID),
+ CM_ARM_PROC_NODE_ID_INFO
+ );
+
+/**
+ Search the Node Indexer and return the indexed PPTT node with the given
+ Token.
+
+ @param [in] NodeIndexer Pointer to the Node Indexer array.
+ @param [in] NodeCount Number of elements in Node Indexer.
+ @param [in] SearchToken Token used for Node Indexer lookup.
+ @param [out] IndexedNodeFound Pointer to the Node Indexer array element
+ with the given Token.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_NOT_FOUND No element with a matching token was
+ found in the Node Indexer array.
+**/
+STATIC
+EFI_STATUS
+GetPpttNodeReferencedByToken (
+ IN PPTT_NODE_INDEXER * NodeIndexer,
+ IN UINT32 NodeCount,
+ IN CONST CM_OBJECT_TOKEN SearchToken,
+ OUT PPTT_NODE_INDEXER ** IndexedNodeFound
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (NodeIndexer != NULL);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "PPTT: Node Indexer: SearchToken = %p\n",
+ SearchToken
+ ));
+
+ while (NodeCount-- != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "PPTT: Node Indexer: NodeIndexer->Token = %p. Offset = %d\n",
+ NodeIndexer->Token,
+ NodeIndexer->Offset
+ ));
+
+ if (NodeIndexer->Token == SearchToken) {
+ *IndexedNodeFound = NodeIndexer;
+ Status = EFI_SUCCESS;
+ DEBUG ((
+ DEBUG_INFO,
+ "PPTT: Node Indexer: Token = %p. Found, Status = %r\n",
+ SearchToken,
+ Status
+ ));
+ return Status;
+ }
+ NodeIndexer++;
+ }
+
+ Status = EFI_NOT_FOUND;
+ DEBUG ((
+ DEBUG_ERROR,
+ "PPTT: Node Indexer: SearchToken = %p. Status = %r\n",
+ SearchToken,
+ Status
+ ));
+
+ return Status;
+}
+
+/**
+ Detect cycles in the processor and cache topology graph represented in
+ the PPTT table.
+
+ @param [in] Generator Pointer to the PPTT Generator.
+
+ @retval EFI_SUCCESS There are no cyclic references in the graph.
+ @retval EFI_INVALID_PARAMETER Processor or cache references form a cycle.
+**/
+STATIC
+EFI_STATUS
+DetectCyclesInTopology (
+ IN CONST ACPI_PPTT_GENERATOR * CONST Generator
+ )
+{
+ EFI_STATUS Status;
+ PPTT_NODE_INDEXER * Iterator;
+ PPTT_NODE_INDEXER * CycleDetector;
+ UINT32 NodesRemaining;
+
+ ASSERT (Generator != NULL);
+
+ Iterator = Generator->NodeIndexer;
+ NodesRemaining = Generator->ProcTopologyStructCount;
+
+ while (NodesRemaining != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: PPTT: Cycle detection for element with index %d\n",
+ Generator->ProcTopologyStructCount - NodesRemaining
+ ));
+
+ CycleDetector = Iterator;
+
+ // Walk the topology tree
+ while (CycleDetector->TopologyParent != NULL) {
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: PPTT: %p -> %p\n",
+ CycleDetector->Token,
+ CycleDetector->TopologyParent->Token
+ ));
+
+ // Check if we have already visited this node
+ if (CycleDetector->CycleDetectionStamp == NodesRemaining) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Cycle in processor and cache topology detected for " \
+ "a chain of references originating from a node with: Token = %p " \
+ "Status = %r\n",
+ Iterator->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ // Stamp the visited node
+ CycleDetector->CycleDetectionStamp = NodesRemaining;
+ CycleDetector = CycleDetector->TopologyParent;
+ } // Continue topology tree walk
+
+ Iterator++;
+ NodesRemaining--;
+ } // Next Node Indexer
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the array of private resources for a given Processor Hierarchy Node.
+
+ @param [in] Generator Pointer to the PPTT Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] PrivResArray Pointer to the array of private resources.
+ @param [in] PrivResCount Number of private resources.
+ @param [in] PrivResArrayToken Reference Token for the CM_ARM_OBJ_REF
+ array describing node's private resources.
+
+ @retval EFI_SUCCESS Array updated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND A private resource was not found.
+**/
+STATIC
+EFI_STATUS
+AddPrivateResources (
+ IN CONST ACPI_PPTT_GENERATOR * CONST Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN UINT32 * PrivResArray,
+ IN UINT32 PrivResCount,
+ IN CONST CM_OBJECT_TOKEN PrivResArrayToken
+ )
+{
+ EFI_STATUS Status;
+ CM_ARM_OBJ_REF * CmObjRefs;
+ UINT32 CmObjRefCount;
+ PPTT_NODE_INDEXER * PpttNodeFound;
+
+ ASSERT (
+ (Generator != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (PrivResArray != NULL) &&
+ (PrivResCount != 0)
+ );
+
+ // Validate input arguments
+ if (PrivResArrayToken == CM_NULL_TOKEN) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The number of private resources is %d while " \
+ "PrivResToken = CM_NULL_TOKEN. Status = %r\n",
+ PrivResCount,
+ Status
+ ));
+ return Status;
+ }
+
+ CmObjRefCount = 0;
+ // Get the CM Object References
+ Status = GetEArmObjCmRef (
+ CfgMgrProtocol,
+ PrivResArrayToken,
+ &CmObjRefs,
+ &CmObjRefCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get CM Object References. " \
+ "PrivResToken = %p. Status = %r\n",
+ PrivResArrayToken,
+ Status
+ ));
+ return Status;
+ }
+
+ if (CmObjRefCount != PrivResCount) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The number of CM Object References retrieved and the " \
+ "number of private resources don't match. CmObjRefCount = %d. " \
+ "PrivResourceCount = %d. PrivResToken = %p. Status = %r\n",
+ CmObjRefCount,
+ PrivResCount,
+ PrivResArrayToken,
+ Status
+ ));
+ return Status;
+ }
+
+ while (PrivResCount-- != 0) {
+ if (CmObjRefs->ReferenceToken == CM_NULL_TOKEN) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: CM_NULL_TOKEN provided as reference token for a " \
+ "private resource. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // The Node indexer has the Processor hierarchy nodes at the begining
+ // followed by the cache structs and Id structs. Therefore we can
+ // skip the Processor hierarchy nodes in the node indexer search.
+ Status = GetPpttNodeReferencedByToken (
+ Generator->CacheStructIndexedList,
+ (Generator->ProcTopologyStructCount -
+ Generator->ProcHierarchyNodeCount),
+ CmObjRefs->ReferenceToken,
+ &PpttNodeFound
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get a private resource with Token = %p from " \
+ "Node Indexer. Status = %r\n",
+ CmObjRefs->ReferenceToken,
+ Status
+ ));
+ return Status;
+ }
+
+ // Update the offset of the private resources in the Processor
+ // Hierarchy Node structure
+ *(PrivResArray++) = PpttNodeFound->Offset;
+ CmObjRefs++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Function to test if two indexed Processor Hierarchy Info objects map to the
+ same GIC CPU Interface Info object.
+
+ This is a callback function that can be invoked by FindDuplicateValue ().
+
+ @param [in] Object1 Pointer to the first indexed Processor Hierarchy
+ Info object.
+ @param [in] Object2 Pointer to the second indexed Processor Hierarchy
+ Info object.
+ @param [in] Index1 Index of Object1 to be displayed for debugging
+ purposes.
+ @param [in] Index2 Index of Object2 to be displayed for debugging
+ purposes.
+
+ @retval TRUE Object1 and Object2 have the same GicCToken.
+ @retval FALSE Object1 and Object2 have different GicCTokens.
+**/
+BOOLEAN
+EFIAPI
+IsGicCTokenEqual (
+ IN CONST VOID * Object1,
+ IN CONST VOID * Object2,
+ IN UINTN Index1,
+ IN UINTN Index2
+ )
+{
+ PPTT_NODE_INDEXER * IndexedObject1;
+ PPTT_NODE_INDEXER * IndexedObject2;
+ CM_ARM_PROC_HIERARCHY_INFO * ProcNode1;
+ CM_ARM_PROC_HIERARCHY_INFO * ProcNode2;
+
+ ASSERT (
+ (Object1 != NULL) &&
+ (Object2 != NULL)
+ );
+
+ IndexedObject1 = (PPTT_NODE_INDEXER*)Object1;
+ IndexedObject2 = (PPTT_NODE_INDEXER*)Object2;
+ ProcNode1 = (CM_ARM_PROC_HIERARCHY_INFO*)IndexedObject1->Object;
+ ProcNode2 = (CM_ARM_PROC_HIERARCHY_INFO*)IndexedObject2->Object;
+
+ if (IS_ACPI_PROC_ID_VALID (ProcNode1) &&
+ IS_ACPI_PROC_ID_VALID (ProcNode2) &&
+ (ProcNode1->GicCToken != CM_NULL_TOKEN) &&
+ (ProcNode2->GicCToken != CM_NULL_TOKEN) &&
+ (ProcNode1->GicCToken == ProcNode2->GicCToken)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Two Processor Hierarchy Info objects (%d and %d) map to " \
+ "the same GICC Info object. ACPI Processor IDs are not unique. " \
+ "GicCToken = %p.\n",
+ Index1,
+ IndexedObject1->Token,
+ Index2,
+ ProcNode1->GicCToken
+ ));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Update the Processor Hierarchy Node (Type 0) information.
+
+ This function populates the Processor Hierarchy Nodes with information from
+ the Configuration Manager and adds this information to the PPTT table.
+
+ @param [in] Generator Pointer to the PPTT Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Pptt Pointer to PPTT table structure.
+ @param [in] NodesStartOffset Offset from the start of PPTT table to the
+ start of Processor Hierarchy Nodes.
+
+ @retval EFI_SUCCESS Node updated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddProcHierarchyNodes (
+ IN CONST ACPI_PPTT_GENERATOR * CONST Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,
+ IN CONST UINT32 NodesStartOffset
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR * ProcStruct;
+ UINT32 * PrivateResources;
+ BOOLEAN IsGicCTokenDuplicated;
+
+ CM_ARM_GICC_INFO * GicCInfoList;
+ UINT32 GicCInfoCount;
+ UINT32 UniqueGicCRefCount;
+
+ PPTT_NODE_INDEXER * PpttNodeFound;
+ CM_ARM_PROC_HIERARCHY_INFO * ProcInfoNode;
+
+ PPTT_NODE_INDEXER * ProcNodeIterator;
+ UINT32 NodeCount;
+ UINT32 Length;
+
+ ASSERT (
+ (Generator != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (Pptt != NULL)
+ );
+
+ ProcStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR*)((UINT8*)Pptt +
+ NodesStartOffset);
+
+ ProcNodeIterator = Generator->ProcHierarchyNodeIndexedList;
+ NodeCount = Generator->ProcHierarchyNodeCount;
+
+ // Check if every GICC Object is referenced by onlu one Proc Node
+ IsGicCTokenDuplicated = FindDuplicateValue (
+ ProcNodeIterator,
+ NodeCount,
+ sizeof (PPTT_NODE_INDEXER),
+ IsGicCTokenEqual
+ );
+ // Duplicate GIC CPU Interface Token was found so two PPTT Processor Hierarchy
+ // Nodes map to the same MADT GICC structure
+ if (IsGicCTokenDuplicated) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UniqueGicCRefCount = 0;
+
+ while (NodeCount-- != 0) {
+ ProcInfoNode = (CM_ARM_PROC_HIERARCHY_INFO*)ProcNodeIterator->Object;
+
+ // Check if the private resource count is within the size limit
+ // imposed on the Processor Hierarchy node by the specification.
+ // Note: The length field is 8 bit wide while the number of private
+ // resource field is 32 bit wide.
+ Length = GetProcHierarchyNodeSize (ProcInfoNode);
+ if (Length > MAX_UINT8) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Too many private resources. Count = %d. " \
+ "Maximum supported Processor Node size exceeded. " \
+ "Token = %p. Status = %r\n",
+ ProcInfoNode->NoOfPrivateResources,
+ ProcInfoNode->ParentToken,
+ Status
+ ));
+ return Status;
+ }
+
+ // Populate the node header
+ ProcStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_PROCESSOR;
+ ProcStruct->Length = (UINT8)Length;
+ ProcStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
+ ProcStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
+
+ // Populate the flags
+ ProcStruct->Flags.PhysicalPackage = ProcInfoNode->Flags & BIT0;
+ ProcStruct->Flags.AcpiProcessorIdValid = (ProcInfoNode->Flags & BIT1) >> 1;
+ ProcStruct->Flags.ProcessorIsAThread = (ProcInfoNode->Flags & BIT2) >> 2;
+ ProcStruct->Flags.NodeIsALeaf = (ProcInfoNode->Flags & BIT3) >> 3;
+ ProcStruct->Flags.IdenticalImplementation =
+ (ProcInfoNode->Flags & BIT4) >> 4;
+ ProcStruct->Flags.Reserved = 0;
+
+ // Populate the parent reference
+ if (ProcInfoNode->ParentToken == CM_NULL_TOKEN) {
+ ProcStruct->Parent = 0;
+ } else {
+ Status = GetPpttNodeReferencedByToken (
+ Generator->ProcHierarchyNodeIndexedList,
+ Generator->ProcHierarchyNodeCount,
+ ProcInfoNode->ParentToken,
+ &PpttNodeFound
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get parent processor hierarchy node " \
+ "reference. Token = %p, Status = %r\n",
+ ProcInfoNode->ParentToken,
+ ProcInfoNode->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ // Test if the reference is to a 'leaf' node
+ if (IS_PROC_NODE_LEAF (
+ ((CM_ARM_PROC_HIERARCHY_INFO*)PpttNodeFound->Object))) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Reference to a leaf Processor Hierarchy Node. " \
+ "ParentToken = %p. ChildToken = %p. Status = %r\n",
+ ProcInfoNode->ParentToken,
+ ProcInfoNode->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ // Update Proc Structure with the offset of the parent node
+ ProcStruct->Parent = PpttNodeFound->Offset;
+
+ // Store the reference for the parent node in the Node Indexer
+ // so that this can be used later for cycle detection
+ ProcNodeIterator->TopologyParent = PpttNodeFound;
+ }
+
+ // Populate ACPI Processor ID
+ if (!IS_ACPI_PROC_ID_VALID (ProcInfoNode)) {
+ // Default invalid ACPI Processor ID to 0
+ ProcStruct->AcpiProcessorId = 0;
+ } else if (ProcInfoNode->GicCToken == CM_NULL_TOKEN) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The 'ACPI Processor ID valid' flag is set but no GICC " \
+ "structure token was provided. GicCToken = %p. RequestorToken = %p. " \
+ "Status = %r\n",
+ ProcInfoNode->GicCToken,
+ ProcInfoNode->Token,
+ Status
+ ));
+ return Status;
+ } else {
+ Status = GetEArmObjGicCInfo (
+ CfgMgrProtocol,
+ ProcInfoNode->GicCToken,
+ &GicCInfoList,
+ &GicCInfoCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get GICC structure. ACPI Processor ID " \
+ "can't be populated. GicCToken = %p. RequestorToken = %p. " \
+ "Status = %r\n",
+ ProcInfoNode->GicCToken,
+ ProcInfoNode->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ if (GicCInfoCount != 1) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to find a unique GICC structure. " \
+ "ACPI Processor ID can't be populated. " \
+ "GICC Structure Count = %d. GicCToken = %p. RequestorToken = %p " \
+ "Status = %r\n",
+ GicCInfoCount,
+ ProcInfoNode->GicCToken,
+ ProcInfoNode->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ // Update the ACPI Processor Id
+ ProcStruct->AcpiProcessorId = GicCInfoList->AcpiProcessorUid;
+
+ // Increment the reference count for the number of
+ // Unique GICC objects that were retrieved.
+ UniqueGicCRefCount++;
+ }
+
+ ProcStruct->NumberOfPrivateResources = ProcInfoNode->NoOfPrivateResources;
+ PrivateResources = (UINT32*)((UINT8*)ProcStruct +
+ sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR));
+
+ if (ProcStruct->NumberOfPrivateResources != 0) {
+ // Populate the private resources array
+ Status = AddPrivateResources (
+ Generator,
+ CfgMgrProtocol,
+ PrivateResources,
+ ProcStruct->NumberOfPrivateResources,
+ ProcInfoNode->PrivateResourcesArrayToken
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to populate the private resources array. " \
+ "Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ // Next Processor Hierarchy Node
+ ProcStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_PROCESSOR*)((UINT8*)ProcStruct +
+ ProcStruct->Length);
+ ProcNodeIterator++;
+ } // Processor Hierarchy Node
+
+ // Knowing the total number of GICC references made and that all GICC Token
+ // references are unique, we can test if no GICC instances have been left out.
+ Status = GetEArmObjGicCInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &GicCInfoList,
+ &GicCInfoCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get GICC Info. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // MADT - PPTT cross validation
+ // This checks that one and only one GICC structure is referenced by a
+ // Processor Hierarchy Node in the PPTT.
+ // Since we have already checked that the GICC objects referenced by the
+ // Proc Nodes are unique, the UniqueGicCRefCount cannot be greater than
+ // the total number of GICC objects in the platform.
+ if (GicCInfoCount > UniqueGicCRefCount) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: %d GICC structure(s) exposed by MADT don't have " \
+ "a corresponding Processor Hierarchy Node. Status = %r\n",
+ GicCInfoCount - UniqueGicCRefCount,
+ Status
+ ));
+ }
+
+ return Status;
+}
+
+/**
+ Update the Cache Type Structure (Type 1) information.
+
+ This function populates the Cache Type Structures with information from
+ the Configuration Manager and adds this information to the PPTT table.
+
+ @param [in] Generator Pointer to the PPTT Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Pptt Pointer to PPTT table structure.
+ @param [in] NodesStartOffset Offset from the start of PPTT table to the
+ start of Cache Type Structures.
+
+ @retval EFI_SUCCESS Structures updated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND A required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddCacheTypeStructures (
+ IN CONST ACPI_PPTT_GENERATOR * CONST Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,
+ IN CONST UINT32 NodesStartOffset
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE * CacheStruct;
+ PPTT_NODE_INDEXER * PpttNodeFound;
+ CM_ARM_CACHE_INFO * CacheInfoNode;
+ PPTT_NODE_INDEXER * CacheNodeIterator;
+ UINT32 NodeCount;
+
+ ASSERT (
+ (Generator != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (Pptt != NULL)
+ );
+
+ CacheStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE*)((UINT8*)Pptt +
+ NodesStartOffset);
+
+ CacheNodeIterator = Generator->CacheStructIndexedList;
+ NodeCount = Generator->CacheStructCount;
+
+ while (NodeCount-- != 0) {
+ CacheInfoNode = (CM_ARM_CACHE_INFO*)CacheNodeIterator->Object;
+
+ // Populate the node header
+ CacheStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_CACHE;
+ CacheStruct->Length = sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE);
+ CacheStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
+ CacheStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
+
+ // "On Arm-based systems, all cache properties must be provided in the
+ // table." (ACPI 6.3, Section 5.2.29.2)
+ CacheStruct->Flags.SizePropertyValid = 1;
+ CacheStruct->Flags.NumberOfSetsValid = 1;
+ CacheStruct->Flags.AssociativityValid = 1;
+ CacheStruct->Flags.AllocationTypeValid = 1;
+ CacheStruct->Flags.CacheTypeValid = 1;
+ CacheStruct->Flags.WritePolicyValid = 1;
+ CacheStruct->Flags.LineSizeValid = 1;
+ CacheStruct->Flags.Reserved = 0;
+
+ // Populate the reference to the next level of cache
+ if (CacheInfoNode->NextLevelOfCacheToken == CM_NULL_TOKEN) {
+ CacheStruct->NextLevelOfCache = 0;
+ } else {
+ Status = GetPpttNodeReferencedByToken (
+ Generator->CacheStructIndexedList,
+ Generator->CacheStructCount,
+ CacheInfoNode->NextLevelOfCacheToken,
+ &PpttNodeFound
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get the reference to the Next Level of " \
+ "Cache. NextLevelOfCacheToken = %p. RequestorToken = %p. " \
+ "Status = %r\n",
+ CacheInfoNode->NextLevelOfCacheToken,
+ CacheInfoNode->Token,
+ Status
+ ));
+ return Status;
+ }
+
+ // Update Cache Structure with the offset for the next level of cache
+ CacheStruct->NextLevelOfCache = PpttNodeFound->Offset;
+
+ // Store the next level of cache information in the Node Indexer
+ // so that this can be used later for cycle detection
+ CacheNodeIterator->TopologyParent = PpttNodeFound;
+ }
+
+ CacheStruct->Size = CacheInfoNode->Size;
+
+ // Validate and populate the 'Number of sets' field
+ if (CacheInfoNode->NumberOfSets > PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum number " \
+ "of sets can be %d. NumberOfSets = %d. Status = %r\n",
+ PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX,
+ CacheInfoNode->NumberOfSets,
+ Status
+ ));
+ return Status;
+ }
+
+ if (CacheInfoNode->NumberOfSets > PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX) {
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \
+ "number of sets can be %d. NumberOfSets = %d\n",
+ PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX,
+ CacheInfoNode->NumberOfSets
+ ));
+ }
+
+ CacheStruct->NumberOfSets = CacheInfoNode->NumberOfSets;
+
+ // Validate Associativity field based on maximum associativity
+ // supported by ACPI Cache type structure.
+ if (CacheInfoNode->Associativity > MAX_UINT8) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The maximum associativity supported by ACPI " \
+ "Cache type structure is %d. Associativity = %d, Status = %r\n",
+ MAX_UINT8,
+ CacheInfoNode->Associativity,
+ Status
+ ));
+ return Status;
+ }
+
+ // Validate the Associativity field based on the architecture specification
+ // The architecture supports much larger associativity values than the
+ // current ACPI specification.
+ // These checks will be needed in the future when the ACPI specification
+ // is extended. Disabling this code for now.
+#if 0
+ if (CacheInfoNode->Associativity > PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: When ARMv8.3-CCIDX is implemented the maximum cache " \
+ "associativity can be %d. Associativity = %d. Status = %r\n",
+ PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX,
+ CacheInfoNode->Associativity,
+ Status
+ ));
+ return Status;
+ }
+
+ if (CacheInfoNode->Associativity > PPTT_ARM_CACHE_ASSOCIATIVITY_MAX) {
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: PPTT: When ARMv8.3-CCIDX is not implemented the maximum " \
+ "cache associativity can be %d. Associativity = %d\n",
+ PPTT_ARM_CACHE_ASSOCIATIVITY_MAX,
+ CacheInfoNode->Associativity
+ ));
+ }
+#endif
+
+ // Note a typecast is needed as the maximum associativity
+ // supported by ACPI Cache type structure is MAX_UINT8.
+ CacheStruct->Associativity = (UINT8)CacheInfoNode->Associativity;
+
+ // Populate cache attributes
+ CacheStruct->Attributes.AllocationType =
+ CacheInfoNode->Attributes & (BIT0 | BIT1);
+ CacheStruct->Attributes.CacheType =
+ (CacheInfoNode->Attributes & (BIT2 | BIT3)) >> 2;
+ CacheStruct->Attributes.WritePolicy =
+ (CacheInfoNode->Attributes & BIT4) >> 4;
+ CacheStruct->Attributes.Reserved = 0;
+
+ // Validate and populate cache line size
+ if ((CacheInfoNode->LineSize < PPTT_ARM_CACHE_LINE_SIZE_MIN) ||
+ (CacheInfoNode->LineSize > PPTT_ARM_CACHE_LINE_SIZE_MAX)) {
+
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The cache line size must be between %d and %d bytes " \
+ "on ARM Platforms. LineSize = %d. Status = %r\n" ,
+ PPTT_ARM_CACHE_LINE_SIZE_MIN,
+ PPTT_ARM_CACHE_LINE_SIZE_MAX,
+ CacheInfoNode->LineSize,
+ Status
+ ));
+ return Status;
+ }
+
+ if ((CacheInfoNode->LineSize & (CacheInfoNode->LineSize - 1)) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: The cache line size is not a power of 2. " \
+ "LineSize = %d. Status = %r\n" ,
+ CacheInfoNode->LineSize,
+ Status
+ ));
+ return Status;
+ }
+
+ CacheStruct->LineSize = CacheInfoNode->LineSize;
+
+ // Next Cache Type Structure
+ CacheStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_CACHE*)((UINT8*)CacheStruct +
+ CacheStruct->Length);
+ CacheNodeIterator++;
+ } // Cache Type Structure
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the ID Type Structure (Type 2) information.
+
+ This function populates the ID Type Structures with information from
+ the Configuration Manager and and adds this information to the PPTT table.
+
+ @param [in] Generator Pointer to the PPTT Generator.
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Pptt Pointer to PPTT table structure.
+ @param [in] NodesStartOffset Offset from the start of PPTT table to the
+ start of ID Type Structures.
+
+ @retval EFI_SUCCESS Structures updated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND A required object was not found.
+**/
+STATIC
+EFI_STATUS
+AddIdTypeStructures (
+ IN CONST ACPI_PPTT_GENERATOR * CONST Generator,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN CONST EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt,
+ IN CONST UINT32 NodesStartOffset
+ )
+{
+ EFI_ACPI_6_3_PPTT_STRUCTURE_ID * IdStruct;
+ CM_ARM_PROC_NODE_ID_INFO * ProcIdInfoNode;
+ PPTT_NODE_INDEXER * IdStructIterator;
+ UINT32 NodeCount;
+
+
+ ASSERT (
+ (Generator != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (Pptt != NULL)
+ );
+
+ IdStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_ID*)((UINT8*)Pptt + NodesStartOffset);
+
+ IdStructIterator = Generator->IdStructIndexedList;
+ NodeCount = Generator->IdStructCount;
+ while (NodeCount-- != 0) {
+ ProcIdInfoNode = (CM_ARM_PROC_NODE_ID_INFO*)IdStructIterator->Object;
+
+ // Populate the node
+ IdStruct->Type = EFI_ACPI_6_3_PPTT_TYPE_ID;
+ IdStruct->Length = sizeof (EFI_ACPI_6_3_PPTT_STRUCTURE_ID);
+ IdStruct->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
+ IdStruct->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
+ IdStruct->VendorId = ProcIdInfoNode->VendorId;
+ IdStruct->Level1Id = ProcIdInfoNode->Level1Id;
+ IdStruct->Level2Id = ProcIdInfoNode->Level2Id;
+ IdStruct->MajorRev = ProcIdInfoNode->MajorRev;
+ IdStruct->MinorRev = ProcIdInfoNode->MinorRev;
+ IdStruct->SpinRev = ProcIdInfoNode->SpinRev;
+
+ // Next ID Type Structure
+ IdStruct = (EFI_ACPI_6_3_PPTT_STRUCTURE_ID*)((UINT8*)IdStruct +
+ IdStruct->Length);
+ IdStructIterator++;
+ } // ID Type Structure
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Construct the PPTT 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 generator to be used.
+ @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
+BuildPpttTable (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TableSize;
+ UINT32 ProcTopologyStructCount;
+ UINT32 ProcHierarchyNodeCount;
+ UINT32 CacheStructCount;
+ UINT32 IdStructCount;
+
+ UINT32 ProcHierarchyNodeOffset;
+ UINT32 CacheStructOffset;
+ UINT32 IdStructOffset;
+
+ CM_ARM_PROC_HIERARCHY_INFO * ProcHierarchyNodeList;
+ CM_ARM_CACHE_INFO * CacheStructList;
+ CM_ARM_PROC_NODE_ID_INFO * IdStructList;
+
+ ACPI_PPTT_GENERATOR * Generator;
+
+ // Pointer to the Node Indexer array
+ PPTT_NODE_INDEXER * NodeIndexer;
+
+ EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER * Pptt;
+
+ ASSERT (
+ (This != NULL) &&
+ (AcpiTableInfo != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (Table != NULL) &&
+ (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&
+ (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)
+ );
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Requested table revision = %d is not supported. "
+ "Supported table revisions: Minimum = %d. Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Generator = (ACPI_PPTT_GENERATOR*)This;
+ *Table = NULL;
+
+ // Get the processor hierarchy info and update the processor topology
+ // structure count with Processor Hierarchy Nodes (Type 0)
+ Status = GetEArmObjProcHierarchyInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &ProcHierarchyNodeList,
+ &ProcHierarchyNodeCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get processor hierarchy info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ ProcTopologyStructCount = ProcHierarchyNodeCount;
+ Generator->ProcHierarchyNodeCount = ProcHierarchyNodeCount;
+
+ // Get the cache info and update the processor topology structure count with
+ // Cache Type Structures (Type 1)
+ Status = GetEArmObjCacheInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &CacheStructList,
+ &CacheStructCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get cache info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ ProcTopologyStructCount += CacheStructCount;
+ Generator->CacheStructCount = CacheStructCount;
+
+ // Get the processor hierarchy node ID info and update the processor topology
+ // structure count with ID Structures (Type 2)
+ Status = GetEArmObjProcNodeIdInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &IdStructList,
+ &IdStructCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to get processor hierarchy node ID info. " \
+ "Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ ProcTopologyStructCount += IdStructCount;
+ Generator->IdStructCount = IdStructCount;
+
+ // Allocate Node Indexer array
+ NodeIndexer = (PPTT_NODE_INDEXER*)AllocateZeroPool (
+ sizeof (PPTT_NODE_INDEXER) *
+ ProcTopologyStructCount
+ );
+ if (NodeIndexer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to allocate memory for Node Indexer. Status = %r\n ",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));
+ Generator->ProcTopologyStructCount = ProcTopologyStructCount;
+ Generator->NodeIndexer = NodeIndexer;
+
+ // Calculate the size of the PPTT table
+ TableSize = sizeof (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER);
+
+ // Include the size of Processor Hierarchy Nodes and index them
+ if (Generator->ProcHierarchyNodeCount != 0) {
+ ProcHierarchyNodeOffset = TableSize;
+ Generator->ProcHierarchyNodeIndexedList = NodeIndexer;
+ TableSize += GetSizeofProcHierarchyNodes (
+ ProcHierarchyNodeOffset,
+ ProcHierarchyNodeList,
+ Generator->ProcHierarchyNodeCount,
+ &NodeIndexer
+ );
+
+ DEBUG ((
+ DEBUG_INFO,
+ " ProcHierarchyNodeCount = %d\n" \
+ " ProcHierarchyNodeOffset = 0x%x\n" \
+ " ProcHierarchyNodeIndexedList = 0x%p\n",
+ Generator->ProcHierarchyNodeCount,
+ ProcHierarchyNodeOffset,
+ Generator->ProcHierarchyNodeIndexedList
+ ));
+
+ }
+
+ // Include the size of Cache Type Structures and index them
+ if (Generator->CacheStructCount != 0) {
+ CacheStructOffset = TableSize;
+ Generator->CacheStructIndexedList = NodeIndexer;
+ TableSize += GetSizeofCacheTypeStructs (
+ CacheStructOffset,
+ CacheStructList,
+ Generator->CacheStructCount,
+ &NodeIndexer
+ );
+ DEBUG ((
+ DEBUG_INFO,
+ " CacheStructCount = %d\n" \
+ " CacheStructOffset = 0x%x\n" \
+ " CacheStructIndexedList = 0x%p\n",
+ Generator->CacheStructCount,
+ CacheStructOffset,
+ Generator->CacheStructIndexedList
+ ));
+ }
+
+ // Include the size of ID Type Structures and index them
+ if (Generator->IdStructCount != 0) {
+ IdStructOffset = TableSize;
+ Generator->IdStructIndexedList = NodeIndexer;
+ TableSize += GetSizeofIdStructs (
+ IdStructOffset,
+ IdStructList,
+ Generator->IdStructCount,
+ &NodeIndexer
+ );
+ DEBUG ((
+ DEBUG_INFO,
+ " IdStructCount = %d\n" \
+ " IdStructOffset = 0x%x\n" \
+ " IdStructIndexedList = 0x%p\n",
+ Generator->IdStructCount,
+ IdStructOffset,
+ Generator->IdStructIndexedList
+ ));
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "INFO: PPTT:\n" \
+ " ProcTopologyStructCount = %d\n" \
+ " TableSize = %d\n",
+ ProcTopologyStructCount,
+ TableSize
+ ));
+
+ // Allocate the Buffer for the PPTT table
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
+ if (*Table == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to allocate memory for PPTT Table. " \
+ "Size = %d. Status = %r\n",
+ TableSize,
+ Status
+ ));
+ goto error_handler;
+ }
+
+ Pptt = (EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_HEADER*)*Table;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "PPTT: Pptt = 0x%p. TableSize = 0x%x\n",
+ Pptt,
+ TableSize
+ ));
+
+ // Add ACPI header
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ &Pptt->Header,
+ AcpiTableInfo,
+ TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to add ACPI header. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Add Processor Hierarchy Nodes (Type 0) to the generated table
+ if (Generator->ProcHierarchyNodeCount != 0) {
+ Status = AddProcHierarchyNodes (
+ Generator,
+ CfgMgrProtocol,
+ Pptt,
+ ProcHierarchyNodeOffset
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to add Processor Hierarchy Nodes. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ // Add Cache Type Structures (Type 1) to the generated table
+ if (Generator->CacheStructCount != 0) {
+ Status = AddCacheTypeStructures (
+ Generator,
+ CfgMgrProtocol,
+ Pptt,
+ CacheStructOffset
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to add Cache Type Structures. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ // Add ID Type Structures (Type 2) to the generated table
+ if (Generator->IdStructCount != 0) {
+ Status = AddIdTypeStructures (
+ Generator,
+ CfgMgrProtocol,
+ Pptt,
+ IdStructOffset
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Failed to add ID Type Structures. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ // Validate CM object cross-references in PPTT
+ Status = DetectCyclesInTopology (Generator);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: PPTT: Invalid processor and cache topology. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ return Status;
+
+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 PPTT
+
+ @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
+FreePpttTableResources (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
+ )
+{
+ ACPI_PPTT_GENERATOR * Generator;
+
+ ASSERT (
+ (This != NULL) &&
+ (AcpiTableInfo != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&
+ (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)
+ );
+
+ Generator = (ACPI_PPTT_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: PPTT: Invalid Table Pointer\n"));
+ ASSERT (
+ (Table != NULL) &&
+ (*Table != NULL)
+ );
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FreePool (*Table);
+ *Table = NULL;
+ return EFI_SUCCESS;
+}
+
+/** The PPTT Table Generator revision.
+*/
+#define PPTT_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the PPTT Table Generator.
+*/
+STATIC
+ACPI_PPTT_GENERATOR PpttGenerator = {
+ // ACPI table generator header
+ {
+ // Generator ID
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdPptt),
+ // Generator Description
+ L"ACPI.STD.PPTT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_STRUCTURE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION,
+ // Minimum supported ACPI Table Revision
+ EFI_ACPI_6_3_PROCESSOR_PROPERTIES_TOPOLOGY_TABLE_REVISION,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ PPTT_GENERATOR_REVISION,
+ // Build Table function
+ BuildPpttTable,
+ // Free Resource function
+ FreePpttTableResources,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended free resource function is not required.
+ NULL
+ },
+
+ // PPTT Generator private data
+
+ // Processor topology node count
+ 0,
+ // Count of Processor Hierarchy Nodes
+ 0,
+ // Count of Cache Structures
+ 0,
+ // Count of Id Structures
+ 0,
+ // Pointer to PPTT 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
+AcpiPpttLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = RegisterAcpiTableGenerator (&PpttGenerator.Header);
+ DEBUG ((DEBUG_INFO, "PPTT: 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
+AcpiPpttLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&PpttGenerator.Header);
+ DEBUG ((DEBUG_INFO, "PPTT: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.h b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.h
new file mode 100644
index 00000000..1e9cf543
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/PpttGenerator.h
@@ -0,0 +1,189 @@
+/** @file
+ Header file for the dynamic PPTT generator
+
+ Copyright (c) 2019, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.3 Specification, January 2019
+ - ARM Architecture Reference Manual ARMv8 (D.a)
+
+ @par Glossary:
+ - Cm or CM - Configuration Manager
+ - Obj or OBJ - Object
+**/
+
+#ifndef PPTT_GENERATOR_H_
+#define PPTT_GENERATOR_H_
+
+#pragma pack(1)
+
+/// Cache parameters allowed by the architecture with
+/// ARMv8.3-CCIDX (Cache extended number of sets)
+/// Derived from CCSIDR_EL1 when ID_AA64MMFR2_EL1.CCIDX==0001
+#define PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX (1 << 24)
+#define PPTT_ARM_CCIDX_CACHE_ASSOCIATIVITY_MAX (1 << 21)
+
+/// Cache parameters allowed by the architecture without
+/// ARMv8.3-CCIDX (Cache extended number of sets)
+/// Derived from CCSIDR_EL1 when ID_AA64MMFR2_EL1.CCIDX==0000
+#define PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX (1 << 15)
+#define PPTT_ARM_CACHE_ASSOCIATIVITY_MAX (1 << 10)
+
+/// Common cache parameters
+/// Derived from CCSIDR_EL1
+/// The LineSize is represented by bits 2:0
+/// (Log2(Number of bytes in cache line)) - 4 is used to represent
+/// the LineSize bits.
+#define PPTT_ARM_CACHE_LINE_SIZE_MAX (1 << 11)
+#define PPTT_ARM_CACHE_LINE_SIZE_MIN (1 << 4)
+
+/// Test if the given Processor Hierarchy Info object has the 'Node is a Leaf'
+/// flag set
+#define IS_PROC_NODE_LEAF(Node) ((Node->Flags & BIT3) != 0)
+
+/// Test if the given Processor Hierarchy Info object has the 'ACPI Processor
+/// ID valid' flag set
+#define IS_ACPI_PROC_ID_VALID(Node) ((Node->Flags & BIT1) != 0)
+
+/**
+ The GET_SIZE_OF_PPTT_STRUCTS macro expands to a function that is used to
+ calculate the total memory requirement for the PPTT structures represented
+ by the given list of Configuration Manager Objects of the same type. This
+ function also indexes the input CM objects so that various other CM objects
+ (possibly of different type) can reference them.
+
+ The size of memory needed for the specified type of PPTT structures is based
+ on the number and type of CM objects provided. The macro assumes that the
+ ACPI object PpttObjName has fixed size.
+
+ The macro expands to a function which has the following prototype:
+
+ STATIC
+ UINT32
+ EFIAPI
+ GetSizeof<PpttObjName> (
+ IN CONST UINT32 StartOffset,
+ IN CONST CmObjectType * Nodes,
+ IN UINT32 NodeCount,
+ IN OUT PPTT_NODE_INDEXER ** CONST NodeIndexer
+ )
+
+ Generated function parameters:
+ @param [in] StartOffset Offset from the start of PPTT to where
+ the PPTT structures will be placed.
+ @param [in] NodesToIndex Pointer to the list of CM objects to be
+ indexed and size-estimated.
+ @param [out] NodeCount Number of CM objects in NodesToIndex.
+ @param [in, out] NodeIndexer Pointer to the list of Node Indexer
+ elements to populate.
+ @retval Size Total memory requirement for the PPTT
+ structures described in NodesToIndex.
+
+ Macro Parameters:
+ @param [in] PpttObjName Name for the type of PPTT structures which
+ size is estimated.
+ @param [in] PpttObjSize Expression to use to calculate the size of
+ of a single instance of the PPTT structure
+ which corresponds to the CM object being
+ indexed.
+ @param [in] CmObjectType Data type of the CM nodes in NodesToIndex.
+**/
+#define GET_SIZE_OF_PPTT_STRUCTS( \
+ PpttObjName, \
+ PpttObjSize, \
+ CmObjectType \
+) \
+STATIC \
+UINT32 \
+GetSizeof##PpttObjName ( \
+ IN CONST UINT32 StartOffset, \
+ IN CONST CmObjectType * NodesToIndex, \
+ IN UINT32 NodeCount, \
+ IN OUT PPTT_NODE_INDEXER ** CONST NodeIndexer \
+ ) \
+{ \
+ UINT32 Size; \
+ \
+ ASSERT ( \
+ (NodesToIndex != NULL) && \
+ (NodeIndexer != NULL) \
+ ); \
+ \
+ Size = 0; \
+ while (NodeCount-- != 0) { \
+ (*NodeIndexer)->Token = NodesToIndex->Token; \
+ (*NodeIndexer)->Object = (VOID*)NodesToIndex; \
+ (*NodeIndexer)->Offset = Size + StartOffset; \
+ (*NodeIndexer)->CycleDetectionStamp = 0; \
+ (*NodeIndexer)->TopologyParent = NULL; \
+ DEBUG (( \
+ DEBUG_INFO, \
+ "PPTT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n", \
+ *NodeIndexer, \
+ (*NodeIndexer)->Token, \
+ (*NodeIndexer)->Object, \
+ (*NodeIndexer)->Offset \
+ )); \
+ \
+ Size += PpttObjSize; \
+ (*NodeIndexer)++; \
+ NodesToIndex++; \
+ } \
+ return Size; \
+}
+
+/**
+ A structure for indexing CM objects (nodes) used in PPTT generation.
+
+ PPTT_NODE_INDEXER is a wrapper around CM objects which augments these objects
+ with additional information that enables generating PPTT structures with
+ correct cross-references.
+
+ PPTT_NODE_INDEXER keeps track of each structure's offset from the base
+ address of the generated table. It also caches certain information and makes
+ PPTT cyclic reference detection possible.
+*/
+typedef struct PpttNodeIndexer {
+ /// Unique identifier for the node
+ CM_OBJECT_TOKEN Token;
+ /// Pointer to the CM object being indexed
+ VOID * Object;
+ /// Offset from the start of the PPTT table to the PPTT structure which is
+ /// represented by Object
+ UINT32 Offset;
+ /// Field used to mark nodes as 'visited' when detecting cycles in processor
+ /// and cache topology
+ UINT32 CycleDetectionStamp;
+ /// Reference to a Node Indexer element which is the parent of this Node
+ /// Indexer element in the processor and cache topology
+ /// e.g For a hardware thread the TopologyParent would point to a CPU node
+ /// For a L1 cache the TopologyParent would point to a L2 cache
+ struct PpttNodeIndexer * TopologyParent;
+} PPTT_NODE_INDEXER;
+
+typedef struct AcpiPpttGenerator {
+ /// ACPI Table generator header
+ ACPI_TABLE_GENERATOR Header;
+ /// PPTT structure count
+ UINT32 ProcTopologyStructCount;
+ /// Count of Processor Hierarchy Nodes
+ UINT32 ProcHierarchyNodeCount;
+ /// Count of Cache Structures
+ UINT32 CacheStructCount;
+ /// Count of Id Structures
+ UINT32 IdStructCount;
+ /// List of indexed CM objects for PPTT generation
+ PPTT_NODE_INDEXER * NodeIndexer;
+ /// Pointer to the start of Processor Hierarchy nodes in
+ /// the Node Indexer array
+ PPTT_NODE_INDEXER * ProcHierarchyNodeIndexedList;
+ /// Pointer to the start of Cache Structures in the Node Indexer array
+ PPTT_NODE_INDEXER * CacheStructIndexedList;
+ /// Pointer to the start of Id Structures in the Node Indexer array
+ PPTT_NODE_INDEXER * IdStructIndexedList;
+} ACPI_PPTT_GENERATOR;
+
+#pragma pack()
+
+#endif // PPTT_GENERATOR_H_
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibArm.inf
new file mode 100644
index 00000000..53d2b1ac
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibArm.inf
@@ -0,0 +1,36 @@
+## @file
+# Raw Table Generator
+#
+# Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[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/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/RawGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/RawGenerator.c
new file mode 100644
index 00000000..39c684ef
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/RawGenerator.c
@@ -0,0 +1,144 @@
+/** @file
+ MCFG Table Generator
+
+ Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#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 EDKII_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 (EStdAcpiTableIdRaw),
+ // Generator Description
+ L"ACPI.STD.RAW.GENERATOR",
+ // ACPI Table Signature - Unused
+ 0,
+ // ACPI Table Revision - Unused
+ 0,
+ // Minimum 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,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&RawGenerator);
+ DEBUG ((DEBUG_INFO, "RAW: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibArm.inf
new file mode 100644
index 00000000..bc3b0d3e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibArm.inf
@@ -0,0 +1,37 @@
+## @file
+# SPCR Table Generator
+#
+# Copyright (c) 2017 - 2020, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[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
+ SsdtSerialPortFixupLib
+
+[Pcd]
+
+[Protocols]
+
+[Guids]
+
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/SpcrGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/SpcrGenerator.c
new file mode 100644
index 00000000..6c07bfdc
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/SpcrGenerator.c
@@ -0,0 +1,477 @@
+/** @file
+ SPCR Table Generator
+
+ Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @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 <Library/MemoryAllocationLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/SsdtSerialPortFixupLib.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)
+
+/** A string representing the name of the SPCR port.
+*/
+#define NAME_STR_SPCR_PORT "COM1"
+
+/** An UID representing the SPCR port.
+*/
+#define UID_SPCR_PORT 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_PARITY,
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_STOP_BITS_1,
+ SPCR_FLOW_CONTROL_NONE,
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_ANSI,
+ 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
+ )
+
+/** Free any resources allocated for constructing the tables.
+
+ @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 an array of pointers
+ to ACPI Table(s).
+ @param [in] TableCount Number of ACPI table(s).
+
+ @retval EFI_SUCCESS The resources were freed successfully.
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FreeSpcrTableEx (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,
+ IN CONST UINTN TableCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((Table == NULL) ||
+ (*Table == NULL) ||
+ (TableCount != 2)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: SPCR: Invalid Table Pointer\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TableList = *Table;
+
+ if ((TableList[1] == NULL) ||
+ (TableList[1]->Signature !=
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: SPCR: Invalid SSDT table pointer.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Only need to free the SSDT table at index 1. The SPCR table is static.
+ Status = FreeSsdtSerialPortTable (TableList[1]);
+ ASSERT_EFI_ERROR (Status);
+
+ // Free the table list.
+ FreePool (*Table);
+
+ return Status;
+}
+
+/** Construct the SPCR ACPI table and its associated SSDT 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 FreeXXXXTableResourcesEx function.
+
+ @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 a list of generated ACPI table(s).
+ @param [out] TableCount Number of generated ACPI table(s).
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for
+ the requested object.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+ @retval EFI_UNSUPPORTED Unsupported configuration.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildSpcrTableEx (
+ IN CONST ACPI_TABLE_GENERATOR * This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,
+ OUT UINTN * CONST TableCount
+ )
+{
+ EFI_STATUS Status;
+ CM_ARM_SERIAL_PORT_INFO * SerialPortInfo;
+ UINT32 SerialPortCount;
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (TableCount != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Requested table revision = %d, is not supported."
+ "Supported table revision: Minimum = %d, Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Table = NULL;
+
+ Status = GetEArmObjSerialConsolePortInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &SerialPortInfo,
+ &SerialPortCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Failed to get serial port information. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ if (SerialPortCount == 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Serial port information not found. Status = %r\n",
+ EFI_NOT_FOUND
+ ));
+ return EFI_NOT_FOUND;
+ }
+
+ // Validate the SerialPort info. Only one SPCR port can be described.
+ // If platform provides description for multiple SPCR ports, use the
+ // first SPCR port information.
+ Status = ValidateSerialPortInfo (SerialPortInfo, 1);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Invalid serial port information. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Allocate a table to store pointers to the SPCR and SSDT tables.
+ TableList = (EFI_ACPI_DESCRIPTION_HEADER**)
+ AllocateZeroPool (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * 2);
+ if (TableList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Failed to allocate memory for Table List," \
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Build SPCR table.
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiSpcr,
+ AcpiTableInfo,
+ 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;
+ }
+
+ // The SPCR InterfaceType uses the same encoding as that of the
+ // DBG2 table Port Subtype field. However InterfaceType is 8-bit
+ // while the Port Subtype field in the DBG2 table is 16-bit.
+ if ((SerialPortInfo->PortSubtype & 0xFF00) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Invalid Port subtype (must be < 256). Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Update the serial port subtype
+ AcpiSpcr.InterfaceType = (UINT8)SerialPortInfo->PortSubtype;
+
+ // Update the base address
+ AcpiSpcr.BaseAddress.Address = SerialPortInfo->BaseAddress;
+
+ // Set the access size
+ if (SerialPortInfo->AccessSize >= EFI_ACPI_6_3_QWORD) {
+ Status = EFI_INVALID_PARAMETER;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Access size must be <= 3 (DWORD). Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ } else if (SerialPortInfo->AccessSize == EFI_ACPI_6_3_UNDEFINED) {
+ // 0 Undefined (legacy reasons)
+ // Default to DWORD access size as the access
+ // size field was introduced at a later date
+ // and some ConfigurationManager implementations
+ // may not be providing this field data
+ AcpiSpcr.BaseAddress.AccessSize = EFI_ACPI_6_3_DWORD;
+ } else {
+ AcpiSpcr.BaseAddress.AccessSize = SerialPortInfo->AccessSize;
+ }
+
+ // 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_19200;
+ break;
+ case 57600:
+ AcpiSpcr.BaudRate =
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_57600;
+ break;
+ case 115200:
+ AcpiSpcr.BaudRate =
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_BAUD_RATE_115200;
+ break;
+ default:
+ Status = EFI_UNSUPPORTED;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Invalid Baud Rate %ld, Status = %r\n",
+ SerialPortInfo->BaudRate,
+ Status
+ ));
+ goto error_handler;
+ } // switch
+
+ TableList[0] = (EFI_ACPI_DESCRIPTION_HEADER*)&AcpiSpcr;
+
+ // Build a SSDT table describing the serial port.
+ Status = BuildSsdtSerialPortTable (
+ AcpiTableInfo,
+ SerialPortInfo,
+ NAME_STR_SPCR_PORT,
+ UID_SPCR_PORT,
+ &TableList[1]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Failed to build associated SSDT table. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ *TableCount = 2;
+ *Table = TableList;
+
+ return Status;
+
+error_handler:
+ if (TableList != NULL) {
+ FreePool (TableList);
+ }
+
+ 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 (EStdAcpiTableIdSpcr),
+ // Generator Description
+ L"ACPI.STD.SPCR.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_REVISION,
+ // Minimum supported 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. Use the extended version instead.
+ NULL,
+ // Free table function. Use the extended version instead.
+ NULL,
+ // Extended Build table function.
+ BuildSpcrTableEx,
+ // Extended free function.
+ FreeSpcrTableEx
+};
+
+/** 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS 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 EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&SpcrGenerator);
+ DEBUG ((DEBUG_INFO, "SPCR: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/AcpiSratLibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/AcpiSratLibArm.inf
new file mode 100644
index 00000000..ac7e0ffa
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/AcpiSratLibArm.inf
@@ -0,0 +1,29 @@
+## @file
+# SRAT Table Generator
+#
+# Copyright (c) 2019, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = AcpiSratLibArm
+ FILE_GUID = 2CE21E0A-A39C-4B26-BC0E-526178036ACD
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL|DXE_DRIVER
+ CONSTRUCTOR = AcpiSratLibConstructor
+ DESTRUCTOR = AcpiSratLibDestructor
+
+[Sources]
+ SratGenerator.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ DynamicTablesPkg/DynamicTablesPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/SratGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/SratGenerator.c
new file mode 100644
index 00000000..1d723939
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/SratGenerator.c
@@ -0,0 +1,835 @@
+/** @file
+ SRAT Table Generator
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI 6.3 Specification, January 2019
+
+ @par Glossary:
+ - Cm or CM - Configuration Manager
+ - Obj or OBJ - Object
+**/
+
+#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>
+
+/**
+ ARM standard SRAT Generator
+
+ Requirements:
+ The following Configuration Manager Object(s) are used by this Generator:
+ - EArmObjGicCInfo (REQUIRED)
+ - EArmObjGicItsInfo (OPTIONAL)
+ - EArmObjMemoryAffinityInfo (OPTIONAL)
+ - EArmObjGenericInitiatorAffinityInfo (OPTIONAL)
+ - EArmObjDeviceHandleAcpi (OPTIONAL)
+ - EArmObjDeviceHandlePci (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
+ Interrupt Translation Service Information from the
+ Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjGicItsInfo,
+ CM_ARM_GIC_ITS_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the Memory Affinity
+ information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjMemoryAffinityInfo,
+ CM_ARM_MEMORY_AFFINITY_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the Generic Initiator Affinity
+ information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjGenericInitiatorAffinityInfo,
+ CM_ARM_GENERIC_INITIATOR_AFFINITY_INFO
+ );
+
+/**
+ This macro expands to a function that retrieves the ACPI Device Handle
+ information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjDeviceHandleAcpi,
+ CM_ARM_DEVICE_HANDLE_ACPI
+ );
+
+/**
+ This macro expands to a function that retrieves the PCI Device Handle
+ information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjDeviceHandlePci,
+ CM_ARM_DEVICE_HANDLE_PCI
+ );
+
+
+/** Return the PCI Device information in BDF format
+
+ PCI Bus Number - Max 256 busses (Bits 15:8 of BDF)
+ PCI Device Number - Max 32 devices (Bits 7:3 of BDF)
+ PCI Function Number - Max 8 functions (Bits 2:0 of BDF)
+
+ @param [in] DeviceHandlePci Pointer to the PCI Device Handle.
+
+ @retval BDF value corresponding to the PCI Device Handle.
+**/
+STATIC
+UINT16
+GetBdf (
+ IN CONST CM_ARM_DEVICE_HANDLE_PCI * DeviceHandlePci
+ )
+{
+ UINT16 Bdf;
+ Bdf = (UINT16)DeviceHandlePci->BusNumber << 8;
+ Bdf |= (DeviceHandlePci->DeviceNumber & 0x1F) << 3;
+ Bdf |= DeviceHandlePci->FunctionNumber & 0x7;
+ return Bdf;
+}
+
+/** Add the GICC Affinity Structures in the SRAT Table.
+
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Srat Pointer to the SRAT Table.
+ @param [in] GicCAffOffset Offset of the GICC Affinity
+ information in the SRAT Table.
+ @param [in] GicCInfo Pointer to the GIC CPU Information list.
+ @param [in] GicCCount Count of GIC CPU Interfaces.
+
+ @retval EFI_SUCCESS Table generated successfully.
+**/
+STATIC
+EFI_STATUS
+AddGICCAffinity (
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER * CONST Srat,
+ IN CONST UINT32 GicCAffOffset,
+ IN CONST CM_ARM_GICC_INFO * GicCInfo,
+ IN UINT32 GicCCount
+ )
+{
+ EFI_ACPI_6_3_GICC_AFFINITY_STRUCTURE * GicCAff;
+
+ ASSERT (Srat != NULL);
+ ASSERT (GicCInfo != NULL);
+
+ GicCAff = (EFI_ACPI_6_3_GICC_AFFINITY_STRUCTURE *)((UINT8*)Srat +
+ GicCAffOffset);
+
+ while (GicCCount-- != 0) {
+ DEBUG ((DEBUG_INFO, "SRAT: GicCAff = 0x%p\n", GicCAff));
+
+ GicCAff->Type = EFI_ACPI_6_3_GICC_AFFINITY;
+ GicCAff->Length = sizeof (EFI_ACPI_6_3_GICC_AFFINITY_STRUCTURE);
+ GicCAff->ProximityDomain = GicCInfo->ProximityDomain;
+ GicCAff->AcpiProcessorUid = GicCInfo->AcpiProcessorUid;
+ GicCAff->Flags = GicCInfo->AffinityFlags;
+ GicCAff->ClockDomain = GicCInfo->ClockDomain;
+
+ // Next
+ GicCAff++;
+ GicCInfo++;
+ }// while
+ return EFI_SUCCESS;
+}
+
+/** Add the GIC ITS Affinity Structures in the SRAT Table.
+
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Srat Pointer to the SRAT Table.
+ @param [in] GicItsAffOffset Offset of the GIC ITS Affinity
+ information in the SRAT Table.
+ @param [in] GicItsInfo Pointer to the GIC ITS Information list.
+ @param [in] GicItsCount Count of GIC ITS.
+
+ @retval EFI_SUCCESS Table generated successfully.
+**/
+STATIC
+EFI_STATUS
+AddGICItsAffinity (
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER * CONST Srat,
+ IN CONST UINT32 GicItsAffOffset,
+ IN CONST CM_ARM_GIC_ITS_INFO * GicItsInfo,
+ IN UINT32 GicItsCount
+ )
+{
+ EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE * GicItsAff;
+
+ ASSERT (Srat != NULL);
+ ASSERT (GicItsInfo != NULL);
+
+ GicItsAff = (EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE *)((UINT8*)Srat +
+ GicItsAffOffset);
+
+ while (GicItsCount-- != 0) {
+ DEBUG ((DEBUG_INFO, "SRAT: GicItsAff = 0x%p\n", GicItsAff));
+
+ GicItsAff->Type = EFI_ACPI_6_3_GIC_ITS_AFFINITY;
+ GicItsAff->Length = sizeof (EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE);
+ GicItsAff->ProximityDomain = GicItsInfo->ProximityDomain;
+ GicItsAff->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
+ GicItsAff->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
+ GicItsAff->ItsId = GicItsInfo->GicItsId;
+
+ // Next
+ GicItsAff++;
+ GicItsInfo++;
+ }// while
+ return EFI_SUCCESS;
+}
+
+/** Add the Memory Affinity Structures in the SRAT Table.
+
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Srat Pointer to the SRAT Table.
+ @param [in] MemAffOffset Offset of the Memory Affinity
+ information in the SRAT Table.
+ @param [in] MemAffInfo Pointer to the Memory Affinity Information list.
+ @param [in] MemAffCount Count of Memory Affinity objects.
+
+ @retval EFI_SUCCESS Table generated successfully.
+**/
+STATIC
+EFI_STATUS
+AddMemoryAffinity (
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER * CONST Srat,
+ IN CONST UINT32 MemAffOffset,
+ IN CONST CM_ARM_MEMORY_AFFINITY_INFO * MemAffInfo,
+ IN UINT32 MemAffCount
+ )
+{
+ EFI_ACPI_6_3_MEMORY_AFFINITY_STRUCTURE * MemAff;
+
+ ASSERT (Srat != NULL);
+ ASSERT (MemAffInfo != NULL);
+
+ MemAff = (EFI_ACPI_6_3_MEMORY_AFFINITY_STRUCTURE *)((UINT8*)Srat +
+ MemAffOffset);
+
+ while (MemAffCount-- != 0) {
+ DEBUG ((DEBUG_INFO, "SRAT: MemAff = 0x%p\n", MemAff));
+
+ MemAff->Type = EFI_ACPI_6_3_MEMORY_AFFINITY;
+ MemAff->Length = sizeof (EFI_ACPI_6_3_MEMORY_AFFINITY_STRUCTURE);
+ MemAff->ProximityDomain = MemAffInfo->ProximityDomain;
+ MemAff->Reserved1 = EFI_ACPI_RESERVED_WORD;
+ MemAff->AddressBaseLow = (UINT32)(MemAffInfo->BaseAddress & MAX_UINT32);
+ MemAff->AddressBaseHigh = (UINT32)(MemAffInfo->BaseAddress >> 32);
+ MemAff->LengthLow = (UINT32)(MemAffInfo->Length & MAX_UINT32);
+ MemAff->LengthHigh = (UINT32)(MemAffInfo->Length >> 32);
+ MemAff->Reserved2 = EFI_ACPI_RESERVED_DWORD;
+ MemAff->Flags = MemAffInfo->Flags;
+ MemAff->Reserved3 = EFI_ACPI_RESERVED_QWORD;
+
+ // Next
+ MemAff++;
+ MemAffInfo++;
+ }// while
+ return EFI_SUCCESS;
+}
+
+
+/** Add the Generic Initiator Affinity Structures in the SRAT Table.
+
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager
+ Protocol Interface.
+ @param [in] Srat Pointer to the SRAT Table.
+ @param [in] GenInitAffOff Offset of the Generic Initiator Affinity
+ information in the SRAT Table.
+ @param [in] GenInitAffInfo Pointer to the Generic Initiator Affinity
+ Information list.
+ @param [in] GenInitAffCount Count of Generic Initiator Affinity
+ objects.
+
+ @retval EFI_SUCCESS Table generated 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.
+**/
+STATIC
+EFI_STATUS
+AddGenericInitiatorAffinity (
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER * CONST Srat,
+ IN CONST UINT32 GenInitAffOff,
+ IN CONST CM_ARM_GENERIC_INITIATOR_AFFINITY_INFO * GenInitAffInfo,
+ IN UINT32 GenInitAffCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY_STRUCTURE * GenInitAff;
+ CM_ARM_DEVICE_HANDLE_ACPI * DeviceHandleAcpi;
+ CM_ARM_DEVICE_HANDLE_PCI * DeviceHandlePci;
+ UINT32 DeviceHandleCount;
+
+ ASSERT (Srat != NULL);
+ ASSERT (GenInitAffInfo != NULL);
+
+ GenInitAff = (EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY_STRUCTURE *)(
+ (UINT8*)Srat + GenInitAffOff);
+
+ while (GenInitAffCount-- != 0) {
+ DEBUG ((DEBUG_INFO, "SRAT: GenInitAff = 0x%p\n", GenInitAff));
+
+ GenInitAff->Type = EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY;
+ GenInitAff->Length =
+ sizeof (EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY_STRUCTURE);
+ GenInitAff->Reserved1 = EFI_ACPI_RESERVED_WORD;
+ GenInitAff->DeviceHandleType = GenInitAffInfo->DeviceHandleType;
+ GenInitAff->ProximityDomain = GenInitAffInfo->ProximityDomain;
+
+ if (GenInitAffInfo->DeviceHandleToken == CM_NULL_TOKEN) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Invalid Device Handle Token.\n"
+ ));
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GenInitAffInfo->DeviceHandleType == EFI_ACPI_6_3_ACPI_DEVICE_HANDLE) {
+ Status = GetEArmObjDeviceHandleAcpi (
+ CfgMgrProtocol,
+ GenInitAffInfo->DeviceHandleToken,
+ &DeviceHandleAcpi,
+ &DeviceHandleCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to get ACPI Device Handle Inf."
+ " DeviceHandleToken = %p."
+ " Status = %r\n",
+ GenInitAffInfo->DeviceHandleToken,
+ Status
+ ));
+ return Status;
+ }
+
+ // We are expecting only one device handle.
+ ASSERT (DeviceHandleCount == 1);
+
+ // Populate the ACPI device handle information.
+ GenInitAff->DeviceHandle.Acpi.AcpiHid = DeviceHandleAcpi->Hid;
+ GenInitAff->DeviceHandle.Acpi.AcpiUid = DeviceHandleAcpi->Uid;
+ GenInitAff->DeviceHandle.Acpi.Reserved[0] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Acpi.Reserved[1] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Acpi.Reserved[2] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Acpi.Reserved[3] = EFI_ACPI_RESERVED_BYTE;
+ } else if (GenInitAffInfo->DeviceHandleType ==
+ EFI_ACPI_6_3_PCI_DEVICE_HANDLE) {
+ Status = GetEArmObjDeviceHandlePci (
+ CfgMgrProtocol,
+ GenInitAffInfo->DeviceHandleToken,
+ &DeviceHandlePci,
+ &DeviceHandleCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to get ACPI Device Handle Inf."
+ " DeviceHandleToken = %p."
+ " Status = %r\n",
+ GenInitAffInfo->DeviceHandleToken,
+ Status
+ ));
+ return Status;
+ }
+
+ // We are expecting only one device handle
+ ASSERT (DeviceHandleCount == 1);
+
+ // Populate the ACPI device handle information.
+ GenInitAff->DeviceHandle.Pci.PciSegment = DeviceHandlePci->SegmentNumber;
+ GenInitAff->DeviceHandle.Pci.PciBdfNumber = GetBdf (DeviceHandlePci);
+
+ GenInitAff->DeviceHandle.Pci.Reserved[0] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[1] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[2] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[3] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[4] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[5] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[6] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[7] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[8] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[9] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[10] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->DeviceHandle.Pci.Reserved[11] = EFI_ACPI_RESERVED_BYTE;
+ } else {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Invalid Device Handle Type.\n"
+ ));
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ GenInitAff->Flags = GenInitAffInfo->Flags;
+ GenInitAff->Reserved2[0] = EFI_ACPI_RESERVED_BYTE;
+ GenInitAff->Reserved2[1] = EFI_ACPI_RESERVED_BYTE;
+
+ // Next
+ GenInitAff++;
+ GenInitAffInfo++;
+ }// while
+ return EFI_SUCCESS;
+}
+
+/** Construct the SRAT 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
+BuildSratTable (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TableSize;
+ UINT32 GicCCount;
+ UINT32 GicItsCount;
+ UINT32 MemAffCount;
+ UINT32 GenInitiatorAffCount;
+
+ UINT32 GicCAffOffset;
+ UINT32 GicItsAffOffset;
+ UINT32 MemAffOffset;
+ UINT32 GenInitiatorAffOffset;
+
+ CM_ARM_GICC_INFO * GicCInfo;
+ CM_ARM_GIC_ITS_INFO * GicItsInfo;
+ CM_ARM_MEMORY_AFFINITY_INFO * MemAffInfo;
+ CM_ARM_GENERIC_INITIATOR_AFFINITY_INFO * GenInitiatorAffInfo;
+
+ EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER * Srat;
+
+ ASSERT (
+ (This != NULL) &&
+ (AcpiTableInfo != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (Table != NULL) &&
+ (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&
+ (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)
+ );
+
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Requested table revision = %d is not supported. "
+ "Supported table revisions: Minimum = %d. Maximum = %d\n",
+ AcpiTableInfo->AcpiTableRevision,
+ This->MinAcpiTableRevision,
+ This->AcpiTableRevision
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Table = NULL;
+
+ Status = GetEArmObjGicCInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &GicCInfo,
+ &GicCCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to get GICC Info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ if (GicCCount == 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: GIC CPU Interface information not provided.\n"
+ ));
+ ASSERT (0);
+ Status = EFI_INVALID_PARAMETER;
+ goto error_handler;
+ }
+
+ Status = GetEArmObjGicItsInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &GicItsInfo,
+ &GicItsCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to get GIC ITS Info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ Status = GetEArmObjMemoryAffinityInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &MemAffInfo,
+ &MemAffCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to get Memory Affinity Info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ Status = GetEArmObjGenericInitiatorAffinityInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &GenInitiatorAffInfo,
+ &GenInitiatorAffCount
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to get Generic Initiator Affinity Info."
+ " Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Calculate the size of the SRAT table
+ TableSize = sizeof (EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER);
+
+ GicCAffOffset = TableSize;
+ TableSize += (sizeof (EFI_ACPI_6_3_GICC_AFFINITY_STRUCTURE) * GicCCount);
+
+ if (GicItsCount != 0) {
+ GicItsAffOffset = TableSize;
+ TableSize += (sizeof (EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE) *
+ GicItsCount);
+ }
+
+ if (MemAffCount != 0) {
+ MemAffOffset = TableSize;
+ TableSize += (sizeof (EFI_ACPI_6_3_MEMORY_AFFINITY_STRUCTURE) *
+ MemAffCount);
+ }
+
+ if (GenInitiatorAffCount != 0) {
+ GenInitiatorAffOffset = TableSize;
+ TableSize += (sizeof (EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY_STRUCTURE) *
+ GenInitiatorAffCount);
+ }
+
+ // Allocate the Buffer for SRAT table
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);
+ if (*Table == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to allocate memory for SRAT Table, Size = %d," \
+ " Status = %r\n",
+ TableSize,
+ Status
+ ));
+ goto error_handler;
+ }
+
+ Srat = (EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER*)*Table;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "SRAT: Srat = 0x%p TableSize = 0x%x\n",
+ Srat,
+ TableSize
+ ));
+
+ Status = AddAcpiHeader (
+ CfgMgrProtocol,
+ This,
+ &Srat->Header,
+ AcpiTableInfo,
+ TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to add ACPI header. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Setup the Reserved fields
+ // Reserved1 must be set to 1 for backward compatibility
+ Srat->Reserved1 = 1;
+ Srat->Reserved2 = EFI_ACPI_RESERVED_QWORD;
+
+ Status = AddGICCAffinity (
+ CfgMgrProtocol,
+ Srat,
+ GicCAffOffset,
+ GicCInfo,
+ GicCCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to add GICC Affinity structures. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ if (GicItsCount != 0) {
+ Status = AddGICItsAffinity (
+ CfgMgrProtocol,
+ Srat,
+ GicItsAffOffset,
+ GicItsInfo,
+ GicItsCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to add GIC ITS Affinity structures. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ if (MemAffCount != 0) {
+ Status = AddMemoryAffinity (
+ CfgMgrProtocol,
+ Srat,
+ MemAffOffset,
+ MemAffInfo,
+ MemAffCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to add Memory Affinity structures. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ if (GenInitiatorAffCount != 0) {
+ Status = AddGenericInitiatorAffinity (
+ CfgMgrProtocol,
+ Srat,
+ GenInitiatorAffOffset,
+ GenInitiatorAffInfo,
+ GenInitiatorAffCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SRAT: Failed to add Generic Initiator Affinity structures."
+ " Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
+ return Status;
+
+error_handler:
+
+ if (*Table != NULL) {
+ FreePool (*Table);
+ *Table = NULL;
+ }
+
+ return Status;
+}
+
+/** Free any resources allocated for constructing the SRAT.
+
+ @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
+FreeSratTableResources (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table
+ )
+{
+ ASSERT (
+ (This != NULL) &&
+ (AcpiTableInfo != NULL) &&
+ (CfgMgrProtocol != NULL) &&
+ (AcpiTableInfo->TableGeneratorId == This->GeneratorID) &&
+ (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature)
+ );
+
+ if ((Table == NULL) || (*Table == NULL)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: SRAT: Invalid Table Pointer\n"));
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FreePool (*Table);
+ *Table = NULL;
+ return EFI_SUCCESS;
+}
+
+/** The SRAT Table Generator revision.
+*/
+#define SRAT_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the SRAT Table Generator.
+*/
+STATIC
+CONST
+ACPI_TABLE_GENERATOR SratGenerator = {
+ // Generator ID
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSrat),
+ // Generator Description
+ L"ACPI.STD.SRAT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE,
+ // ACPI Table Revision supported by this Generator
+ EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION,
+ // Minimum supported ACPI Table Revision
+ EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ SRAT_GENERATOR_REVISION,
+ // Build Table function
+ BuildSratTable,
+ // Free Resource function
+ FreeSratTableResources,
+ // Extended build function not needed
+ NULL,
+ // Extended build function not implemented by the generator.
+ // Hence extended 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
+AcpiSratLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = RegisterAcpiTableGenerator (&SratGenerator);
+ DEBUG ((DEBUG_INFO, "SRAT: 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
+AcpiSratLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&SratGenerator);
+ DEBUG ((DEBUG_INFO, "SRAT: Deregister Generator. Status = %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c
new file mode 100644
index 00000000..a0c4a7fa
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c
@@ -0,0 +1,708 @@
+/** @file
+ SSDT CMN-600 AML Table Generator.
+
+ Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - Arm CoreLink CMN-600 Coherent Mesh Network Technical Reference Manual r3p0
+ - Generic ACPI for Arm Components 1.0 Platform Design Document
+**/
+
+#include <IndustryStandard/DebugPort2Table.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/AmlLib/AmlLib.h>
+#include <Library/TableHelperLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+#include "SsdtCmn600Generator.h"
+
+/** C array containing the compiled AML template.
+ This symbol is defined in the auto generated C file
+ containing the AML bytecode array.
+*/
+extern CHAR8 ssdtcmn600template_aml_code[];
+
+/** SSDT CMN-600 Table Generator.
+
+ Requirements:
+ The following Configuration Manager Object(s) are required by
+ this Generator:
+ - EArmObjCmn600Info
+*/
+
+/** This macro expands to a function that retrieves the CMN-600
+ Information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjCmn600Info,
+ CM_ARM_CMN_600_INFO
+ );
+
+/** Check the CMN-600 Information.
+
+ @param [in] Cmn600InfoList Array of CMN-600 information structure.
+ @param [in] Cmn600Count Count of CMN-600 information structure.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ValidateCmn600Info (
+ IN CONST CM_ARM_CMN_600_INFO * Cmn600InfoList,
+ IN CONST UINT32 Cmn600Count
+ )
+{
+ UINT32 Index;
+ UINT32 DtcIndex;
+ CONST CM_ARM_CMN_600_INFO * Cmn600Info;
+ CONST CM_ARM_GENERIC_INTERRUPT * DtcInterrupt;
+
+ if ((Cmn600InfoList == NULL) ||
+ (Cmn600Count == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Validate each Cmn600Info structure.
+ for (Index = 0; Index < Cmn600Count; Index++) {
+ Cmn600Info = &Cmn600InfoList[Index];
+
+ // At least one DTC is required.
+ if ((Cmn600Info->DtcCount == 0) ||
+ (Cmn600Info->DtcCount > MAX_DTC_COUNT)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Invalid DTC configuration:\n"
+ ));
+ goto error_handler;
+ }
+
+ // Check PERIPHBASE and ROOTNODEBASE address spaces are initialized.
+ if ((Cmn600Info->PeriphBaseAddress == 0) ||
+ (Cmn600Info->RootNodeBaseAddress == 0)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Invalid PERIPHBASE or ROOTNODEBASE.\n"
+ ));
+ goto error_handler;
+ }
+
+ // The PERIPHBASE address must be 64MB aligned for a (X < 4) && (Y < 4)
+ // dimension mesh, and 256MB aligned otherwise.
+ // Check it is a least 64MB aligned.
+ if ((Cmn600Info->PeriphBaseAddress &
+ (PERIPHBASE_MIN_ADDRESS_LENGTH - 1)) != 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: PERIPHBASE address must be 64MB aligned.\n"
+ ));
+ goto error_handler;
+ }
+
+ // The PERIPHBASE address is at most 64MB for a (X < 4) && (Y < 4)
+ // dimension mesh, and 256MB otherwise. Check it is not more than 256MB.
+ if (Cmn600Info->PeriphBaseAddressLength > PERIPHBASE_MAX_ADDRESS_LENGTH) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: PERIPHBASE address range must be < 256MB.\n"
+ ));
+ goto error_handler;
+ }
+
+ // Check the 16 KB alignment of the ROOTNODEBASE address.
+ if ((Cmn600Info->PeriphBaseAddress &
+ (ROOTNODEBASE_ADDRESS_LENGTH - 1)) != 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Root base address must be 16KB aligned.\n"
+ ));
+ goto error_handler;
+ }
+
+ // The ROOTNODEBASE address space should be included in the PERIPHBASE
+ // address space.
+ if ((Cmn600Info->PeriphBaseAddress > Cmn600Info->RootNodeBaseAddress) ||
+ ((Cmn600Info->PeriphBaseAddress + Cmn600Info->PeriphBaseAddressLength) <
+ (Cmn600Info->RootNodeBaseAddress + ROOTNODEBASE_ADDRESS_LENGTH))) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600:"
+ " ROOTNODEBASE address space not in PERIPHBASE address space.\n"
+ ));
+ goto error_handler;
+ }
+
+ for (DtcIndex = 0; DtcIndex < Cmn600Info->DtcCount; DtcIndex++) {
+ DtcInterrupt = &Cmn600Info->DtcInterrupt[DtcIndex];
+ if (((DtcInterrupt->Flags &
+ EFI_ACPI_EXTENDED_INTERRUPT_FLAG_PRODUCER_CONSUMER_MASK) == 0)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: DTC Interrupt must be consumer.\n"
+ ));
+ goto error_handler;
+ }
+ } // for DTC Interrupt
+
+ } //for Cmn600InfoList
+
+ return EFI_SUCCESS;
+
+error_handler:
+
+ DEBUG ((
+ DEBUG_ERROR,
+ "PeriphBaseAddress = 0x%llx\n"
+ "PeriphBaseAddressLength = 0x%llx\n"
+ "RootNodeBaseAddress = 0x%llx\n"
+ "DtcCount = %u\n",
+ Cmn600Info->PeriphBaseAddress,
+ Cmn600Info->PeriphBaseAddressLength,
+ Cmn600Info->RootNodeBaseAddress,
+ Cmn600Info->DtcCount
+ ));
+
+ DEBUG_CODE (
+ for (DtcIndex = 0; DtcIndex < Cmn600Info->DtcCount; DtcIndex++) {
+ DtcInterrupt = &Cmn600Info->DtcInterrupt[DtcIndex];
+ DEBUG ((
+ DEBUG_ERROR,
+ " DTC[%d]:\n",
+ DtcIndex
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ " Interrupt = 0x%lx\n",
+ DtcInterrupt->Interrupt
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ " Flags = 0x%lx\n",
+ DtcInterrupt->Flags
+ ));
+ } // for
+ );
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/** Build a SSDT table describing the CMN-600 device.
+
+ The table created by this function must be freed by FreeSsdtCmn600Table.
+
+ @param [in] Cmn600Info Pointer to a Cmn600 structure.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ @param [in] Uid UID for the CMN600 device.
+ @param [out] Table If success, pointer to the created SSDT table.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FixupCmn600Info (
+ IN CONST CM_ARM_CMN_600_INFO * Cmn600Info,
+ IN CONST CHAR8 * Name,
+ IN CONST UINT64 Uid,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** Table
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ UINT8 Index;
+ CONST CM_ARM_GENERIC_INTERRUPT * DtcInt;
+
+ EFI_ACPI_DESCRIPTION_HEADER * SsdtCmn600Template;
+ AML_ROOT_NODE_HANDLE RootNodeHandle;
+ AML_OBJECT_NODE_HANDLE NameOpIdNode;
+ AML_OBJECT_NODE_HANDLE NameOpCrsNode;
+ AML_DATA_NODE_HANDLE CmnPeriphBaseRdNode;
+ AML_DATA_NODE_HANDLE CmnRootNodeBaseRdNode;
+ AML_OBJECT_NODE_HANDLE DeviceNode;
+
+ // Parse the Ssdt CMN-600 Template.
+ SsdtCmn600Template = (EFI_ACPI_DESCRIPTION_HEADER*)
+ ssdtcmn600template_aml_code;
+
+ RootNodeHandle = NULL;
+ Status = AmlParseDefinitionBlock (
+ SsdtCmn600Template,
+ &RootNodeHandle
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Failed to parse SSDT CMN-600 Template."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Get the _UID NameOp object defined by the "Name ()" statement,
+ // and update its value.
+ Status = AmlFindNode (
+ RootNodeHandle,
+ "\\_SB_.CMN0._UID",
+ &NameOpIdNode
+ );
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ Status = AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid);
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ // Get the _CRS object defined by the "Name ()" statement.
+ Status = AmlFindNode (
+ RootNodeHandle,
+ "\\_SB.CMN0._CRS",
+ &NameOpCrsNode
+ );
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ // Get the first Rd node in the "_CRS" object.
+ // This is the PERIPHBASE node.
+ Status = AmlNameOpCrsGetFirstRdNode (NameOpCrsNode, &CmnPeriphBaseRdNode);
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ if (CmnPeriphBaseRdNode == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto error_handler;
+ }
+
+ // Update the PERIPHBASE base address and length.
+ Status = AmlUpdateRdQWord (
+ CmnPeriphBaseRdNode,
+ Cmn600Info->PeriphBaseAddress,
+ Cmn600Info->PeriphBaseAddressLength
+ );
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ // Get the QWord node corresponding to the ROOTNODEBASE.
+ // It is the second Resource Data element in the BufferNode's
+ // variable list of arguments.
+ Status = AmlNameOpCrsGetNextRdNode (
+ CmnPeriphBaseRdNode,
+ &CmnRootNodeBaseRdNode
+ );
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ if (CmnRootNodeBaseRdNode == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto error_handler;
+ }
+
+ // Update the ROOTNODEBASE base address and length.
+ Status = AmlUpdateRdQWord (
+ CmnRootNodeBaseRdNode,
+ Cmn600Info->RootNodeBaseAddress,
+ ROOTNODEBASE_ADDRESS_LENGTH
+ );
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ // Add the Interrupt node(s).
+ // Generate Resource Data node(s) corresponding to the "Interrupt ()"
+ // ASL function and add it at the last position in the list of
+ // Resource Data nodes.
+ for (Index = 0; Index < Cmn600Info->DtcCount; Index++) {
+ DtcInt = &Cmn600Info->DtcInterrupt[Index];
+ Status = AmlCodeGenCrsAddRdInterrupt (
+ NameOpCrsNode,
+ ((DtcInt->Flags &
+ EFI_ACPI_EXTENDED_INTERRUPT_FLAG_PRODUCER_CONSUMER_MASK) != 0),
+ ((DtcInt->Flags &
+ EFI_ACPI_EXTENDED_INTERRUPT_FLAG_MODE_MASK) != 0),
+ ((DtcInt->Flags &
+ EFI_ACPI_EXTENDED_INTERRUPT_FLAG_POLARITY_MASK) != 0),
+ ((DtcInt->Flags &
+ EFI_ACPI_EXTENDED_INTERRUPT_FLAG_SHARABLE_MASK) != 0),
+ (UINT32*)&DtcInt->Interrupt,
+ 1
+ );
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+ } // for
+
+ // Fixup the CMN600 device name.
+ // This MUST be done at the end, otherwise AML paths won't be valid anymore.
+ // Get the CMN0 variable defined by the "Device ()" statement.
+ Status = AmlFindNode (RootNodeHandle, "\\_SB_.CMN0", &DeviceNode);
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ // Update the CMN600 Device's name.
+ Status = AmlDeviceOpUpdateName (DeviceNode, (CHAR8*)Name);
+ if (EFI_ERROR (Status)) {
+ goto error_handler;
+ }
+
+ // Serialise the definition block
+ Status = AmlSerializeDefinitionBlock (
+ RootNodeHandle,
+ Table
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Failed to Serialize SSDT Table Data."
+ " Status = %r\n",
+ Status
+ ));
+ }
+
+error_handler:
+ // Cleanup
+ if (RootNodeHandle != NULL) {
+ Status1 = AmlDeleteTree (RootNodeHandle);
+ if (EFI_ERROR (Status1)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Failed to cleanup AML tree."
+ " Status = %r\n",
+ Status1
+ ));
+ // If Status was success but we failed to delete the AML Tree
+ // return Status1 else return the original error code, i.e. Status.
+ if (!EFI_ERROR (Status)) {
+ return Status1;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/** Free any resources allocated for constructing the SSDT tables for CMN-600.
+
+ @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 an array of pointers
+ to ACPI Table(s).
+ @param [in] TableCount Number of ACPI table(s).
+
+ @retval EFI_SUCCESS The resources were freed successfully.
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FreeSsdtCmn600TableResourcesEx (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,
+ IN CONST UINTN TableCount
+ )
+{
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+ UINTN Index;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((Table == NULL) ||
+ (*Table == NULL) ||
+ (TableCount == 0)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: SSDT-CMN-600: Invalid Table Pointer\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TableList = *Table;
+
+ for (Index = 0; Index < TableCount; Index++) {
+ if ((TableList[Index] != NULL) &&
+ (TableList[Index]->Signature ==
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {
+ FreePool (TableList[Index]);
+ } else {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Could not free SSDT table at index %d."
+ " Status = %r\n",
+ Index,
+ EFI_INVALID_PARAMETER
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+ } //for
+
+ // Free the table list.
+ FreePool (*Table);
+ *Table = NULL;
+ return EFI_SUCCESS;
+}
+
+/** Construct SSDT tables for describing CMN-600 meshes.
+
+ 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 FreeXXXXTableResourcesEx function.
+
+ @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 a list of generated ACPI table(s).
+ @param [out] TableCount Number of generated ACPI table(s).
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for
+ the requested object.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+ @retval EFI_UNSUPPORTED Unsupported configuration.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildSsdtCmn600TableEx (
+ IN CONST ACPI_TABLE_GENERATOR * This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,
+ OUT UINTN * CONST TableCount
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Index;
+ CM_ARM_CMN_600_INFO * Cmn600Info;
+ UINT32 Cmn600Count;
+ CHAR8 NewName[5];
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (TableCount != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ *Table = NULL;
+
+ // Get CMN-600 information.
+ Status = GetEArmObjCmn600Info (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &Cmn600Info,
+ &Cmn600Count
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Failed to get the CMN-600 information."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ if ((Cmn600Count == 0) || (Cmn600Count > MAX_CMN600_DEVICES_SUPPORTED)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: CMN600 peripheral count = %d."
+ " This must be between 1 to 16.\n",
+ Cmn600Count
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Validate the CMN-600 Info.
+ Status = ValidateCmn600Info (Cmn600Info, Cmn600Count);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Invalid CMN600 information. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Allocate a table to store pointers to the SSDT tables.
+ TableList = (EFI_ACPI_DESCRIPTION_HEADER**)
+ AllocateZeroPool (
+ (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * Cmn600Count)
+ );
+ if (TableList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Failed to allocate memory for Table List."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Setup the table list early so that that appropriate cleanup
+ // can be done in case of failure.
+ *Table = TableList;
+
+ NewName[0] = 'C';
+ NewName[1] = 'M';
+ NewName[2] = 'N';
+ NewName[4] = '\0';
+ for (Index = 0; Index < Cmn600Count; Index++) {
+ NewName[3] = AsciiFromHex ((UINT8)(Index));
+
+ // Build a SSDT table describing the CMN600 device.
+ Status = FixupCmn600Info (
+ &Cmn600Info[Index],
+ NewName,
+ Index,
+ &TableList[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-CMN-600: Failed to build associated SSDT table."
+ " Status = %r\n",
+ Status
+ ));
+ break;
+ }
+
+ // Increment the table count here so that appropriate clean-up
+ // can be done in case of failure.
+ *TableCount += 1;
+ } // for
+
+ // Note: Table list and CMN600 device count has been setup. The
+ // framework will invoke FreeSsdtCmn600TableResourcesEx() even
+ // on failure, so appropriate clean-up will be done.
+ return Status;
+}
+
+/** This macro defines the Raw Generator revision.
+*/
+#define SSDT_CMN_600_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the Raw Table Generator.
+*/
+STATIC
+CONST
+ACPI_TABLE_GENERATOR SsdtCmn600Generator = {
+ // Generator ID
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtCmn600),
+ // Generator Description
+ L"ACPI.STD.SSDT.CMN600.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
+ // ACPI Table Revision - Unused
+ 0,
+ // Minimum ACPI Table Revision - Unused
+ 0,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ SSDT_CMN_600_GENERATOR_REVISION,
+ // Build table function. Use the extended version instead.
+ NULL,
+ // Free table function. Use the extended version instead.
+ NULL,
+ // Build Table function
+ BuildSsdtCmn600TableEx,
+ // Free Resource function
+ FreeSsdtCmn600TableResourcesEx
+};
+
+/** 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
+AcpiSsdtCmn600LibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = RegisterAcpiTableGenerator (&SsdtCmn600Generator);
+ DEBUG ((
+ DEBUG_INFO,
+ "SSDT-CMN-600: 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
+AcpiSsdtCmn600LibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = DeregisterAcpiTableGenerator (&SsdtCmn600Generator);
+ DEBUG ((
+ DEBUG_INFO,
+ "SSDT-CMN-600: Deregister Generator. Status = %r\n",
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.h b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.h
new file mode 100644
index 00000000..a7ecb940
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.h
@@ -0,0 +1,51 @@
+/** @file
+
+ Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Cm or CM - Configuration Manager
+ - Obj or OBJ - Object
+ - Std or STD - Standard
+
+ @par Reference(s):
+ - Arm CoreLink CMN-600 Coherent Mesh Network Technical Reference Manual r3p0
+ - Generic ACPI for Arm Components 1.0 Platform Design Document
+**/
+
+#ifndef SSDT_CMN600_GENERATOR_H_
+#define SSDT_CMN600_GENERATOR_H_
+
+/** PeriphBase maximum address length is 256MB (0x10000000)
+ for a (X >= 4) || (Y >= 4) dimensions mesh.
+*/
+#define PERIPHBASE_MAX_ADDRESS_LENGTH SIZE_256MB
+
+/** PeriphBase minimum address length is 64MB (0x04000000)
+ for a (X < 4) && (Y < 4) dimensions mesh.
+*/
+#define PERIPHBASE_MIN_ADDRESS_LENGTH SIZE_64MB
+
+/** RootNodeBase address length is 16KB (0x00004000).
+*/
+#define ROOTNODEBASE_ADDRESS_LENGTH SIZE_16KB
+
+/** Maximum number of CMN-600 Debug and Trace Logic Controllers (DTC).
+*/
+#define MAX_DTC_COUNT 4
+
+/** Starting value for the UID to represent the CMN600 devices.
+*/
+#define CMN600_DEVICE_START_UID 0
+
+/** Maximum CMN-600 devices supported by this generator.
+ This generator supports a maximum of 16 CMN-600 devices.
+ Note: This is not a hard limitation and can be extended if needed.
+ Corresponding changes would be needed to support the Name and
+ UID fields describing the serial port.
+
+*/
+#define MAX_CMN600_DEVICES_SUPPORTED 16
+
+#endif // SSDT_CMN600_GENERATOR_H_
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf
new file mode 100644
index 00000000..9f10c987
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600LibArm.inf
@@ -0,0 +1,34 @@
+## @file
+# Ssdt CMN-600 Table Generator
+#
+# Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = SsdtCmn600LibArm
+ FILE_GUID = CEDB450D-8F0E-4ACC-8FB7-F72EC7D216A4
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL|DXE_DRIVER
+ CONSTRUCTOR = AcpiSsdtCmn600LibConstructor
+ DESTRUCTOR = AcpiSsdtCmn600LibDestructor
+
+[Sources]
+ SsdtCmn600Generator.c
+ SsdtCmn600Generator.h
+ SsdtCmn600Template.asl
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ DynamicTablesPkg/DynamicTablesPkg.dec
+
+[LibraryClasses]
+ AmlLib
+ BaseLib
+
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Template.asl b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Template.asl
new file mode 100644
index 00000000..33c49f8f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Template.asl
@@ -0,0 +1,81 @@
+/** @file
+ SSDT CMN-600 Template
+
+ Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - Arm CoreLink CMN-600 Coherent Mesh Network Technical Reference Manual r3p0
+ - Generic ACPI for Arm Components 1.0 Platform Design Document
+
+ @par Glossary:
+ - {template} - Data fixed up using AML Fixup APIs.
+ - {codegen} - Data generated using AML Codegen APIs.
+**/
+
+DefinitionBlock ("SsdtCmn600.aml", "SSDT", 2, "ARMLTD", "CMN-600", 1) {
+ Scope (_SB) {
+ // CMN-600 device object for a X * Y mesh, where (X >= 4) || (Y >= 4).
+ Device (CMN0) { // {template}
+ Name (_HID, "ARMHC600")
+ Name (_UID, 0x0) // {template}
+
+ Name (_CRS, ResourceTemplate () {
+ // Descriptor for 256 MB of the CFG region at offset PERIPHBASE.
+ QWordMemory (
+ ResourceConsumer, // bit 0 of general flags is 0.
+ PosDecode,
+ MinFixed, // Range is fixed.
+ MaxFixed, // Range is Fixed.
+ NonCacheable,
+ ReadWrite,
+ 0x00000000, // Granularity
+ 0xA0000000, // MinAddress // {template}
+ 0xAFFFFFFF, // MaxAddress // {template}
+ 0x00000000, // Translation
+ 0x10000000, // RangeLength // {template}
+ , // ResourceSourceIndex
+ , // ResourceSource
+ CFGR // DescriptorName
+ ) // QWordMemory
+
+ // Descriptor for the root node. This is a 16 KB region at offset
+ // ROOTNODEBASE. In this example, ROOTNODEBASE starts at the 16 KB
+ // aligned offset of PERIPHBASE.
+ QWordMemory (
+ ResourceConsumer, // bit 0 of general flags is 0.
+ PosDecode,
+ MinFixed, // Range is fixed.
+ MaxFixed, // Range is Fixed.
+ NonCacheable,
+ ReadWrite,
+ 0x00000000, // Granularity
+ 0xA0000000, // MinAddress // {template}
+ 0xAFFFFFFF, // MaxAddress // {template}
+ 0x00000000, // Translation
+ 0x10000000, // RangeLength // {template}
+ , // ResourceSourceIndex
+ , // ResourceSource
+ ROOT // DescriptorName
+ ) // QWordMemory
+
+ // The Interrupt information is generated using AmlCodegen.
+ // Interrupt on PMU0 overflow, attached to DTC [0], with GSIV = <gsiv0>.
+ //
+ // Interrupt ( // {codegen}
+ // ResourceConsumer, // ResourceUsage
+ // Level, // EdgeLevel
+ // ActiveHigh, // ActiveLevel
+ // Exclusive, // Shared
+ // , // ResourceSourceIndex
+ // , // ResourceSource
+ // // DescriptorName
+ // ) {
+ // 0xA5 // <gsiv0 >
+ // } // Interrupt
+
+ }) // Name
+ } // Device
+ } // _SB
+} // DefinitionBlock
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortGenerator.c
new file mode 100644
index 00000000..0af74613
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortGenerator.c
@@ -0,0 +1,371 @@
+/** @file
+ SSDT Serial Port Table Generator.
+
+ Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <IndustryStandard/DebugPort2Table.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/SsdtSerialPortFixupLib.h>
+#include <Library/TableHelperLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+/** ARM standard SSDT Serial Port Table Generator
+
+ Constructs SSDT tables describing serial ports (other than the serial ports
+ used by the SPCR or DBG2 tables).
+
+Requirements:
+ The following Configuration Manager Object(s) are required by
+ this Generator:
+ - EArmObjSerialPortInfo
+*/
+
+/** This macro expands to a function that retrieves the Serial-port
+ information from the Configuration Manager.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArm,
+ EArmObjSerialPortInfo,
+ CM_ARM_SERIAL_PORT_INFO
+ );
+
+/** Starting value for the UID to represent the serial ports.
+ Note: The UID 0 and 1 are reserved for use by DBG2 port and SPCR
+ respectively. So, the UIDs for serial ports for general use
+ start at 2.
+*/
+#define SERIAL_PORT_START_UID 2
+
+/** Maximum serial ports supported by this generator.
+ This generator supports a maximum of 14 (16 - 2) serial ports.
+ The -2 here reflects the reservation for serial ports for the DBG2
+ and SPCR ports regardless of whether the DBG2 or SPCR port is enabled.
+ Note: This is not a hard limitation and can be extended if needed.
+ Corresponding changes would be needed to support the Name and
+ UID fields describing the serial port.
+
+*/
+#define MAX_SERIAL_PORTS_SUPPORTED 14
+
+/** Free any resources allocated for constructing the tables.
+
+ @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 an array of pointers
+ to ACPI Table(s).
+ @param [in] TableCount Number of ACPI table(s).
+
+ @retval EFI_SUCCESS The resources were freed successfully.
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FreeSsdtSerialPortTableEx (
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,
+ IN CONST UINTN TableCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+ UINTN Index;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ if ((Table == NULL) ||
+ (*Table == NULL) ||
+ (TableCount == 0)) {
+ DEBUG ((DEBUG_ERROR, "ERROR: SSDT-SERIAL-PORT: Invalid Table Pointer\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TableList = *Table;
+
+ for (Index = 0; Index < TableCount; Index++) {
+ if ((TableList[Index] != NULL) &&
+ (TableList[Index]->Signature ==
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {
+ Status = FreeSsdtSerialPortTable (TableList[Index]);
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT: Could not free SSDT table at index %d."
+ " Status = %r\n",
+ Index,
+ Status
+ ));
+ return Status;
+ }
+ } //for
+
+ // Free the table list.
+ FreePool (*Table);
+
+ return EFI_SUCCESS;
+}
+
+/** Construct SSDT tables describing serial-ports.
+
+ 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 FreeXXXXTableResourcesEx function.
+
+ @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 a list of generated ACPI table(s).
+ @param [out] TableCount Number of generated ACPI table(s).
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
+ Manager is less than the Object size for
+ the requested object.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+ @retval EFI_UNSUPPORTED Unsupported configuration.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+BuildSsdtSerialPortTableEx (
+ IN CONST ACPI_TABLE_GENERATOR * This,
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,
+ OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,
+ OUT UINTN * CONST TableCount
+ )
+{
+ EFI_STATUS Status;
+ CM_ARM_SERIAL_PORT_INFO * SerialPortInfo;
+ UINT32 SerialPortCount;
+ UINTN Index;
+ CHAR8 NewName[5];
+ UINT64 Uid;
+ EFI_ACPI_DESCRIPTION_HEADER ** TableList;
+
+ ASSERT (This != NULL);
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (CfgMgrProtocol != NULL);
+ ASSERT (Table != NULL);
+ ASSERT (TableCount != NULL);
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
+
+ *Table = NULL;
+
+ Status = GetEArmObjSerialPortInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &SerialPortInfo,
+ &SerialPortCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT: Failed to get serial port information."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ if (SerialPortCount > MAX_SERIAL_PORTS_SUPPORTED) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT: Too many serial ports: %d."
+ " Maximum serial ports supported = %d.\n",
+ SerialPortCount,
+ MAX_SERIAL_PORTS_SUPPORTED
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Validate the SerialPort info.
+ Status = ValidateSerialPortInfo (SerialPortInfo, SerialPortCount);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT: Invalid serial port information. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Allocate a table to store pointers to the SSDT tables.
+ TableList = (EFI_ACPI_DESCRIPTION_HEADER**)
+ AllocateZeroPool (
+ (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * SerialPortCount)
+ );
+ if (TableList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT: Failed to allocate memory for Table List."
+ " Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Setup the table list early so that that appropriate cleanup
+ // can be done in case of failure.
+ *Table = TableList;
+
+ NewName[0] = 'C';
+ NewName[1] = 'O';
+ NewName[2] = 'M';
+ NewName[4] = '\0';
+ for (Index = 0; Index < SerialPortCount; Index++) {
+ Uid = SERIAL_PORT_START_UID + Index;
+ NewName[3] = AsciiFromHex ((UINT8)(Uid));
+
+ // Build a SSDT table describing the serial port.
+ Status = BuildSsdtSerialPortTable (
+ AcpiTableInfo,
+ &SerialPortInfo[Index],
+ NewName,
+ Uid,
+ &TableList[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT: Failed to build associated SSDT table."
+ " Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+
+ // Increment the table count here so that appropriate cleanup
+ // can be done in case of failure.
+ *TableCount += 1;
+ } // for
+
+error_handler:
+ // Note: Table list and Serial port count has been setup. The
+ // error handler does nothing here as the framework will invoke
+ // FreeSsdtSerialPortTableEx() even on failure.
+ return Status;
+}
+
+/** This macro defines the SSDT Serial Port Table Generator revision.
+*/
+#define SSDT_SERIAL_GENERATOR_REVISION CREATE_REVISION (1, 0)
+
+/** The interface for the SSDT Serial Port Table Generator.
+*/
+STATIC
+CONST
+ACPI_TABLE_GENERATOR SsdtSerialPortGenerator = {
+ // Generator ID
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtSerialPort),
+ // Generator Description
+ L"ACPI.STD.SSDT.SERIAL.PORT.GENERATOR",
+ // ACPI Table Signature
+ EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
+ // ACPI Table Revision - Unused
+ 0,
+ // Minimum ACPI Table Revision - Unused
+ 0,
+ // Creator ID
+ TABLE_GENERATOR_CREATOR_ID_ARM,
+ // Creator Revision
+ SSDT_SERIAL_GENERATOR_REVISION,
+ // Build table function. Use the extended version instead.
+ NULL,
+ // Free table function. Use the extended version instead.
+ NULL,
+ // Extended Build table function.
+ BuildSsdtSerialPortTableEx,
+ // Extended free function.
+ FreeSsdtSerialPortTableEx
+};
+
+/** 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
+AcpiSsdtSerialPortLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = RegisterAcpiTableGenerator (&SsdtSerialPortGenerator);
+ DEBUG ((
+ DEBUG_INFO,
+ "SSDT-SERIAL-PORT: 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
+AcpiSsdtSerialPortLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE * SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = DeregisterAcpiTableGenerator (&SsdtSerialPortGenerator);
+ DEBUG ((
+ DEBUG_INFO,
+ "SSDT-SERIAL-PORT: Deregister Generator. Status = %r\n",
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortLibArm.inf b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortLibArm.inf
new file mode 100644
index 00000000..36907c79
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortLibArm.inf
@@ -0,0 +1,33 @@
+## @file
+# Ssdt Serial Port Table Generator
+#
+# Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = SsdtSerialPortLibArm
+ FILE_GUID = D1F92325-2DFB-435C-9B4C-A6B864F19230
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = NULL|DXE_DRIVER
+ CONSTRUCTOR = AcpiSsdtSerialPortLibConstructor
+ DESTRUCTOR = AcpiSsdtSerialPortLibDestructor
+
+[Sources]
+ SsdtSerialPortGenerator.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ DynamicTablesPkg/DynamicTablesPkg.dec
+
+[LibraryClasses]
+ AmlLib
+ BaseLib
+ TableHelperLib
+ SsdtSerialPortFixupLib