summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiMadtLibArm/MadtGenerator.c830
1 files changed, 830 insertions, 0 deletions
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;
+}