| /** @file | |
| MADT Table Generator | |
| Copyright (c) 2017 - 2023, Arm Limited. All rights reserved. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| @par Reference(s): | |
| - ACPI 6.5 Specification - Aug 29, 2022 | |
| **/ | |
| #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_5_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. | |
| @param [in] GicRPresent TRUE if MADT also contains any GICR structures. | |
| **/ | |
| STATIC | |
| VOID | |
| AddGICC ( | |
| IN EFI_ACPI_6_5_GIC_STRUCTURE *CONST Gicc, | |
| IN CONST CM_ARM_GICC_INFO *CONST GicCInfo, | |
| IN CONST UINT8 MadtRev, | |
| IN CONST BOOLEAN GicRPresent | |
| ) | |
| { | |
| ASSERT (Gicc != NULL); | |
| ASSERT (GicCInfo != NULL); | |
| // UINT8 Type | |
| Gicc->Type = EFI_ACPI_6_5_GIC; | |
| // UINT8 Length | |
| Gicc->Length = sizeof (EFI_ACPI_6_5_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 | |
| if (!GicRPresent) { | |
| Gicc->GICRBaseAddress = GicCInfo->GICRBaseAddress; | |
| } else { | |
| Gicc->GICRBaseAddress = 0; | |
| } | |
| // 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; | |
| } | |
| // UINT16 TrbeInterrupt | |
| if (MadtRev > EFI_ACPI_6_4_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) { | |
| Gicc->TrbeInterrupt = GicCInfo->TrbeInterrupt; | |
| } | |
| } | |
| /** | |
| 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. | |
| @param [in] GicRPresent TRUE if MADT also contains any GICR | |
| structures. | |
| @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_5_GIC_STRUCTURE *Gicc, | |
| IN CONST CM_ARM_GICC_INFO *GicCInfo, | |
| IN UINT32 GicCCount, | |
| IN CONST UINT8 MadtRev, | |
| IN CONST BOOLEAN GicRPresent | |
| ) | |
| { | |
| 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, GicRPresent); | |
| } | |
| 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_5_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_5_GICD; | |
| // UINT8 Length | |
| Gicd->Length = sizeof (EFI_ACPI_6_5_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_5_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_5_GIC_MSI_FRAME; | |
| GicMsiFrame->Length = sizeof (EFI_ACPI_6_5_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_5_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_5_GICR_STRUCTURE *CONST Gicr, | |
| IN CONST CM_ARM_GIC_REDIST_INFO *CONST GicRedistributorInfo | |
| ) | |
| { | |
| ASSERT (Gicr != NULL); | |
| ASSERT (GicRedistributorInfo != NULL); | |
| Gicr->Type = EFI_ACPI_6_5_GICR; | |
| Gicr->Length = sizeof (EFI_ACPI_6_5_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_5_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_5_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_5_GIC_ITS; | |
| GicIts->Length = sizeof (EFI_ACPI_6_5_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_5_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_5_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_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER); | |
| GicCOffset = TableSize; | |
| TableSize += (sizeof (EFI_ACPI_6_5_GIC_STRUCTURE) * GicCCount); | |
| GicDOffset = TableSize; | |
| TableSize += (sizeof (EFI_ACPI_6_5_GIC_DISTRIBUTOR_STRUCTURE) * GicDCount); | |
| GicMSIOffset = TableSize; | |
| TableSize += (sizeof (EFI_ACPI_6_5_GIC_MSI_FRAME_STRUCTURE) * GicMSICount); | |
| GicRedistOffset = TableSize; | |
| TableSize += (sizeof (EFI_ACPI_6_5_GICR_STRUCTURE) * GicRedistCount); | |
| GicItsOffset = TableSize; | |
| TableSize += (sizeof (EFI_ACPI_6_5_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_5_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_5_GIC_STRUCTURE *)((UINT8 *)Madt + GicCOffset), | |
| GicCInfo, | |
| GicCCount, | |
| Madt->Header.Revision, | |
| GicRedistCount != 0 | |
| ); | |
| 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_5_GIC_DISTRIBUTOR_STRUCTURE *)((UINT8 *)Madt + GicDOffset), | |
| GicDInfo | |
| ); | |
| if (GicMSICount != 0) { | |
| AddGICMsiFrameInfoList ( | |
| (EFI_ACPI_6_5_GIC_MSI_FRAME_STRUCTURE *)((UINT8 *)Madt + GicMSIOffset), | |
| GicMSIInfo, | |
| GicMSICount | |
| ); | |
| } | |
| if (GicRedistCount != 0) { | |
| AddGICRedistributorList ( | |
| (EFI_ACPI_6_5_GICR_STRUCTURE *)((UINT8 *)Madt + GicRedistOffset), | |
| GicRedistInfo, | |
| GicRedistCount | |
| ); | |
| } | |
| if (GicItsCount != 0) { | |
| AddGICItsList ( | |
| (EFI_ACPI_6_5_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); | |
| ASSERT (Table != NULL); | |
| if ((Table == NULL) || (*Table == NULL)) { | |
| DEBUG ((DEBUG_ERROR, "ERROR: MADT: Invalid Table Pointer\n")); | |
| 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_5_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE, | |
| // ACPI Table Revision supported by this Generator | |
| EFI_ACPI_6_5_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; | |
| } |