| /** @file | |
| MADT Table Generator for RISC-V | |
| Copyright (c) 2024, Ventana Micro Systems Inc. All rights reserved. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| @par Reference(s): | |
| - TBD - ACPI 6.6 Specification | |
| **/ | |
| #include <IndustryStandard/Acpi.h> | |
| #include <Library/AcpiHelperLib.h> | |
| #include <Library/AcpiLib.h> | |
| #include <Library/BaseMemoryLib.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> | |
| /** RISC-V standard MADT Generator | |
| Requirements: | |
| The following Configuration Manager Object(s) are required by | |
| this Generator: | |
| - ERiscVObjRintcInfo | |
| - ERiscVObjImsicInfo (OPTIONAL) | |
| - ERiscVObjAplicInfo (OPTIONAL) | |
| - ERiscVObjPlicInfo (OPTIONAL) | |
| */ | |
| /** This macro expands to a function that retrieves the RINTC | |
| Information from the Configuration Manager. | |
| */ | |
| GET_OBJECT_LIST ( | |
| EObjNameSpaceRiscV, | |
| ERiscVObjRintcInfo, | |
| CM_RISCV_RINTC_INFO | |
| ); | |
| /** This macro expands to a function that retrieves the IMSIC | |
| Information from the Configuration Manager. | |
| */ | |
| GET_OBJECT_LIST ( | |
| EObjNameSpaceRiscV, | |
| ERiscVObjImsicInfo, | |
| CM_RISCV_IMSIC_INFO | |
| ); | |
| /** This macro expands to a function that retrieves the APLIC | |
| Information from the Configuration Manager. | |
| */ | |
| GET_OBJECT_LIST ( | |
| EObjNameSpaceRiscV, | |
| ERiscVObjAplicInfo, | |
| CM_RISCV_APLIC_INFO | |
| ); | |
| /** This macro expands to a function that retrieves the PLIC | |
| Information from the Configuration Manager. | |
| */ | |
| GET_OBJECT_LIST ( | |
| EObjNameSpaceRiscV, | |
| ERiscVObjPlicInfo, | |
| CM_RISCV_PLIC_INFO | |
| ); | |
| /** This function updates the RINTC Information in the | |
| EFI_ACPI_6_6_RINTC_STRUCTURE structure. | |
| @param [in] Rintc Pointer to RINTC structure. | |
| @param [in] RintcInfo Pointer to the RINTC Information. | |
| **/ | |
| STATIC | |
| VOID | |
| AddRINTC ( | |
| IN EFI_ACPI_6_6_RINTC_STRUCTURE *CONST Rintc, | |
| IN CONST CM_RISCV_RINTC_INFO *CONST RintcInfo | |
| ) | |
| { | |
| ASSERT (Rintc != NULL); | |
| ASSERT (RintcInfo != NULL); | |
| // UINT8 Type | |
| Rintc->Type = EFI_ACPI_6_6_RINTC; | |
| // UINT8 Length | |
| Rintc->Length = sizeof (EFI_ACPI_6_6_RINTC_STRUCTURE); | |
| // UINT8 Version | |
| Rintc->Version = EFI_ACPI_6_6_RINTC_STRUCTURE_VERSION; | |
| // UINT8 Reserved | |
| Rintc->Reserved = EFI_ACPI_RESERVED_BYTE; | |
| ASSERT ((RintcInfo->Flags & ~(UINT32)(EFI_ACPI_6_6_RINTC_FLAG_ENABLE)) == 0); | |
| // UINT32 Flags | |
| Rintc->Flags = RintcInfo->Flags; | |
| // UINT64 HartID | |
| Rintc->HartId = RintcInfo->HartId; | |
| // UINT32 AcpiProcessorUid | |
| Rintc->Uid = RintcInfo->AcpiProcessorUid; | |
| // UINT32 ExtIntcId | |
| Rintc->ExtIntcId = RintcInfo->ExtIntcId; | |
| // UINT64 ImsicBaseAddress | |
| Rintc->ImsicAddr = RintcInfo->ImsicBaseAddress; | |
| // UINT32 ImsicSize | |
| Rintc->ImsicSize = RintcInfo->ImsicSize; | |
| } | |
| /** | |
| Function to test if two RINTC information structures have the | |
| same ACPI Processor UID. | |
| @param [in] RintcInfo1 Pointer to the first RINTC info structure. | |
| @param [in] RintcInfo2 Pointer to the second RINTC info structure. | |
| @param [in] Index1 Index of RintcInfo1 in the shared list of RINTC | |
| Info structures. | |
| @param [in] Index2 Index of RintcInfo2 in the shared list of RINTC | |
| Info structures. | |
| @retval TRUE RintcInfo1 and RintcInfo2 have the same UID. | |
| @retval FALSE RintcInfo1 and RintcInfo2 have different UIDs. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| IsAcpiUidEqual ( | |
| IN CONST VOID *RintcInfo1, | |
| IN CONST VOID *RintcInfo2, | |
| IN UINTN Index1, | |
| IN UINTN Index2 | |
| ) | |
| { | |
| UINT32 Uid1; | |
| UINT32 Uid2; | |
| ASSERT (RintcInfo1 != NULL); | |
| ASSERT (RintcInfo2 != NULL); | |
| Uid1 = ((CM_RISCV_RINTC_INFO *)RintcInfo1)->AcpiProcessorUid; | |
| Uid2 = ((CM_RISCV_RINTC_INFO *)RintcInfo2)->AcpiProcessorUid; | |
| if (Uid1 == Uid2) { | |
| DEBUG ( | |
| ( | |
| DEBUG_ERROR, | |
| "ERROR: MADT: RINTC Info Structures %d and %d have the same ACPI " \ | |
| "Processor UID: 0x%x.\n", | |
| Index1, | |
| Index2, | |
| Uid1 | |
| ) | |
| ); | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| /** Add the RINTC Information to the MADT Table. | |
| This function also checks for duplicate ACPI Processor UIDs. | |
| @param [in] Rintc Pointer to RINTC structure list. | |
| @param [in] RintcInfo Pointer to the RINTC Information list. | |
| @param [in] RintcCount Count of RINTC. | |
| @retval EFI_SUCCESS RINTC Information was added successfully. | |
| @retval EFI_INVALID_PARAMETER One or more invalid RINTC Info values were | |
| provided and the generator failed to add the | |
| information to the table. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| AddRINTCList ( | |
| IN EFI_ACPI_6_6_RINTC_STRUCTURE *Rintc, | |
| IN CONST CM_RISCV_RINTC_INFO *RintcInfo, | |
| IN UINT32 RintcCount | |
| ) | |
| { | |
| BOOLEAN IsAcpiProcUidDuplicated; | |
| ASSERT (Rintc != NULL); | |
| ASSERT (RintcInfo != NULL); | |
| IsAcpiProcUidDuplicated = FindDuplicateValue ( | |
| RintcInfo, | |
| RintcCount, | |
| sizeof (CM_RISCV_RINTC_INFO), | |
| IsAcpiUidEqual | |
| ); | |
| // Duplicate ACPI Processor UID was found so the RINTC info provided | |
| // is invalid | |
| if (IsAcpiProcUidDuplicated) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| while (RintcCount-- != 0) { | |
| AddRINTC (Rintc++, RintcInfo++); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** Update the IMSIC Information in the MADT Table. | |
| @param [in] Imsic Pointer to IMSIC structure. | |
| @param [in] ImsicInfo Pointer to the IMSIC Information. | |
| **/ | |
| STATIC | |
| VOID | |
| AddIMSIC ( | |
| EFI_ACPI_6_6_IMSIC_STRUCTURE *CONST Imsic, | |
| CONST CM_RISCV_IMSIC_INFO *CONST ImsicInfo | |
| ) | |
| { | |
| ASSERT (Imsic != NULL); | |
| ASSERT (ImsicInfo != NULL); | |
| // UINT8 Type | |
| Imsic->Type = EFI_ACPI_6_6_IMSIC; | |
| // UINT8 Length | |
| Imsic->Length = sizeof (EFI_ACPI_6_6_IMSIC_STRUCTURE); | |
| // UINT8 Version | |
| Imsic->Version = EFI_ACPI_6_6_IMSIC_STRUCTURE_VERSION; | |
| // UINT8 Reserved | |
| Imsic->Reserved = EFI_ACPI_RESERVED_BYTE; | |
| // UINT32 Flags | |
| Imsic->Flags = ImsicInfo->Flags; | |
| // UINT16 NumIds | |
| ASSERT ( | |
| ((ImsicInfo->NumIds >= IMSIC_MIN_NUM_IDS) && | |
| (ImsicInfo->NumIds <= IMSIC_MAX_NUM_IDS) && | |
| ((ImsicInfo->NumIds + 1) % 64 == 0)) | |
| ); | |
| Imsic->NumIds = ImsicInfo->NumIds; | |
| // UINT16 NumGuestIds | |
| ASSERT ( | |
| ((ImsicInfo->NumGuestIds >= IMSIC_MIN_NUM_GUEST_IDS) && | |
| (ImsicInfo->NumGuestIds <= IMSIC_MAX_NUM_GUEST_IDS) && | |
| ((ImsicInfo->NumGuestIds + 1) % 64 == 0)) | |
| ); | |
| Imsic->NumGuestIds = ImsicInfo->NumGuestIds; | |
| // UINT8 GuestIndexBits | |
| ASSERT ( | |
| ImsicInfo->GuestIndexBits >= IMSIC_MIN_GUEST_INDEX_BITS && | |
| ImsicInfo->GuestIndexBits <= IMSIC_MAX_GUEST_INDEX_BITS | |
| ); | |
| Imsic->GuestIndexBits = ImsicInfo->GuestIndexBits; | |
| // UINT8 HartIndexBits | |
| ASSERT ( | |
| ImsicInfo->HartIndexBits >= IMSIC_MIN_HART_INDEX_BITS && | |
| ImsicInfo->HartIndexBits <= IMSIC_MAX_HART_INDEX_BITS | |
| ); | |
| Imsic->HartIndexBits = ImsicInfo->HartIndexBits; | |
| // UINT8 GroupIndexBits | |
| ASSERT ( | |
| ImsicInfo->GroupIndexBits >= IMSIC_MIN_GROUP_INDEX_BITS && | |
| ImsicInfo->GroupIndexBits <= IMSIC_MAX_GROUP_INDEX_BITS | |
| ); | |
| Imsic->GroupIndexBits = ImsicInfo->GroupIndexBits; | |
| // UINT8 GroupIndexShift | |
| ASSERT ( | |
| ImsicInfo->GroupIndexShift >= IMSIC_MIN_GROUP_INDEX_SHIFT && | |
| ImsicInfo->GroupIndexShift <= IMSIC_MAX_GROUP_INDEX_SHIFT | |
| ); | |
| Imsic->GroupIndexShift = ImsicInfo->GroupIndexShift; | |
| } | |
| /** Update the APLIC Information. | |
| @param [in] Aplic Pointer to APLIC structure. | |
| @param [in] AplicInfo Pointer to the APLIC Info. | |
| **/ | |
| STATIC | |
| VOID | |
| AddAPLIC ( | |
| IN EFI_ACPI_6_6_APLIC_STRUCTURE *CONST Aplic, | |
| IN CONST CM_RISCV_APLIC_INFO *CONST AplicInfo | |
| ) | |
| { | |
| ASSERT (Aplic != NULL); | |
| ASSERT (AplicInfo != NULL); | |
| Aplic->Type = EFI_ACPI_6_6_APLIC; | |
| Aplic->Length = sizeof (EFI_ACPI_6_6_APLIC_STRUCTURE); | |
| Aplic->Version = EFI_ACPI_6_6_APLIC_STRUCTURE_VERSION; | |
| Aplic->Id = AplicInfo->PlicAplicCommonInfo.Id; | |
| Aplic->Flags = AplicInfo->PlicAplicCommonInfo.Flags; | |
| CopyMem (&Aplic->HwId, &AplicInfo->PlicAplicCommonInfo.Hid, RISCV_HWID_LENGTH); | |
| ASSERT (IsValidAcpiId ((CHAR8 *)Aplic->HwId) != 0); | |
| Aplic->NumIdcs = AplicInfo->NumIdcs; | |
| Aplic->NumSources = AplicInfo->PlicAplicCommonInfo.NumSources; | |
| Aplic->GsiBase = AplicInfo->PlicAplicCommonInfo.GsiBase; | |
| Aplic->BaseAddr = AplicInfo->PlicAplicCommonInfo.BaseAddress; | |
| Aplic->Size = AplicInfo->PlicAplicCommonInfo.Size; | |
| } | |
| /** Add the APLIC Information to the MADT Table. | |
| @param [in] Aplic Pointer to APLIC structure list. | |
| @param [in] AplicInfo Pointer to the APLIC info list. | |
| @param [in] AplicCount Count of APLICs. | |
| **/ | |
| STATIC | |
| VOID | |
| AddAPLICList ( | |
| IN EFI_ACPI_6_6_APLIC_STRUCTURE *Aplic, | |
| IN CONST CM_RISCV_APLIC_INFO *AplicInfo, | |
| IN UINT32 AplicCount | |
| ) | |
| { | |
| ASSERT (Aplic != NULL); | |
| ASSERT (AplicInfo != NULL); | |
| while (AplicCount-- != 0) { | |
| AddAPLIC (Aplic++, AplicInfo++); | |
| } | |
| } | |
| /** Update the PLIC Information. | |
| @param [in] Plic Pointer to PLIC structure. | |
| @param [in] PlicInfo Pointer to the PLIC Info. | |
| **/ | |
| STATIC | |
| VOID | |
| AddPLIC ( | |
| IN EFI_ACPI_6_6_PLIC_STRUCTURE *CONST Plic, | |
| IN CONST CM_RISCV_PLIC_INFO *CONST PlicInfo | |
| ) | |
| { | |
| ASSERT (Plic != NULL); | |
| ASSERT (PlicInfo != NULL); | |
| Plic->Type = EFI_ACPI_6_6_PLIC; | |
| Plic->Length = sizeof (EFI_ACPI_6_6_PLIC_STRUCTURE); | |
| Plic->Version = EFI_ACPI_6_6_PLIC_STRUCTURE_VERSION; | |
| Plic->Id = PlicInfo->PlicAplicCommonInfo.Id; | |
| CopyMem (&Plic->HwId, &PlicInfo->PlicAplicCommonInfo.Hid, RISCV_HWID_LENGTH); | |
| ASSERT (IsValidAcpiId ((CHAR8 *)Plic->HwId) != 0); | |
| Plic->NumIrqs = PlicInfo->PlicAplicCommonInfo.NumSources; | |
| Plic->MaxPrio = PlicInfo->MaxPriority; | |
| Plic->Flags = PlicInfo->PlicAplicCommonInfo.Flags; | |
| Plic->Size = PlicInfo->PlicAplicCommonInfo.Size; | |
| Plic->BaseAddr = PlicInfo->PlicAplicCommonInfo.BaseAddress; | |
| Plic->GsiBase = PlicInfo->PlicAplicCommonInfo.GsiBase; | |
| } | |
| /** Add the PLIC Information to the MADT Table. | |
| @param [in] Plic Pointer to PLIC structure list. | |
| @param [in] PlicInfo Pointer to the PLIC info list. | |
| @param [in] PlicCount Count of PLICs. | |
| **/ | |
| STATIC | |
| VOID | |
| AddPLICList ( | |
| IN EFI_ACPI_6_6_PLIC_STRUCTURE *Plic, | |
| IN CONST CM_RISCV_PLIC_INFO *PlicInfo, | |
| IN UINT32 PlicCount | |
| ) | |
| { | |
| ASSERT (Plic != NULL); | |
| ASSERT (PlicInfo != NULL); | |
| while (PlicCount-- != 0) { | |
| AddPLIC (Plic++, PlicInfo++); | |
| } | |
| } | |
| /** 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 | |
| ) | |
| { | |
| CM_RISCV_RINTC_INFO *RintcInfo; | |
| CM_RISCV_IMSIC_INFO *ImsicInfo; | |
| CM_RISCV_APLIC_INFO *AplicInfo; | |
| CM_RISCV_PLIC_INFO *PlicInfo; | |
| EFI_STATUS Status; | |
| UINT32 TableSize; | |
| UINT32 RintcCount; | |
| UINT32 ImsicCount; | |
| UINT32 AplicCount; | |
| UINT32 PlicCount; | |
| UINT32 RintcOffset; | |
| UINT32 ImsicOffset; | |
| UINT32 AplicOffset; | |
| UINT32 PlicOffset; | |
| EFI_ACPI_6_6_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 = GetERiscVObjRintcInfo ( | |
| CfgMgrProtocol, | |
| CM_NULL_TOKEN, | |
| &RintcInfo, | |
| &RintcCount | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ( | |
| ( | |
| DEBUG_ERROR, | |
| "ERROR: MADT: Failed to get RINTC Info. Status = %r\n", | |
| Status | |
| ) | |
| ); | |
| goto error_handler; | |
| } | |
| if (RintcCount == 0) { | |
| DEBUG ( | |
| ( | |
| DEBUG_ERROR, | |
| "ERROR: MADT: RINTC information not provided.\n" | |
| ) | |
| ); | |
| ASSERT (RintcCount != 0); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto error_handler; | |
| } | |
| Status = GetERiscVObjImsicInfo ( | |
| CfgMgrProtocol, | |
| CM_NULL_TOKEN, | |
| &ImsicInfo, | |
| &ImsicCount | |
| ); | |
| if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { | |
| DEBUG ( | |
| ( | |
| DEBUG_ERROR, | |
| "ERROR: MADT: Failed to get IMSIC Info. Status = %r\n", | |
| Status | |
| ) | |
| ); | |
| goto error_handler; | |
| } | |
| if (ImsicCount > 1) { | |
| DEBUG ( | |
| ( | |
| DEBUG_ERROR, | |
| "ERROR: MADT: One, and only one, IMSIC must be present." | |
| "ImsicCount = %d\n", | |
| ImsicCount | |
| ) | |
| ); | |
| ASSERT (ImsicCount <= 1); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto error_handler; | |
| } | |
| Status = GetERiscVObjAplicInfo ( | |
| CfgMgrProtocol, | |
| CM_NULL_TOKEN, | |
| &AplicInfo, | |
| &AplicCount | |
| ); | |
| if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { | |
| DEBUG ( | |
| ( | |
| DEBUG_ERROR, | |
| "ERROR: MADT: Failed to get APLIC Info. Status = %r\n", | |
| Status | |
| ) | |
| ); | |
| goto error_handler; | |
| } | |
| Status = GetERiscVObjPlicInfo ( | |
| CfgMgrProtocol, | |
| CM_NULL_TOKEN, | |
| &PlicInfo, | |
| &PlicCount | |
| ); | |
| if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { | |
| DEBUG ( | |
| ( | |
| DEBUG_ERROR, | |
| "ERROR: MADT: Failed to get PLIC Info. Status = %r\n", | |
| Status | |
| ) | |
| ); | |
| goto error_handler; | |
| } | |
| TableSize = sizeof (EFI_ACPI_6_6_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER); | |
| RintcOffset = TableSize; | |
| TableSize += (sizeof (EFI_ACPI_6_6_RINTC_STRUCTURE) * RintcCount); | |
| ImsicOffset = TableSize; | |
| TableSize += (sizeof (EFI_ACPI_6_6_IMSIC_STRUCTURE) * ImsicCount); | |
| AplicOffset = TableSize; | |
| TableSize += (sizeof (EFI_ACPI_6_6_APLIC_STRUCTURE) * AplicCount); | |
| PlicOffset = TableSize; | |
| TableSize += (sizeof (EFI_ACPI_6_6_PLIC_STRUCTURE) * PlicCount); | |
| // 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_6_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 = AddRINTCList ( | |
| (EFI_ACPI_6_6_RINTC_STRUCTURE *)((UINT8 *)Madt + RintcOffset), | |
| RintcInfo, | |
| RintcCount | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ( | |
| ( | |
| DEBUG_ERROR, | |
| "ERROR: MADT: Failed to add RINTC structures. Status = %r\n", | |
| Status | |
| ) | |
| ); | |
| goto error_handler; | |
| } | |
| if (ImsicCount != 0) { | |
| AddIMSIC ( | |
| (EFI_ACPI_6_6_IMSIC_STRUCTURE *)((UINT8 *)Madt + ImsicOffset), | |
| ImsicInfo | |
| ); | |
| } | |
| if (AplicCount != 0) { | |
| AddAPLICList ( | |
| (EFI_ACPI_6_6_APLIC_STRUCTURE *)((UINT8 *)Madt + AplicOffset), | |
| AplicInfo, | |
| AplicCount | |
| ); | |
| } | |
| if (PlicCount != 0) { | |
| AddPLICList ( | |
| (EFI_ACPI_6_6_PLIC_STRUCTURE *)((UINT8 *)Madt + PlicOffset), | |
| PlicInfo, | |
| PlicCount | |
| ); | |
| } | |
| 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_6_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE, | |
| // ACPI Table Revision supported by this Generator | |
| EFI_ACPI_6_6_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION, | |
| // Minimum supported ACPI Table Revision | |
| EFI_ACPI_6_6_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION, | |
| // Creator ID | |
| TABLE_GENERATOR_CREATOR_ID, | |
| // 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; | |
| } |