From e89ff681106dc85b695724f084331af67dcdf05f Mon Sep 17 00:00:00 2001 From: Abdul Lateef Attar Date: Mon, 18 Nov 2024 10:39:10 +0000 Subject: DynamicTablesPkg: Add X64 MADT table generator Updates X64 namespace object. Updates the object parser. Updates the Readme. Cc: Sami Mujawar Cc: Pierre Gondois Signed-off-by: Abdul Lateef Attar --- DynamicTablesPkg/DynamicTables.dsc.inc | 6 +- DynamicTablesPkg/DynamicTablesPkg.ci.yaml | 4 +- DynamicTablesPkg/Include/X64NameSpaceObjects.h | 78 ++- .../Library/Acpi/X64/AcpiMadtLib/AcpiMadtLib.inf | 35 ++ .../Library/Acpi/X64/AcpiMadtLib/MadtGenerator.c | 598 +++++++++++++++++++++ .../ConfigurationManagerObjectParser.c | 68 ++- DynamicTablesPkg/Readme.md | 5 + 7 files changed, 778 insertions(+), 16 deletions(-) create mode 100644 DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/AcpiMadtLib.inf create mode 100644 DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/MadtGenerator.c diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc index 99424b0d50..9cdc0b2f8a 100644 --- a/DynamicTablesPkg/DynamicTables.dsc.inc +++ b/DynamicTablesPkg/DynamicTables.dsc.inc @@ -57,9 +57,10 @@ # # Generators (IA32/X64 specific) # - DynamicTablesPkg/Library/Acpi/X64/AcpiWsmtLib/AcpiWsmtLib.inf DynamicTablesPkg/Library/Acpi/X64/AcpiHpetLib/AcpiHpetLib.inf + DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/AcpiMadtLib.inf DynamicTablesPkg/Library/Acpi/X64/AcpiSsdtHpetLib/AcpiSsdtHpetLib.inf + DynamicTablesPkg/Library/Acpi/X64/AcpiWsmtLib/AcpiWsmtLib.inf # # Dynamic Table Factory Dxe @@ -71,9 +72,10 @@ NULL|DynamicTablesPkg/Library/Acpi/Common/AcpiFadtLib/AcpiFadtLib.inf NULL|DynamicTablesPkg/Library/Acpi/Common/AcpiSpmiLib/AcpiSpmiLib.inf # X64 specific - NULL|DynamicTablesPkg/Library/Acpi/X64/AcpiWsmtLib/AcpiWsmtLib.inf NULL|DynamicTablesPkg/Library/Acpi/X64/AcpiHpetLib/AcpiHpetLib.inf + NULL|DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/AcpiMadtLib.inf NULL|DynamicTablesPkg/Library/Acpi/X64/AcpiSsdtHpetLib/AcpiSsdtHpetLib.inf + NULL|DynamicTablesPkg/Library/Acpi/X64/AcpiWsmtLib/AcpiWsmtLib.inf } [Components.ARM, Components.AARCH64] diff --git a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml index 5f2c6e8fb6..42638ca704 100644 --- a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml +++ b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml @@ -2,6 +2,7 @@ # CI configuration for DynamicTablesPkg # # Copyright (c) 2020, Arm Limited. All rights reserved.
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause-Patent ## { @@ -131,7 +132,8 @@ "TABLEEX", "TNSID", "Vatos", - "WBINVD" + "WBINVD", + "xapic" ], # words to extend to the dictionary for this package "IgnoreStandardPaths": [], # Standard Plugin defined paths that # should be ignore diff --git a/DynamicTablesPkg/Include/X64NameSpaceObjects.h b/DynamicTablesPkg/Include/X64NameSpaceObjects.h index f153461be0..f07d6d4655 100644 --- a/DynamicTablesPkg/Include/X64NameSpaceObjects.h +++ b/DynamicTablesPkg/Include/X64NameSpaceObjects.h @@ -2,7 +2,7 @@ Defines the X64 Namespace Object. - Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent @@ -17,6 +17,15 @@ #include +/** The LOCAL_APIC_MODE enum describes the Local APIC + mode in the X64 Namespace +*/ +typedef enum { + LocalApicModeInvalid = 0, + LocalApicModeXApic, + LocalApicModeX2Apic +} LOCAL_APIC_MODE; + /** The EX64_OBJECT_ID enum describes the Object IDs in the X64 Namespace */ @@ -33,7 +42,12 @@ typedef enum X64ObjectID { EX64ObjFadtMiscInfo, ///< 9 - FADT Legacy fields info EX64ObjWsmtFlagsInfo, ///< 10 - WSMT protection flags info EX64ObjHpetInfo, ///< 11 - HPET device info - EX64ObjMax ///< 12 - Maximum Object ID + EX64ObjMadtInfo, ///< 12 - MADT info + EX64ObjLocalApicX2ApicInfo, ///< 13 - Local APIC and X2APIC info + EX64ObjIoApicInfo, ///< 14 - IO APIC info + EX64ObjIntrSourceOverrideInfo, ///< 15 - Interrupt Source Override info + EX64ObjLocalApicX2ApicNmiInfo, ///< 16 - Local APIC and X2APIC NMI info + EX64ObjMax ///< 17 - Maximum Object ID } EX64_OBJECT_ID; /** A structure that describes the @@ -188,4 +202,64 @@ typedef struct CmX64HpetInfo { UINT16 MainCounterMinimumClockTickInPeriodicMode; UINT8 PageProtectionAndOemAttribute; } CM_X64_HPET_INFO; + +/** + A structure that describes the MADT information. + + ID: EX64ObjMadtInfo +*/ +typedef struct CmX64MadtInfo { + UINT32 LocalApicAddress; + UINT32 Flags; + LOCAL_APIC_MODE ApicMode; +} CM_X64_MADT_INFO; + +/** + A structure that describes the Local APIC and X2APIC information. + This structure includes fields from the ACPI_6_5_LOCAL_APIC_STRUCTURE + and ACPI_6_5_LOCAL_X2APIC_STRUCTURE from the ACPI specifications. + Additional fields are included to support CPU SSDT topology generation. + + ID: EX64ObjLocalApicX2ApicInfo +*/ +typedef struct CmX64LocalApicX2ApicInfo { + UINT32 ApicId; + UINT32 Flags; + UINT32 AcpiProcessorUid; +} CM_X64_LOCAL_APIC_X2APIC_INFO; + +/** + A structure that describes the IO APIC information. + + ID: EX64ObjIoApicInfo +*/ +typedef struct CmX64IoApicInfo { + UINT8 IoApicId; + UINT32 IoApicAddress; + UINT32 GlobalSystemInterruptBase; +} CM_X64_IO_APIC_INFO; + +/** + A structure that describes the Interrupt Source Override information. + + ID: EX64ObjIntrSourceOverrideInfo +*/ +typedef struct CmX64IntrSourceOverrideInfo { + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterrupt; + UINT16 Flags; +} CM_X64_INTR_SOURCE_OVERRIDE_INFO; + +/** + A structure that describes the Local APIC NMI information. + + ID: EX64ObjLocalApicX2ApicNmiInfo +*/ +typedef struct CmX64LocalApicX2ApicNmiInfo { + UINT16 Flags; + UINT32 AcpiProcessorUid; + UINT8 LocalApicLint; +} CM_X64_LOCAL_APIC_X2APIC_NMI_INFO; + #endif // X64_NAMESPACE_OBJECTS_H_ diff --git a/DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/AcpiMadtLib.inf b/DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/AcpiMadtLib.inf new file mode 100644 index 0000000000..8cca73c55b --- /dev/null +++ b/DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/AcpiMadtLib.inf @@ -0,0 +1,35 @@ +## @file +# MADT Table Generator +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.30 + BASE_NAME = AcpiMadtLib + FILE_GUID = 3D0CA837-FDA2-4546-9CDC-42953238E456 + VERSION_STRING = 1.0 + MODULE_TYPE = DXE_DRIVER + LIBRARY_CLASS = NULL|DXE_DRIVER + CONSTRUCTOR = AcpiMadtLibConstructor + DESTRUCTOR = AcpiMadtLibDestructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.IA32, Sources.X64] + MadtGenerator.c + +[Packages] + DynamicTablesPkg/DynamicTablesPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib diff --git a/DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/MadtGenerator.c b/DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/MadtGenerator.c new file mode 100644 index 0000000000..743b3b4b3f --- /dev/null +++ b/DynamicTablesPkg/Library/Acpi/X64/AcpiMadtLib/MadtGenerator.c @@ -0,0 +1,598 @@ +/** @file + MADT Table Generator Implementation. + + This file implements the MADT Table Generator, + which handles various APIC structures within a system, + including Local APIC, IO APIC, Interrupt Source Override, and Local APIC NMI. + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** This macro expands to the total size of the MADT table. + The size is calculated based on the number of IO APICs, + Local APICs/X2APICs, Interrupt Source Overrides, + and Local APIC/X2APIC NMIs. +*/ +#define MADT_TOTAL_SIZE(ApicMode, \ + IoApicCount, \ + IntrSourceOverrideCount, \ + LocalApicCount, \ + LocalApicNmiCount) \ + ( \ + sizeof (EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER) + \ + (sizeof (EFI_ACPI_6_5_IO_APIC_STRUCTURE) * IoApicCount) + \ + (sizeof (EFI_ACPI_6_5_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE) * IntrSourceOverrideCount) + \ + ((ApicMode == LocalApicModeXApic) ? \ + ((sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC_STRUCTURE) * LocalApicCount) + \ + (sizeof (EFI_ACPI_6_5_LOCAL_APIC_NMI_STRUCTURE) * LocalApicNmiCount)) : \ + ((sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE) * LocalApicCount) + \ + (sizeof (EFI_ACPI_6_5_LOCAL_X2APIC_NMI_STRUCTURE) * LocalApicNmiCount)) \ + ) \ + ) + +/** This macro expands to a function that retrieves the + MADT local APIC address and flags information + from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceX64, + EX64ObjMadtInfo, + CM_X64_MADT_INFO + ); + +/** This macro defines a function to retrieve the + MADT local APIC or X2APIC information from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceX64, + EX64ObjLocalApicX2ApicInfo, + CM_X64_LOCAL_APIC_X2APIC_INFO + ); + +/** This macro defines a function to retrieve the + MADT IO APIC information from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceX64, + EX64ObjIoApicInfo, + CM_X64_IO_APIC_INFO + ); + +/** This macro defines a function to retrieve the + MADT interrupt source override information from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceX64, + EX64ObjIntrSourceOverrideInfo, + CM_X64_INTR_SOURCE_OVERRIDE_INFO + ); + +/** This macro defines a function to retrieve the + MADT local APIC NMI information from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceX64, + EX64ObjLocalApicX2ApicNmiInfo, + CM_X64_LOCAL_APIC_X2APIC_NMI_INFO + ); + +/** Construct the MADT table. + + This function invokes the Configuration Manager protocol interface + to get the required 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_X64_INTR_SOURCE_OVERRIDE_INFO *IntrSourceOverride; + CM_X64_IO_APIC_INFO *IoApic; + CM_X64_LOCAL_APIC_X2APIC_INFO *LocalApic; + CM_X64_LOCAL_APIC_X2APIC_NMI_INFO *LocalApicNmi; + CM_X64_MADT_INFO *MadtInfo; + EFI_ACPI_6_5_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *IntrSourceOverrideEntry; + EFI_ACPI_6_5_IO_APIC_STRUCTURE *IoApicEntry; + EFI_ACPI_6_5_LOCAL_APIC_NMI_STRUCTURE *LocalApicNmiEntry; + EFI_ACPI_6_5_LOCAL_X2APIC_NMI_STRUCTURE *LocalX2ApicNmiEntry; + EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MadtHeader; + EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApicEntry; + EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *LocalX2ApicEntry; + EFI_STATUS Status; + LOCAL_APIC_MODE ApicMode; + UINT32 AcpiMadtSize; + UINT32 Index; + UINT32 IntrSourceOverrideCount; + UINT32 IoApicCount; + UINT32 LocalApicCount; + UINT32 LocalApicNmiCount; + UINT32 NextPtrSize; + UINT8 *AcpiMadtPtr; + + 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 = GetEX64ObjMadtInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &MadtInfo, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Failed to get MADT Info object. Status = %r\n", + Status + )); + ASSERT_EFI_ERROR (Status); + return Status; + } + + if ((MadtInfo->Flags & ~(UINT32)EFI_ACPI_6_5_PCAT_COMPAT) != 0) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Invalid MADT Info object. Flags = 0x%x\n", + MadtInfo->Flags + )); + Status = EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + return Status; + } + + ApicMode = MadtInfo->ApicMode; + if ((ApicMode != LocalApicModeXApic) && (ApicMode != LocalApicModeX2Apic)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Invalid MADT Info object. ApicMode = 0x%x\n", + ApicMode + )); + Status = EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + return Status; + } + + LocalApicCount = 0; + Status = GetEX64ObjLocalApicX2ApicInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &LocalApic, + &LocalApicCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Failed to get Local APIC/X2APIC Info object. Status = %r\n", + Status + )); + ASSERT_EFI_ERROR (Status); + return Status; + } + + if ((LocalApic == NULL) || (LocalApicCount == 0)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Local APIC/X2APIC Info object not found.\n" + )); + Status = EFI_NOT_FOUND; + ASSERT_EFI_ERROR (Status); + return Status; + } + + for (Index = 0; Index < LocalApicCount; Index++) { + if ((LocalApic[Index].Flags & + ~(UINT32)(EFI_ACPI_6_5_LOCAL_APIC_ENABLED|EFI_ACPI_6_5_LOCAL_APIC_ONLINE_CAPABLE)) != 0) + { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Invalid Local APIC/X2APIC Info object. Flags = 0x%x\n", + LocalApic[Index].Flags + )); + Status = EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + return Status; + } + + /// If in APIC mode, check for AcpiProcessorUid and ApicId overflow against UINT8_MAX + if (ApicMode == LocalApicModeXApic) { + if ((LocalApic[Index].AcpiProcessorUid > MAX_UINT8) || + (LocalApic[Index].ApicId > MAX_UINT8)) + { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Invalid Local XAPIC Info object. AcpiProcessorUid = 0x%x, ApicId = 0x%x\n", + LocalApic[Index].AcpiProcessorUid, + LocalApic[Index].ApicId + )); + Status = EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + return Status; + } + } + } + + IoApicCount = 0; + Status = GetEX64ObjIoApicInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &IoApic, + &IoApicCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Failed to get IO APIC Info object. Status = %r\n", + Status + )); + ASSERT_EFI_ERROR (Status); + return Status; + } + + if ((IoApic == NULL) || (IoApicCount == 0)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: IO APIC Info object not found.\n" + )); + Status = EFI_NOT_FOUND; + ASSERT_EFI_ERROR (Status); + return Status; + } + + IntrSourceOverrideCount = 0; + Status = GetEX64ObjIntrSourceOverrideInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &IntrSourceOverride, + &IntrSourceOverrideCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Failed to get Interrupt Source Override Info object. Status = %r\n", + Status + )); + ASSERT_EFI_ERROR (Status); + return Status; + } + + if ((IntrSourceOverride == NULL) || (IntrSourceOverrideCount == 0)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Interrupt Source Override Info object not found.\n" + )); + Status = EFI_NOT_FOUND; + ASSERT_EFI_ERROR (Status); + return Status; + } + + for (Index = 0; Index < IntrSourceOverrideCount; Index++) { + if ((IntrSourceOverride[Index].Flags & + ~(UINT32)(EFI_ACPI_6_5_POLARITY|EFI_ACPI_6_5_TRIGGER_MODE)) != 0) + { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Invalid Interrupt Source Override Info object. Flags = 0x%x\n", + IntrSourceOverride[Index].Flags + )); + Status = EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + LocalApicNmiCount = 0; + Status = GetEX64ObjLocalApicX2ApicNmiInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &LocalApicNmi, + &LocalApicNmiCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Failed to get Local APIC NMI Info object. Status = %r\n", + Status + )); + ASSERT_EFI_ERROR (Status); + return Status; + } + + if ((LocalApicNmi == NULL) || (LocalApicNmiCount == 0)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Local APIC NMI Info object not found.\n" + )); + Status = EFI_NOT_FOUND; + ASSERT_EFI_ERROR (Status); + return Status; + } + + for (Index = 0; Index < LocalApicNmiCount; Index++) { + if ((LocalApicNmi[Index].Flags & ~(UINT32)(EFI_ACPI_6_5_POLARITY|EFI_ACPI_6_5_TRIGGER_MODE)) != 0) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Invalid Local APIC NMI Info object. Flags = 0x%x\n", + LocalApicNmi[Index].Flags + )); + Status = EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + return Status; + } + + /// check for AcpiProcessorUid overflow against UINT8_MAX if in APIC mode + if (ApicMode == LocalApicModeXApic) { + if (LocalApicNmi[Index].AcpiProcessorUid > MAX_UINT8) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Invalid Local APIC NMI Info object. AcpiProcessorUid = 0x%x\n", + LocalApicNmi[Index].AcpiProcessorUid + )); + Status = EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + return Status; + } + } + } + + if (MADT_TOTAL_SIZE ( + ApicMode, + IoApicCount, + IntrSourceOverrideCount, + LocalApicCount, + LocalApicNmiCount + ) > MAX_UINT32) + { + DEBUG ((DEBUG_ERROR, "ERROR: MADT: MADT_TOTAL_SIZE overflow detected.\n")); + Status = EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + return Status; + } + + AcpiMadtSize = (UINT32)MADT_TOTAL_SIZE ( + ApicMode, + IoApicCount, + IntrSourceOverrideCount, + LocalApicCount, + LocalApicNmiCount + ); + AcpiMadtPtr = AllocateZeroPool (AcpiMadtSize); + if (AcpiMadtPtr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Failed to allocate memory for MADT table.\n" + )); + ASSERT_EFI_ERROR (Status); + return Status; + } + + MadtHeader = (EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)(VOID *)AcpiMadtPtr; + MadtHeader->LocalApicAddress = MadtInfo->LocalApicAddress; + MadtHeader->Flags = MadtInfo->Flags; + + NextPtrSize = sizeof (EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER); + if (ApicMode == LocalApicModeXApic) { + LocalApicEntry = (EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC_STRUCTURE *)(AcpiMadtPtr + NextPtrSize); + for (Index = 0; Index < LocalApicCount; Index++) { + LocalApicEntry[Index].Type = EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC; + LocalApicEntry[Index].Length = sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC_STRUCTURE); + LocalApicEntry[Index].AcpiProcessorUid = (UINT8)LocalApic[Index].AcpiProcessorUid; + LocalApicEntry[Index].ApicId = (UINT8)LocalApic[Index].ApicId; + LocalApicEntry[Index].Flags = LocalApic[Index].Flags; + } + + NextPtrSize += (sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_APIC_STRUCTURE) * LocalApicCount); + } else { + LocalX2ApicEntry = (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE *)(AcpiMadtPtr + NextPtrSize); + for (Index = 0; Index < LocalApicCount; Index++) { + LocalX2ApicEntry[Index].Type = EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC; + LocalX2ApicEntry[Index].Length = sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE); + LocalX2ApicEntry[Index].Reserved[0] = 0; + LocalX2ApicEntry[Index].Reserved[1] = 0; + LocalX2ApicEntry[Index].X2ApicId = LocalApic[Index].ApicId; + LocalX2ApicEntry[Index].Flags = LocalApic[Index].Flags; + LocalX2ApicEntry[Index].AcpiProcessorUid = LocalApic[Index].AcpiProcessorUid; + } + + NextPtrSize += (sizeof (EFI_ACPI_6_5_PROCESSOR_LOCAL_X2APIC_STRUCTURE) * LocalApicCount); + } + + IoApicEntry = (EFI_ACPI_6_5_IO_APIC_STRUCTURE *)(AcpiMadtPtr + NextPtrSize); + for (Index = 0; Index < IoApicCount; Index++) { + IoApicEntry[Index].Type = EFI_ACPI_6_5_IO_APIC; + IoApicEntry[Index].Length = sizeof (EFI_ACPI_6_5_IO_APIC_STRUCTURE); + IoApicEntry[Index].IoApicId = IoApic[Index].IoApicId; + IoApicEntry[Index].Reserved = 0; + IoApicEntry[Index].IoApicAddress = IoApic[Index].IoApicAddress; + IoApicEntry[Index].GlobalSystemInterruptBase = IoApic[Index].GlobalSystemInterruptBase; + } + + NextPtrSize += (sizeof (EFI_ACPI_6_5_IO_APIC_STRUCTURE) * IoApicCount); + + IntrSourceOverrideEntry = (EFI_ACPI_6_5_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)(AcpiMadtPtr + NextPtrSize); + for (Index = 0; Index < IntrSourceOverrideCount; Index++) { + IntrSourceOverrideEntry[Index].Type = EFI_ACPI_6_5_INTERRUPT_SOURCE_OVERRIDE; + IntrSourceOverrideEntry[Index].Length = sizeof (EFI_ACPI_6_5_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE); + IntrSourceOverrideEntry[Index].Bus = IntrSourceOverride[Index].Bus; + IntrSourceOverrideEntry[Index].Source = IntrSourceOverride[Index].Source; + IntrSourceOverrideEntry[Index].GlobalSystemInterrupt = IntrSourceOverride[Index].GlobalSystemInterrupt; + IntrSourceOverrideEntry[Index].Flags = IntrSourceOverride[Index].Flags; + } + + NextPtrSize += (sizeof (EFI_ACPI_6_5_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE) * IntrSourceOverrideCount); + if (ApicMode == LocalApicModeXApic) { + LocalApicNmiEntry = (EFI_ACPI_6_5_LOCAL_APIC_NMI_STRUCTURE *)(AcpiMadtPtr + NextPtrSize); + for (Index = 0; Index < LocalApicNmiCount; Index++) { + LocalApicNmiEntry[Index].Type = EFI_ACPI_6_5_LOCAL_APIC_NMI; + LocalApicNmiEntry[Index].Length = sizeof (EFI_ACPI_6_5_LOCAL_APIC_NMI_STRUCTURE); + LocalApicNmiEntry[Index].AcpiProcessorUid = (UINT8)LocalApicNmi[Index].AcpiProcessorUid; + LocalApicNmiEntry[Index].Flags = LocalApicNmi[Index].Flags; + LocalApicNmiEntry[Index].LocalApicLint = LocalApicNmi[Index].LocalApicLint; + } + } else { + LocalX2ApicNmiEntry = (EFI_ACPI_6_5_LOCAL_X2APIC_NMI_STRUCTURE *)(AcpiMadtPtr + NextPtrSize); + for (Index = 0; Index < LocalApicNmiCount; Index++) { + LocalX2ApicNmiEntry[Index].Type = EFI_ACPI_6_5_LOCAL_X2APIC_NMI; + LocalX2ApicNmiEntry[Index].Length = sizeof (EFI_ACPI_6_5_LOCAL_X2APIC_NMI_STRUCTURE); + LocalX2ApicNmiEntry[Index].AcpiProcessorUid = LocalApicNmi[Index].AcpiProcessorUid; + LocalX2ApicNmiEntry[Index].Flags = LocalApicNmi[Index].Flags; + LocalX2ApicNmiEntry[Index].LocalX2ApicLint = LocalApicNmi[Index].LocalApicLint; + } + } + + Status = AddAcpiHeader ( + CfgMgrProtocol, + This, + (EFI_ACPI_DESCRIPTION_HEADER *)AcpiMadtPtr, + AcpiTableInfo, + AcpiMadtSize + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: MADT: Failed to add ACPI header. Status = %r\n", + Status + )); + ASSERT_EFI_ERROR (Status); + FreePool (AcpiMadtPtr); + return Status; + } + + *Table = (EFI_ACPI_DESCRIPTION_HEADER *)AcpiMadtPtr; + return Status; +} + +/** This macro defines 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_5_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION, + // Creator ID + TABLE_GENERATOR_CREATOR_ID, + // Creator Revision + MADT_GENERATOR_REVISION, + // Build Table function + BuildMadtTable, + // No additional resources are allocated by the generator. + // Hence the Free Resource function is not required. + NULL, + // Extended build function not needed + NULL, + // Extended build function not implemented by the generator. + // Hence extended free resource function is not required. + NULL +}; + +/** Register the Generator with the ACPI Table Factory. + + @param [in] ImageHandle The handle to the image. + @param [in] SystemTable Pointer to the System Table. + + @retval EFI_SUCCESS The Generator is registered. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_ALREADY_STARTED The Generator for the Table ID + is already registered. +**/ +EFI_STATUS +EFIAPI +AcpiMadtLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = RegisterAcpiTableGenerator (&MadtGenerator); + DEBUG ((DEBUG_INFO, "MADT: Register Generator. Status = %r\n", Status)); + ASSERT_EFI_ERROR (Status); + return Status; +} + +/** Deregister the Generator from the ACPI Table Factory. + + @param [in] ImageHandle The handle to the image. + @param [in] SystemTable Pointer to the System Table. + + @retval EFI_SUCCESS The Generator is deregistered. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND The Generator is not registered. +**/ +EFI_STATUS +EFIAPI +AcpiMadtLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = DeregisterAcpiTableGenerator (&MadtGenerator); + DEBUG ((DEBUG_INFO, "MADT: Deregister Generator. Status = %r\n", Status)); + ASSERT_EFI_ERROR (Status); + return Status; +} diff --git a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c index 6dc48abb81..7721e44564 100755 --- a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c +++ b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c @@ -884,21 +884,67 @@ STATIC CONST CM_OBJ_PARSER CmX64ObjHpetInfoParser[] = { { "PageProtectionAndOemAttribute", 1, "0x%x", NULL } }; +/** A parser for EX64ObjMadtInfo. +*/ +STATIC CONST CM_OBJ_PARSER CmX64ObjMadtInfoParser[] = { + { "LocalApicAddress", 4, "0x%x", NULL }, + { "Flags", 4, "0x%x", NULL }, + { "ApicMode", 1, "0x%x", NULL } +}; + +/** A parser for CmArchCommonLocalApicX2ApicInfoParser. +*/ +STATIC CONST CM_OBJ_PARSER CmX64ObjLocalApicX2ApicInfoParser[] = { + { "ApicId", 4, "0x%x", NULL }, + { "Flags", 4, "0x%x", NULL }, + { "AcpiProcessorUid", 4, "0x%x", NULL } +}; + +/** A parser for CmX64IoApicInfoParser. +*/ +STATIC CONST CM_OBJ_PARSER CmX64IoApicInfoParser[] = { + { "IoApicId", 1, "0x%x", NULL }, + { "IoApicAddress", 4, "0x%x", NULL }, + { "GlobalSystemInterruptBase", 4, "0x%x", NULL } +}; + +/** A parser for CmX64IntrSourceOverrideInfoParser. +*/ +STATIC CONST CM_OBJ_PARSER CmX64IntrSourceOverrideInfoParser[] = { + { "Bus", 1, "0x%x", NULL }, + { "Source", 1, "0x%x", NULL }, + { "GlobalSystemInterrupt", 4, "0x%x", NULL }, + { "Flags", 2, "0x%x", NULL } +}; + +/** A parser for CmX64LocalApicNmiInfo. +*/ +STATIC CONST CM_OBJ_PARSER CmX64LocalApicNmiInfo[] = { + { "Flags", 2, "0x%x", NULL }, + { "AcpiProcessorUid", 4, "0x%x", NULL }, + { "LocalApicLint", 1, "0x%x", NULL } +}; + /** A parser for X64 namespace objects. */ STATIC CONST CM_OBJ_PARSER_ARRAY X64NamespaceObjectParser[] = { CM_PARSER_ADD_OBJECT_RESERVED (EX64ObjReserved), - CM_PARSER_ADD_OBJECT (EX64ObjFadtSciInterrupt, CmX64ObjFadtSciInterruptParser), - CM_PARSER_ADD_OBJECT (EX64ObjFadtSciCmdInfo, CmX64ObjFadtSciCmdInfoParser), - CM_PARSER_ADD_OBJECT (EX64ObjFadtPmBlockInfo, CmX64ObjFadtPmBlockInfoParser), - CM_PARSER_ADD_OBJECT (EX64ObjFadtGpeBlockInfo, CmX64ObjFadtGpeBlockInfoParser), - CM_PARSER_ADD_OBJECT (EX64ObjFadtXpmBlockInfo, CmX64ObjFadtXpmBlockInfoParser), - CM_PARSER_ADD_OBJECT (EX64ObjFadtXgpeBlockInfo, CmX64ObjFadtXgpeBlockInfoParser), - CM_PARSER_ADD_OBJECT (EX64ObjFadtSleepBlockInfo,CmX64ObjFadtSleepBlockInfoParser), - CM_PARSER_ADD_OBJECT (EX64ObjFadtResetBlockInfo,CmX64ObjFadtResetBlockInfoParser), - CM_PARSER_ADD_OBJECT (EX64ObjFadtMiscInfo, CmX64ObjFadtMiscInfoParser), - CM_PARSER_ADD_OBJECT (EX64ObjWsmtFlagsInfo, CmX64ObjWsmtFlagsInfoParser), - CM_PARSER_ADD_OBJECT (EX64ObjHpetInfo, CmX64ObjHpetInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjFadtSciInterrupt, CmX64ObjFadtSciInterruptParser), + CM_PARSER_ADD_OBJECT (EX64ObjFadtSciCmdInfo, CmX64ObjFadtSciCmdInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjFadtPmBlockInfo, CmX64ObjFadtPmBlockInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjFadtGpeBlockInfo, CmX64ObjFadtGpeBlockInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjFadtXpmBlockInfo, CmX64ObjFadtXpmBlockInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjFadtXgpeBlockInfo, CmX64ObjFadtXgpeBlockInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjFadtSleepBlockInfo, CmX64ObjFadtSleepBlockInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjFadtResetBlockInfo, CmX64ObjFadtResetBlockInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjFadtMiscInfo, CmX64ObjFadtMiscInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjWsmtFlagsInfo, CmX64ObjWsmtFlagsInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjHpetInfo, CmX64ObjHpetInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjMadtInfo, CmX64ObjMadtInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjLocalApicX2ApicInfo, CmX64ObjLocalApicX2ApicInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjIoApicInfo, CmX64IoApicInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjIntrSourceOverrideInfo,CmX64IntrSourceOverrideInfoParser), + CM_PARSER_ADD_OBJECT (EX64ObjLocalApicX2ApicNmiInfo,CmX64LocalApicNmiInfo), CM_PARSER_ADD_OBJECT_RESERVED (EX64ObjMax) }; diff --git a/DynamicTablesPkg/Readme.md b/DynamicTablesPkg/Readme.md index 3d08596963..5fbc2d261b 100644 --- a/DynamicTablesPkg/Readme.md +++ b/DynamicTablesPkg/Readme.md @@ -518,4 +518,9 @@ The CM_OBJECT_ID type is used to identify the Configuration Manager | 9 | Miscellaneous Block Info | | | 10 | Windows protection flag Info | | | 11 | HPET device Info | | +| 12 | MADT Table Info | | +| 13 | Local APIC and X2APIC info | | +| 14 | IO APIC info | | +| 15 | Interrupt Source Override info | | +| 16 | Local APIC and X2APIC NMI info | | | `*` | All other values are reserved. | | -- cgit