--- /dev/null
+/** @file\r
+ MADT Table Generator\r
+\r
+ Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+ @par Reference(s):\r
+ - ACPI 6.2 Specification - Errata A, September 2017\r
+\r
+**/\r
+\r
+#include <Library/AcpiLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Protocol/AcpiTable.h>\r
+\r
+// Module specific include files.\r
+#include <AcpiTableGenerator.h>\r
+#include <ConfigurationManagerObject.h>\r
+#include <ConfigurationManagerHelper.h>\r
+#include <Library/TableHelperLib.h>\r
+#include <Protocol/ConfigurationManagerProtocol.h>\r
+\r
+/** ARM standard MADT Generator\r
+\r
+Requirements:\r
+ The following Configuration Manager Object(s) are required by\r
+ this Generator:\r
+ - EArmObjGicCInfo\r
+ - EArmObjGicDInfo\r
+ - EArmObjGicMsiFrameInfo (OPTIONAL)\r
+ - EArmObjGicRedistributorInfo (OPTIONAL)\r
+ - EArmObjGicItsInfo (OPTIONAL)\r
+*/\r
+\r
+/** This macro expands to a function that retrieves the GIC\r
+ CPU interface Information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjGicCInfo,\r
+ CM_ARM_GICC_INFO\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the GIC\r
+ Distributor Information from the Configuration Manager.\r
+*/\r
+\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjGicDInfo,\r
+ CM_ARM_GICD_INFO\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the GIC\r
+ MSI Frame Information from the Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjGicMsiFrameInfo,\r
+ CM_ARM_GIC_MSI_FRAME_INFO\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the GIC\r
+ Redistributor Information from the Configuration Manager.\r
+*/\r
+\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjGicRedistributorInfo,\r
+ CM_ARM_GIC_REDIST_INFO\r
+ );\r
+\r
+/** This macro expands to a function that retrieves the GIC\r
+ Interrupt Translation Service Information from the\r
+ Configuration Manager.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjGicItsInfo,\r
+ CM_ARM_GIC_ITS_INFO\r
+ );\r
+\r
+/** This function updates the GIC CPU Interface Information in the\r
+ EFI_ACPI_6_2_GIC_STRUCTURE structure.\r
+\r
+ @param [in] Gicc Pointer to GIC CPU Interface structure.\r
+ @param [in] GicCInfo Pointer to the GIC CPU Interface Information.\r
+**/\r
+STATIC\r
+VOID\r
+AddGICC (\r
+ IN EFI_ACPI_6_2_GIC_STRUCTURE * CONST Gicc,\r
+ IN CONST CM_ARM_GICC_INFO * CONST GicCInfo\r
+ )\r
+{\r
+ ASSERT (Gicc != NULL);\r
+ ASSERT (GicCInfo != NULL);\r
+\r
+ // UINT8 Type\r
+ Gicc->Type = EFI_ACPI_6_2_GIC;\r
+ // UINT8 Length\r
+ Gicc->Length = sizeof (EFI_ACPI_6_2_GIC_STRUCTURE);\r
+ // UINT16 Reserved\r
+ Gicc->Reserved = EFI_ACPI_RESERVED_WORD;\r
+\r
+ // UINT32 CPUInterfaceNumber\r
+ Gicc->CPUInterfaceNumber = GicCInfo->CPUInterfaceNumber;\r
+ // UINT32 AcpiProcessorUid\r
+ Gicc->AcpiProcessorUid = GicCInfo->AcpiProcessorUid;\r
+ // UINT32 Flags\r
+ Gicc->Flags = GicCInfo->Flags;\r
+ // UINT32 ParkingProtocolVersion\r
+ Gicc->ParkingProtocolVersion = GicCInfo->ParkingProtocolVersion;\r
+ // UINT32 PerformanceInterruptGsiv\r
+ Gicc->PerformanceInterruptGsiv = GicCInfo->PerformanceInterruptGsiv;\r
+ // UINT64 ParkedAddress\r
+ Gicc->ParkedAddress = GicCInfo->ParkedAddress;\r
+\r
+ // UINT64 PhysicalBaseAddress\r
+ Gicc->PhysicalBaseAddress = GicCInfo->PhysicalBaseAddress;\r
+ // UINT64 GICV\r
+ Gicc->GICV = GicCInfo->GICV;\r
+ // UINT64 GICH\r
+ Gicc->GICH = GicCInfo->GICH;\r
+\r
+ // UINT32 VGICMaintenanceInterrupt\r
+ Gicc->VGICMaintenanceInterrupt = GicCInfo->VGICMaintenanceInterrupt;\r
+ // UINT64 GICRBaseAddress\r
+ Gicc->GICRBaseAddress = GicCInfo->GICRBaseAddress;\r
+\r
+ // UINT64 MPIDR\r
+ Gicc->MPIDR = GicCInfo->MPIDR;\r
+ // UINT8 ProcessorPowerEfficiencyClass\r
+ Gicc->ProcessorPowerEfficiencyClass =\r
+ GicCInfo->ProcessorPowerEfficiencyClass;\r
+ // UINT8 Reserved2[3]\r
+ Gicc->Reserved2[0] = EFI_ACPI_RESERVED_BYTE;\r
+ Gicc->Reserved2[1] = EFI_ACPI_RESERVED_BYTE;\r
+ Gicc->Reserved2[2] = EFI_ACPI_RESERVED_BYTE;\r
+}\r
+\r
+/** Add the GIC CPU Interface Information to the MADT Table.\r
+\r
+ @param [in] Gicc Pointer to GIC CPU Interface\r
+ structure list.\r
+ @param [in] GicCInfo Pointer to the GIC CPU\r
+ Information list.\r
+ @param [in] GicCCount Count of GIC CPU Interfaces.\r
+**/\r
+STATIC\r
+VOID\r
+AddGICCList (\r
+ IN EFI_ACPI_6_2_GIC_STRUCTURE * Gicc,\r
+ IN CONST CM_ARM_GICC_INFO * GicCInfo,\r
+ IN UINT32 GicCCount\r
+ )\r
+{\r
+ ASSERT (Gicc != NULL);\r
+ ASSERT (GicCInfo != NULL);\r
+\r
+ while (GicCCount-- != 0) {\r
+ AddGICC (Gicc++, GicCInfo++);\r
+ }\r
+}\r
+\r
+/** Update the GIC Distributor Information in the MADT Table.\r
+\r
+ @param [in] Gicd Pointer to GIC Distributor structure.\r
+ @param [in] GicDInfo Pointer to the GIC Distributor Information.\r
+**/\r
+STATIC\r
+VOID\r
+AddGICD (\r
+ EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE * CONST Gicd,\r
+ CONST CM_ARM_GICD_INFO * CONST GicDInfo\r
+)\r
+{\r
+ ASSERT (Gicd != NULL);\r
+ ASSERT (GicDInfo != NULL);\r
+\r
+ // UINT8 Type\r
+ Gicd->Type = EFI_ACPI_6_2_GICD;\r
+ // UINT8 Length\r
+ Gicd->Length = sizeof (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE);\r
+ // UINT16 Reserved\r
+ Gicd->Reserved1 = EFI_ACPI_RESERVED_WORD;\r
+ // UINT32 Identifier\r
+ Gicd->GicId = GicDInfo->GicId;\r
+ // UINT64 PhysicalBaseAddress\r
+ Gicd->PhysicalBaseAddress = GicDInfo->PhysicalBaseAddress;\r
+ // UINT32 VectorBase\r
+ Gicd->SystemVectorBase = EFI_ACPI_RESERVED_DWORD;\r
+ // UINT8 GicVersion\r
+ Gicd->GicVersion = GicDInfo->GicVersion;\r
+ // UINT8 Reserved2[3]\r
+ Gicd->Reserved2[0] = EFI_ACPI_RESERVED_BYTE;\r
+ Gicd->Reserved2[1] = EFI_ACPI_RESERVED_BYTE;\r
+ Gicd->Reserved2[2] = EFI_ACPI_RESERVED_BYTE;\r
+}\r
+\r
+/** Update the GIC MSI Frame Information.\r
+\r
+ @param [in] GicMsiFrame Pointer to GIC MSI Frame structure.\r
+ @param [in] GicMsiFrameInfo Pointer to the GIC MSI Frame Information.\r
+**/\r
+STATIC\r
+VOID\r
+AddGICMsiFrame (\r
+ IN EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE * CONST GicMsiFrame,\r
+ IN CONST CM_ARM_GIC_MSI_FRAME_INFO * CONST GicMsiFrameInfo\r
+)\r
+{\r
+ ASSERT (GicMsiFrame != NULL);\r
+ ASSERT (GicMsiFrameInfo != NULL);\r
+\r
+ GicMsiFrame->Type = EFI_ACPI_6_2_GIC_MSI_FRAME;\r
+ GicMsiFrame->Length = sizeof (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE);\r
+ GicMsiFrame->Reserved1 = EFI_ACPI_RESERVED_WORD;\r
+ GicMsiFrame->GicMsiFrameId = GicMsiFrameInfo->GicMsiFrameId;\r
+ GicMsiFrame->PhysicalBaseAddress = GicMsiFrameInfo->PhysicalBaseAddress;\r
+\r
+ GicMsiFrame->Flags = GicMsiFrameInfo->Flags;\r
+ GicMsiFrame->SPICount = GicMsiFrameInfo->SPICount;\r
+ GicMsiFrame->SPIBase = GicMsiFrameInfo->SPIBase;\r
+}\r
+\r
+/** Add the GIC MSI Frame Information to the MADT Table.\r
+\r
+ @param [in] GicMsiFrame Pointer to GIC MSI Frame structure list.\r
+ @param [in] GicMsiFrameInfo Pointer to the GIC MSI Frame info list.\r
+ @param [in] GicMsiFrameCount Count of GIC MSI Frames.\r
+**/\r
+STATIC\r
+VOID\r
+AddGICMsiFrameInfoList (\r
+ IN EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE * GicMsiFrame,\r
+ IN CONST CM_ARM_GIC_MSI_FRAME_INFO * GicMsiFrameInfo,\r
+ IN UINT32 GicMsiFrameCount\r
+)\r
+{\r
+ ASSERT (GicMsiFrame != NULL);\r
+ ASSERT (GicMsiFrameInfo != NULL);\r
+\r
+ while (GicMsiFrameCount-- != 0) {\r
+ AddGICMsiFrame (GicMsiFrame++, GicMsiFrameInfo++);\r
+ }\r
+}\r
+\r
+/** Update the GIC Redistributor Information.\r
+\r
+ @param [in] Gicr Pointer to GIC Redistributor structure.\r
+ @param [in] GicRedisributorInfo Pointer to the GIC Redistributor Info.\r
+**/\r
+STATIC\r
+VOID\r
+AddGICRedistributor (\r
+ IN EFI_ACPI_6_2_GICR_STRUCTURE * CONST Gicr,\r
+ IN CONST CM_ARM_GIC_REDIST_INFO * CONST GicRedisributorInfo\r
+ )\r
+{\r
+ ASSERT (Gicr != NULL);\r
+ ASSERT (GicRedisributorInfo != NULL);\r
+\r
+ Gicr->Type = EFI_ACPI_6_2_GICR;\r
+ Gicr->Length = sizeof (EFI_ACPI_6_2_GICR_STRUCTURE);\r
+ Gicr->Reserved = EFI_ACPI_RESERVED_WORD;\r
+ Gicr->DiscoveryRangeBaseAddress =\r
+ GicRedisributorInfo->DiscoveryRangeBaseAddress;\r
+ Gicr->DiscoveryRangeLength = GicRedisributorInfo->DiscoveryRangeLength;\r
+}\r
+\r
+/** Add the GIC Redistributor Information to the MADT Table.\r
+\r
+ @param [in] Gicr Pointer to GIC Redistributor structure list.\r
+ @param [in] GicRInfo Pointer to the GIC Distributor info list.\r
+ @param [in] GicRCount Count of GIC Distributors.\r
+**/\r
+STATIC\r
+VOID\r
+AddGICRedistributorList (\r
+ IN EFI_ACPI_6_2_GICR_STRUCTURE * Gicr,\r
+ IN CONST CM_ARM_GIC_REDIST_INFO * GicRInfo,\r
+ IN UINT32 GicRCount\r
+)\r
+{\r
+ ASSERT (Gicr != NULL);\r
+ ASSERT (GicRInfo != NULL);\r
+\r
+ while (GicRCount-- != 0) {\r
+ AddGICRedistributor (Gicr++, GicRInfo++);\r
+ }\r
+}\r
+\r
+/** Update the GIC Interrupt Translation Service Information\r
+\r
+ @param [in] GicIts Pointer to GIC ITS structure.\r
+ @param [in] GicItsInfo Pointer to the GIC ITS Information.\r
+**/\r
+STATIC\r
+VOID\r
+AddGICInterruptTranslationService (\r
+ IN EFI_ACPI_6_2_GIC_ITS_STRUCTURE * CONST GicIts,\r
+ IN CONST CM_ARM_GIC_ITS_INFO * CONST GicItsInfo\r
+)\r
+{\r
+ ASSERT (GicIts != NULL);\r
+ ASSERT (GicItsInfo != NULL);\r
+\r
+ GicIts->Type = EFI_ACPI_6_2_GIC_ITS;\r
+ GicIts->Length = sizeof (EFI_ACPI_6_2_GIC_ITS_STRUCTURE);\r
+ GicIts->Reserved = EFI_ACPI_RESERVED_WORD;\r
+ GicIts->GicItsId = GicItsInfo->GicItsId;\r
+ GicIts->PhysicalBaseAddress = GicItsInfo->PhysicalBaseAddress;\r
+ GicIts->Reserved2 = EFI_ACPI_RESERVED_DWORD;\r
+}\r
+\r
+/** Add the GIC Interrupt Translation Service Information\r
+ to the MADT Table.\r
+\r
+ @param [in] GicIts Pointer to GIC ITS structure list.\r
+ @param [in] GicItsInfo Pointer to the GIC ITS list.\r
+ @param [in] GicItsCount Count of GIC ITS.\r
+**/\r
+STATIC\r
+VOID\r
+AddGICItsList (\r
+ IN EFI_ACPI_6_2_GIC_ITS_STRUCTURE * GicIts,\r
+ IN CONST CM_ARM_GIC_ITS_INFO * GicItsInfo,\r
+ IN UINT32 GicItsCount\r
+)\r
+{\r
+ ASSERT (GicIts != NULL);\r
+ ASSERT (GicItsInfo != NULL);\r
+\r
+ while (GicItsCount-- != 0) {\r
+ AddGICInterruptTranslationService (GicIts++, GicItsInfo++);\r
+ }\r
+}\r
+\r
+/** Construct the MADT ACPI table.\r
+\r
+ This function invokes the Configuration Manager protocol interface\r
+ to get the required hardware information for generating the ACPI\r
+ table.\r
+\r
+ If this function allocates any resources then they must be freed\r
+ in the FreeXXXXTableResources function.\r
+\r
+ @param [in] This Pointer to the table generator.\r
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [out] Table Pointer to the constructed ACPI Table.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
+ Manager is less than the Object size for the\r
+ requested object.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+BuildMadtTable (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 TableSize;\r
+ UINT32 GicCCount;\r
+ UINT32 GicDCount;\r
+ UINT32 GicMSICount;\r
+ UINT32 GicRedistCount;\r
+ UINT32 GicItsCount;\r
+ CM_ARM_GICC_INFO * GicCInfo;\r
+ CM_ARM_GICD_INFO * GicDInfo;\r
+ CM_ARM_GIC_MSI_FRAME_INFO * GicMSIInfo;\r
+ CM_ARM_GIC_REDIST_INFO * GicRedistInfo;\r
+ CM_ARM_GIC_ITS_INFO * GicItsInfo;\r
+ UINT32 GicCOffset;\r
+ UINT32 GicDOffset;\r
+ UINT32 GicMSIOffset;\r
+ UINT32 GicRedistOffset;\r
+ UINT32 GicItsOffset;\r
+\r
+ EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER * Madt;\r
+\r
+ ASSERT (This != NULL);\r
+ ASSERT (AcpiTableInfo != NULL);\r
+ ASSERT (CfgMgrProtocol != NULL);\r
+ ASSERT (Table != NULL);\r
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
+\r
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||\r
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: Requested table revision = %d, is not supported."\r
+ "Supported table revision: Minimum = %d, Maximum = %d\n",\r
+ AcpiTableInfo->AcpiTableRevision,\r
+ This->MinAcpiTableRevision,\r
+ This->AcpiTableRevision\r
+ ));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Table = NULL;\r
+\r
+ Status = GetEArmObjGicCInfo (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &GicCInfo,\r
+ &GicCCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: Failed to get GICC Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ if (GicCCount == 0) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: GIC CPU Interface information not provided.\n"\r
+ ));\r
+ ASSERT (GicCCount != 0);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = GetEArmObjGicDInfo (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &GicDInfo,\r
+ &GicDCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: Failed to get GICD Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ if (GicDCount == 0) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: GIC Distributor information not provided.\n"\r
+ ));\r
+ ASSERT (GicDCount != 0);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto error_handler;\r
+ }\r
+\r
+ if (GicDCount > 1) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: One, and only one, GIC distributor must be present."\r
+ "GicDCount = %d\n",\r
+ GicDCount\r
+ ));\r
+ ASSERT (GicDCount <= 1);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = GetEArmObjGicMsiFrameInfo (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &GicMSIInfo,\r
+ &GicMSICount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: Failed to get GIC MSI Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = GetEArmObjGicRedistributorInfo (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &GicRedistInfo,\r
+ &GicRedistCount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: Failed to get GIC Redistributor Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = GetEArmObjGicItsInfo (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &GicItsInfo,\r
+ &GicItsCount\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: Failed to get GIC ITS Info. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ TableSize = sizeof (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER);\r
+\r
+ GicCOffset = TableSize;\r
+ TableSize += (sizeof (EFI_ACPI_6_2_GIC_STRUCTURE) * GicCCount);\r
+\r
+ GicDOffset = TableSize;\r
+ TableSize += (sizeof (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE) * GicDCount);\r
+\r
+ GicMSIOffset = TableSize;\r
+ TableSize += (sizeof (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE) * GicMSICount);\r
+\r
+ GicRedistOffset = TableSize;\r
+ TableSize += (sizeof (EFI_ACPI_6_2_GICR_STRUCTURE) * GicRedistCount);\r
+\r
+ GicItsOffset = TableSize;\r
+ TableSize += (sizeof (EFI_ACPI_6_2_GIC_ITS_STRUCTURE) * GicItsCount);\r
+\r
+ // Allocate the Buffer for MADT table\r
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);\r
+ if (*Table == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: Failed to allocate memory for MADT Table, Size = %d," \\r
+ " Status = %r\n",\r
+ TableSize,\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ Madt = (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER*)*Table;\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "MADT: Madt = 0x%p TableSize = 0x%x\n",\r
+ Madt,\r
+ TableSize\r
+ ));\r
+\r
+ Status = AddAcpiHeader (\r
+ CfgMgrProtocol,\r
+ This,\r
+ &Madt->Header,\r
+ AcpiTableInfo->AcpiTableRevision,\r
+ TableSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MADT: Failed to add ACPI header. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ AddGICCList (\r
+ (EFI_ACPI_6_2_GIC_STRUCTURE*)((UINT8*)Madt + GicCOffset),\r
+ GicCInfo,\r
+ GicCCount\r
+ );\r
+\r
+ AddGICD (\r
+ (EFI_ACPI_6_2_GIC_DISTRIBUTOR_STRUCTURE*)((UINT8*)Madt + GicDOffset),\r
+ GicDInfo\r
+ );\r
+\r
+ if (GicMSICount != 0) {\r
+ AddGICMsiFrameInfoList (\r
+ (EFI_ACPI_6_2_GIC_MSI_FRAME_STRUCTURE*)((UINT8*)Madt + GicMSIOffset),\r
+ GicMSIInfo,\r
+ GicMSICount\r
+ );\r
+ }\r
+\r
+ if (GicRedistCount != 0) {\r
+ AddGICRedistributorList (\r
+ (EFI_ACPI_6_2_GICR_STRUCTURE*)((UINT8*)Madt + GicRedistOffset),\r
+ GicRedistInfo,\r
+ GicRedistCount\r
+ );\r
+ }\r
+\r
+ if (GicItsCount != 0) {\r
+ AddGICItsList (\r
+ (EFI_ACPI_6_2_GIC_ITS_STRUCTURE*)((UINT8*)Madt + GicItsOffset),\r
+ GicItsInfo,\r
+ GicItsCount\r
+ );\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+error_handler:\r
+ if (*Table != NULL) {\r
+ FreePool (*Table);\r
+ *Table = NULL;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/** Free any resources allocated for constructing the MADT\r
+\r
+ @param [in] This Pointer to the table generator.\r
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in, out] Table Pointer to the ACPI Table.\r
+\r
+ @retval EFI_SUCCESS The resources were freed successfully.\r
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+FreeMadtTableResources (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
+ )\r
+{\r
+ ASSERT (This != NULL);\r
+ ASSERT (AcpiTableInfo != NULL);\r
+ ASSERT (CfgMgrProtocol != NULL);\r
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
+\r
+ if ((Table == NULL) || (*Table == NULL)) {\r
+ DEBUG ((DEBUG_ERROR, "ERROR: MADT: Invalid Table Pointer\n"));\r
+ ASSERT ((Table != NULL) && (*Table != NULL));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FreePool (*Table);\r
+ *Table = NULL;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** The MADT Table Generator revision.\r
+*/\r
+#define MADT_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
+\r
+/** The interface for the MADT Table Generator.\r
+*/\r
+STATIC\r
+CONST\r
+ACPI_TABLE_GENERATOR MadtGenerator = {\r
+ // Generator ID\r
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdMadt),\r
+ // Generator Description\r
+ L"ACPI.STD.MADT.GENERATOR",\r
+ // ACPI Table Signature\r
+ EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,\r
+ // ACPI Table Revision supported by this Generator\r
+ EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,\r
+ // Minimum supported ACPI Table Revision\r
+ EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,\r
+ // Creator ID\r
+ TABLE_GENERATOR_CREATOR_ID_ARM,\r
+ // Creator Revision\r
+ MADT_GENERATOR_REVISION,\r
+ // Build Table function\r
+ BuildMadtTable,\r
+ // Free Resource function\r
+ FreeMadtTableResources,\r
+ // Extended build function not needed\r
+ NULL,\r
+ // Extended build function not implemented by the generator.\r
+ // Hence extended free resource function is not required.\r
+ NULL\r
+};\r
+\r
+/** Register the Generator with the ACPI Table Factory.\r
+\r
+ @param [in] ImageHandle The handle to the image.\r
+ @param [in] SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS The Generator is registered.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
+ is already registered.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AcpiMadtLibConstructor (\r
+ IN CONST EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE * CONST SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ Status = RegisterAcpiTableGenerator (&MadtGenerator);\r
+ DEBUG ((DEBUG_INFO, "MADT: Register Generator. Status = %r\n", Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r
+\r
+/** Deregister the Generator from the ACPI Table Factory.\r
+\r
+ @param [in] ImageHandle The handle to the image.\r
+ @param [in] SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS The Generator is deregistered.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The Generator is not registered.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AcpiMadtLibDestructor (\r
+ IN CONST EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE * CONST SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ Status = DeregisterAcpiTableGenerator (&MadtGenerator);\r
+ DEBUG ((DEBUG_INFO, "MADT: Deregister Generator. Status = %r\n", Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r