diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc index 142832b9fa..0bf7a77cf2 100644 --- a/DynamicTablesPkg/DynamicTables.dsc.inc +++ b/DynamicTablesPkg/DynamicTables.dsc.inc @@ -30,6 +30,7 @@ NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiPpttLibArm/AcpiPpttLibArm.inf NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiRawLibArm/AcpiRawLibArm.inf NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSpcrLibArm/AcpiSpcrLibArm.inf + NULL|DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/AcpiSratLibArm.inf } # diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h index 7d6d344227..e46717e6e8 100644 --- a/DynamicTablesPkg/Include/AcpiTableGenerator.h +++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h @@ -53,6 +53,8 @@ The Dynamic Tables Framework implements the following ACPI table generators: Configuration Manager and builds the IORT table. - PPTT : The PPTT generator collates the processor topology information from the Configuration Manager and builds the PPTT table. + - SRAT : The SRAT generator collates the system resource affinity information + from the Configuration Manager and builds the SRAT table. */ /** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID. @@ -75,6 +77,7 @@ typedef enum StdAcpiTableId { EStdAcpiTableIdMcfg, ///< MCFG Generator EStdAcpiTableIdIort, ///< IORT Generator EStdAcpiTableIdPptt, ///< PPTT Generator + EStdAcpiTableIdSrat, ///< SRAT Generator EStdAcpiTableIdMax } ESTD_ACPI_TABLE_ID; diff --git a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h index ac451b306d..da70cba203 100644 --- a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h +++ b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h @@ -21,37 +21,41 @@ in the ARM Namespace */ typedef enum ArmObjectID { - EArmObjReserved, ///< 0 - Reserved - EArmObjBootArchInfo, ///< 1 - Boot Architecture Info - EArmObjCpuInfo, ///< 2 - CPU Info - EArmObjPowerManagementProfileInfo, ///< 3 - Power Management Profile Info - EArmObjGicCInfo, ///< 4 - GIC CPU Interface Info - EArmObjGicDInfo, ///< 5 - GIC Distributor Info - EArmObjGicMsiFrameInfo, ///< 6 - GIC MSI Frame Info - EArmObjGicRedistributorInfo, ///< 7 - GIC Redistributor Info - EArmObjGicItsInfo, ///< 8 - GIC ITS Info - EArmObjSerialConsolePortInfo, ///< 9 - Serial Console Port Info - EArmObjSerialDebugPortInfo, ///< 10 - Serial Debug Port Info - EArmObjGenericTimerInfo, ///< 11 - Generic Timer Info - EArmObjPlatformGTBlockInfo, ///< 12 - Platform GT Block Info - EArmObjGTBlockTimerFrameInfo, ///< 13 - Generic Timer Block Frame Info - EArmObjPlatformGenericWatchdogInfo, ///< 14 - Platform Generic Watchdog - EArmObjPciConfigSpaceInfo, ///< 15 - PCI Configuration Space Info - EArmObjHypervisorVendorIdentity, ///< 16 - Hypervisor Vendor Id - EArmObjFixedFeatureFlags, ///< 17 - Fixed feature flags for FADT - EArmObjItsGroup, ///< 18 - ITS Group - EArmObjNamedComponent, ///< 19 - Named Component - EArmObjRootComplex, ///< 20 - Root Complex - EArmObjSmmuV1SmmuV2, ///< 21 - SMMUv1 or SMMUv2 - EArmObjSmmuV3, ///< 22 - SMMUv3 - EArmObjPmcg, ///< 23 - PMCG - EArmObjGicItsIdentifierArray, ///< 24 - GIC ITS Identifier Array - EArmObjIdMappingArray, ///< 25 - ID Mapping Array - EArmObjSmmuInterruptArray, ///< 26 - SMMU Interrupt Array - EArmObjProcHierarchyInfo, ///< 27 - Processor Hierarchy Info - EArmObjCacheInfo, ///< 28 - Cache Info - EArmObjProcNodeIdInfo, ///< 29 - Processor Hierarchy Node ID Info - EArmObjCmRef, ///< 30 - CM Object Reference + EArmObjReserved, ///< 0 - Reserved + EArmObjBootArchInfo, ///< 1 - Boot Architecture Info + EArmObjCpuInfo, ///< 2 - CPU Info + EArmObjPowerManagementProfileInfo, ///< 3 - Power Management Profile Info + EArmObjGicCInfo, ///< 4 - GIC CPU Interface Info + EArmObjGicDInfo, ///< 5 - GIC Distributor Info + EArmObjGicMsiFrameInfo, ///< 6 - GIC MSI Frame Info + EArmObjGicRedistributorInfo, ///< 7 - GIC Redistributor Info + EArmObjGicItsInfo, ///< 8 - GIC ITS Info + EArmObjSerialConsolePortInfo, ///< 9 - Serial Console Port Info + EArmObjSerialDebugPortInfo, ///< 10 - Serial Debug Port Info + EArmObjGenericTimerInfo, ///< 11 - Generic Timer Info + EArmObjPlatformGTBlockInfo, ///< 12 - Platform GT Block Info + EArmObjGTBlockTimerFrameInfo, ///< 13 - Generic Timer Block Frame Info + EArmObjPlatformGenericWatchdogInfo, ///< 14 - Platform Generic Watchdog + EArmObjPciConfigSpaceInfo, ///< 15 - PCI Configuration Space Info + EArmObjHypervisorVendorIdentity, ///< 16 - Hypervisor Vendor Id + EArmObjFixedFeatureFlags, ///< 17 - Fixed feature flags for FADT + EArmObjItsGroup, ///< 18 - ITS Group + EArmObjNamedComponent, ///< 19 - Named Component + EArmObjRootComplex, ///< 20 - Root Complex + EArmObjSmmuV1SmmuV2, ///< 21 - SMMUv1 or SMMUv2 + EArmObjSmmuV3, ///< 22 - SMMUv3 + EArmObjPmcg, ///< 23 - PMCG + EArmObjGicItsIdentifierArray, ///< 24 - GIC ITS Identifier Array + EArmObjIdMappingArray, ///< 25 - ID Mapping Array + EArmObjSmmuInterruptArray, ///< 26 - SMMU Interrupt Array + EArmObjProcHierarchyInfo, ///< 27 - Processor Hierarchy Info + EArmObjCacheInfo, ///< 28 - Cache Info + EArmObjProcNodeIdInfo, ///< 29 - Processor Node ID Info + EArmObjCmRef, ///< 30 - CM Object Reference + EArmObjMemoryAffinityInfo, ///< 31 - Memory Affinity Info + EArmObjDeviceHandleAcpi, ///< 32 - Device Handle Acpi + EArmObjDeviceHandlePci, ///< 33 - Device Handle Pci + EArmObjGenericInitiatorAffinityInfo, ///< 34 - Generic Initiator Affinity EArmObjMax } EARM_OBJECT_ID; @@ -166,6 +170,23 @@ typedef struct CmArmGicCInfo { generating MADT revision 4 or lower. */ UINT16 SpeOverflowInterrupt; + + /** The proximity domain to which the logical processor belongs. + This field is used to populate the GICC affinity structure + in the SRAT table. + */ + UINT32 ProximityDomain; + + /** The clock domain to which the logical processor belongs. + This field is used to populate the GICC affinity structure + in the SRAT table. + */ + UINT32 ClockDomain; + + /** The GICC Affinity flags field as described by the GICC Affinity structure + in the SRAT table. + */ + UINT32 AffinityFlags; } CM_ARM_GICC_INFO; /** A structure that describes the @@ -241,6 +262,12 @@ typedef struct CmArmGicItsInfo { /// The physical address for the Interrupt Translation Service UINT64 PhysicalBaseAddress; + + /** The proximity domain to which the logical processor belongs. + This field is used to populate the GIC ITS affinity structure + in the SRAT table. + */ + UINT32 ProximityDomain; } CM_ARM_GIC_ITS_INFO; /** A structure that describes the @@ -729,6 +756,74 @@ typedef struct CmArmObjRef { CM_OBJECT_TOKEN ReferenceToken; } CM_ARM_OBJ_REF; +/** A structure that describes the Memory Affinity Structure (Type 1) in SRAT + + ID: EArmObjMemoryAffinityInfo +*/ +typedef struct CmArmMemoryAffinityInfo { + /// The proximity domain to which the "range of memory" belongs. + UINT32 ProximityDomain; + + /// Base Address + UINT64 BaseAddress; + + /// Length + UINT64 Length; + + /// Flags + UINT32 Flags; +} CM_ARM_MEMORY_AFFINITY_INFO; + +/** A structure that describes the ACPI Device Handle (Type 0) in the + Generic Initiator Affinity structure in SRAT + + ID: EArmObjDeviceHandleAcpi +*/ +typedef struct CmArmDeviceHandleAcpi { + /// Hardware ID + UINT64 Hid; + + /// Unique Id + UINT32 Uid; +} CM_ARM_DEVICE_HANDLE_ACPI; + +/** A structure that describes the PCI Device Handle (Type 1) in the + Generic Initiator Affinity structure in SRAT + + ID: EArmObjDeviceHandlePci +*/ +typedef struct CmArmDeviceHandlePci { + /// PCI Segment Number + UINT16 SegmentNumber; + + /// PCI Bus Number - Max 256 busses (Bits 15:8 of BDF) + UINT8 BusNumber; + + /// PCI Device Mumber - Max 32 devices (Bits 7:3 of BDF) + UINT8 DeviceNumber; + + /// PCI Function Number - Max 8 functions (Bits 2:0 of BDF) + UINT8 FunctionNumber; +} CM_ARM_DEVICE_HANDLE_PCI; + +/** A structure that describes the Generic Initiator Affinity structure in SRAT + + ID: EArmObjGenericInitiatorAffinityInfo +*/ +typedef struct CmArmGenericInitiatorAffinityInfo { + /// The proximity domain to which the generic initiator belongs. + UINT32 ProximityDomain; + + /// Flags + UINT32 Flags; + + /// Device Handle Type + UINT8 DeviceHandleType; + + /// Reference Token for the Device Handle + CM_OBJECT_TOKEN DeviceHandleToken; +} CM_ARM_GENERIC_INITIATOR_AFFINITY_INFO; + #pragma pack() #endif // ARM_NAMESPACE_OBJECTS_H_ diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/AcpiSratLibArm.inf b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/AcpiSratLibArm.inf new file mode 100644 index 0000000000..5891dc4d1c --- /dev/null +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/AcpiSratLibArm.inf @@ -0,0 +1,29 @@ +## @file +# SRAT Table Generator +# +# Copyright (c) 2019, ARM Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = AcpiSratLibArm + FILE_GUID = 2CE21E0A-A39C-4B26-BC0E-526178036ACD + VERSION_STRING = 1.0 + MODULE_TYPE = DXE_DRIVER + LIBRARY_CLASS = NULL|DXE_DRIVER + CONSTRUCTOR = AcpiSratLibConstructor + DESTRUCTOR = AcpiSratLibDestructor + +[Sources] + SratGenerator.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + DynamicTablesPkg/DynamicTablesPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib diff --git a/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/SratGenerator.c b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/SratGenerator.c new file mode 100644 index 0000000000..5d56af6660 --- /dev/null +++ b/DynamicTablesPkg/Library/Acpi/Arm/AcpiSratLibArm/SratGenerator.c @@ -0,0 +1,835 @@ +/** @file + SRAT Table Generator + + Copyright (c) 2019, ARM Limited. All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - ACPI 6.3 Specification, January 2019 + + @par Glossary: + - Cm or CM - Configuration Manager + - Obj or OBJ - Object +**/ + +#include +#include +#include +#include +#include + +// Module specific include files. +#include +#include +#include +#include +#include + +/** + ARM standard SRAT Generator + + Requirements: + The following Configuration Manager Object(s) are used by this Generator: + - EArmObjGicCInfo (REQUIRED) + - EArmObjGicItsInfo (OPTIONAL) + - EArmObjMemoryAffinityInfo (OPTIONAL) + - EArmObjGenericInitiatorAffinityInfo (OPTIONAL) + - EArmObjDeviceHandleAcpi (OPTIONAL) + - EArmObjDeviceHandlePci (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 + Interrupt Translation Service Information from the + Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceArm, + EArmObjGicItsInfo, + CM_ARM_GIC_ITS_INFO + ); + +/** + This macro expands to a function that retrieves the Memory Affinity + information from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceArm, + EArmObjMemoryAffinityInfo, + CM_ARM_MEMORY_AFFINITY_INFO + ); + +/** + This macro expands to a function that retrieves the Generic Initiator Affinity + information from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceArm, + EArmObjGenericInitiatorAffinityInfo, + CM_ARM_GENERIC_INITIATOR_AFFINITY_INFO + ); + +/** + This macro expands to a function that retrieves the ACPI Device Handle + information from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceArm, + EArmObjDeviceHandleAcpi, + CM_ARM_DEVICE_HANDLE_ACPI + ); + +/** + This macro expands to a function that retrieves the PCI Device Handle + information from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceArm, + EArmObjDeviceHandlePci, + CM_ARM_DEVICE_HANDLE_PCI + ); + + +/** Return the PCI Device information in BDF format + + PCI Bus Number - Max 256 busses (Bits 15:8 of BDF) + PCI Device Mumber - Max 32 devices (Bits 7:3 of BDF) + PCI Function Number - Max 8 functions (Bits 2:0 of BDF) + + @param [in] DeviceHandlePci Pointer to the PCI Device Handle. + + @retval BDF value corresponding to the PCI Device Handle. +*/ +STATIC +UINT16 +GetBdf ( + IN CONST CM_ARM_DEVICE_HANDLE_PCI * DeviceHandlePci + ) +{ + UINT16 Bdf; + Bdf = (UINT16)DeviceHandlePci->BusNumber << 8; + Bdf |= (DeviceHandlePci->DeviceNumber & 0x1F) << 3; + Bdf |= DeviceHandlePci->FunctionNumber & 0x7; + return Bdf; +} + +/** Add the GICC Affinity Structures in the SRAT Table. + + @param [in] CfgMgrProtocol Pointer to the Configuration Manager + Protocol Interface. + @param [in] Srat Pointer to the SRAT Table. + @param [in] GicCAffOffset Offset of the GICC Affinity + information in the SRAT Table. + @param [in] GicCInfo Pointer to the GIC CPU Information list. + @param [in] GicCCount Count of GIC CPU Interfaces. + + @retval EFI_SUCCESS Table generated successfully. +**/ +STATIC +EFI_STATUS +AddGICCAffinity ( + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, + IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER * CONST Srat, + IN CONST UINT32 GicCAffOffset, + IN CONST CM_ARM_GICC_INFO * GicCInfo, + IN UINT32 GicCCount + ) +{ + EFI_ACPI_6_3_GICC_AFFINITY_STRUCTURE * GicCAff; + + ASSERT (Srat != NULL); + ASSERT (GicCInfo != NULL); + + GicCAff = (EFI_ACPI_6_3_GICC_AFFINITY_STRUCTURE *)((UINT8*)Srat + + GicCAffOffset); + + while (GicCCount-- != 0) { + DEBUG ((DEBUG_INFO, "SRAT: GicCAff = 0x%p\n", GicCAff)); + + GicCAff->Type = EFI_ACPI_6_3_GICC_AFFINITY; + GicCAff->Length = sizeof (EFI_ACPI_6_3_GICC_AFFINITY_STRUCTURE); + GicCAff->ProximityDomain = GicCInfo->ProximityDomain; + GicCAff->AcpiProcessorUid = GicCInfo->AcpiProcessorUid; + GicCAff->Flags = GicCInfo->AffinityFlags; + GicCAff->ClockDomain = GicCInfo->ClockDomain; + + // Next + GicCAff++; + GicCInfo++; + }// while + return EFI_SUCCESS; +} + +/** Add the GIC ITS Affinity Structures in the SRAT Table. + + @param [in] CfgMgrProtocol Pointer to the Configuration Manager + Protocol Interface. + @param [in] Srat Pointer to the SRAT Table. + @param [in] GicItsAffOffset Offset of the GIC ITS Affinity + information in the SRAT Table. + @param [in] GicItsInfo Pointer to the GIC ITS Information list. + @param [in] GicItsCount Count of GIC ITS. + + @retval EFI_SUCCESS Table generated successfully. +**/ +STATIC +EFI_STATUS +AddGICItsAffinity ( + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, + IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER * CONST Srat, + IN CONST UINT32 GicItsAffOffset, + IN CONST CM_ARM_GIC_ITS_INFO * GicItsInfo, + IN UINT32 GicItsCount + ) +{ + EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE * GicItsAff; + + ASSERT (Srat != NULL); + ASSERT (GicItsInfo != NULL); + + GicItsAff = (EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE *)((UINT8*)Srat + + GicItsAffOffset); + + while (GicItsCount-- != 0) { + DEBUG ((DEBUG_INFO, "SRAT: GicItsAff = 0x%p\n", GicItsAff)); + + GicItsAff->Type = EFI_ACPI_6_3_GIC_ITS_AFFINITY; + GicItsAff->Length = sizeof (EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE); + GicItsAff->ProximityDomain = GicItsInfo->ProximityDomain; + GicItsAff->Reserved[0] = EFI_ACPI_RESERVED_BYTE; + GicItsAff->Reserved[1] = EFI_ACPI_RESERVED_BYTE; + GicItsAff->ItsId = GicItsInfo->GicItsId; + + // Next + GicItsAff++; + GicItsInfo++; + }// while + return EFI_SUCCESS; +} + +/** Add the Memory Affinity Structures in the SRAT Table. + + @param [in] CfgMgrProtocol Pointer to the Configuration Manager + Protocol Interface. + @param [in] Srat Pointer to the SRAT Table. + @param [in] MemAffOffset Offset of the Memory Affinity + information in the SRAT Table. + @param [in] MemAffInfo Pointer to the Memory Affinity Information list. + @param [in] MemAffCount Count of Memory Affinity objects. + + @retval EFI_SUCCESS Table generated successfully. +**/ +STATIC +EFI_STATUS +AddMemoryAffinity ( + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, + IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER * CONST Srat, + IN CONST UINT32 MemAffOffset, + IN CONST CM_ARM_MEMORY_AFFINITY_INFO * MemAffInfo, + IN UINT32 MemAffCount + ) +{ + EFI_ACPI_6_3_MEMORY_AFFINITY_STRUCTURE * MemAff; + + ASSERT (Srat != NULL); + ASSERT (MemAffInfo != NULL); + + MemAff = (EFI_ACPI_6_3_MEMORY_AFFINITY_STRUCTURE *)((UINT8*)Srat + + MemAffOffset); + + while (MemAffCount-- != 0) { + DEBUG ((DEBUG_INFO, "SRAT: MemAff = 0x%p\n", MemAff)); + + MemAff->Type = EFI_ACPI_6_3_MEMORY_AFFINITY; + MemAff->Length = sizeof (EFI_ACPI_6_3_MEMORY_AFFINITY_STRUCTURE); + MemAff->ProximityDomain = MemAffInfo->ProximityDomain; + MemAff->Reserved1 = EFI_ACPI_RESERVED_WORD; + MemAff->AddressBaseLow = (UINT32)(MemAffInfo->BaseAddress & MAX_UINT32); + MemAff->AddressBaseHigh = (UINT32)(MemAffInfo->BaseAddress >> 32); + MemAff->LengthLow = (UINT32)(MemAffInfo->Length & MAX_UINT32); + MemAff->LengthHigh = (UINT32)(MemAffInfo->Length >> 32); + MemAff->Reserved2 = EFI_ACPI_RESERVED_DWORD; + MemAff->Flags = MemAffInfo->Flags; + MemAff->Reserved3 = EFI_ACPI_RESERVED_QWORD; + + // Next + MemAff++; + MemAffInfo++; + }// while + return EFI_SUCCESS; +} + + +/** Add the Generic Initiator Affinity Structures in the SRAT Table. + + @param [in] CfgMgrProtocol Pointer to the Configuration Manager + Protocol Interface. + @param [in] Srat Pointer to the SRAT Table. + @param [in] GenInitAffOff Offset of the Generic Initiator Affinity + information in the SRAT Table. + @param [in] GenInitAffInfo Pointer to the Generic Initiator Affinity + Information list. + @param [in] GenInitAffCount Count of Generic Initiator Affinity + objects. + + @retval EFI_SUCCESS Table generated successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND The required object information is 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 +AddGenericInitiatorAffinity ( + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, + IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER * CONST Srat, + IN CONST UINT32 GenInitAffOff, + IN CONST CM_ARM_GENERIC_INITIATOR_AFFINITY_INFO * GenInitAffInfo, + IN UINT32 GenInitAffCount + ) +{ + EFI_STATUS Status; + EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY_STRUCTURE * GenInitAff; + CM_ARM_DEVICE_HANDLE_ACPI * DeviceHandleAcpi; + CM_ARM_DEVICE_HANDLE_PCI * DeviceHandlePci; + UINT32 DeviceHandleCount; + + ASSERT (Srat != NULL); + ASSERT (GenInitAffInfo != NULL); + + GenInitAff = (EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY_STRUCTURE *)( + (UINT8*)Srat + GenInitAffOff); + + while (GenInitAffCount-- != 0) { + DEBUG ((DEBUG_INFO, "SRAT: GenInitAff = 0x%p\n", GenInitAff)); + + GenInitAff->Type = EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY; + GenInitAff->Length = + sizeof (EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY_STRUCTURE); + GenInitAff->Reserved1 = EFI_ACPI_RESERVED_WORD; + GenInitAff->DeviceHandleType = GenInitAffInfo->DeviceHandleType; + GenInitAff->ProximityDomain = GenInitAffInfo->ProximityDomain; + + if (GenInitAffInfo->DeviceHandleToken == CM_NULL_TOKEN) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Invalid Device Handle Token.\n" + )); + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + if (GenInitAffInfo->DeviceHandleType == EFI_ACPI_6_3_ACPI_DEVICE_HANDLE) { + Status = GetEArmObjDeviceHandleAcpi ( + CfgMgrProtocol, + GenInitAffInfo->DeviceHandleToken, + &DeviceHandleAcpi, + &DeviceHandleCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to get ACPI Device Handle Inf." + " DeviceHandleToken = %p." + " Status = %r\n", + GenInitAffInfo->DeviceHandleToken, + Status + )); + return Status; + } + + // We are expecting only one device handle. + ASSERT (DeviceHandleCount == 1); + + // Populate the ACPI device handle information. + GenInitAff->DeviceHandle.Acpi.AcpiHid = DeviceHandleAcpi->Hid; + GenInitAff->DeviceHandle.Acpi.AcpiUid = DeviceHandleAcpi->Uid; + GenInitAff->DeviceHandle.Acpi.Reserved[0] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Acpi.Reserved[1] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Acpi.Reserved[2] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Acpi.Reserved[3] = EFI_ACPI_RESERVED_BYTE; + } else if (GenInitAffInfo->DeviceHandleType == + EFI_ACPI_6_3_PCI_DEVICE_HANDLE) { + Status = GetEArmObjDeviceHandlePci ( + CfgMgrProtocol, + GenInitAffInfo->DeviceHandleToken, + &DeviceHandlePci, + &DeviceHandleCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to get ACPI Device Handle Inf." + " DeviceHandleToken = %p." + " Status = %r\n", + GenInitAffInfo->DeviceHandleToken, + Status + )); + return Status; + } + + // We are expecting only one device handle + ASSERT (DeviceHandleCount == 1); + + // Populate the ACPI device handle information. + GenInitAff->DeviceHandle.Pci.PciSegment = DeviceHandlePci->SegmentNumber; + GenInitAff->DeviceHandle.Pci.PciBdfNumber = GetBdf (DeviceHandlePci); + + GenInitAff->DeviceHandle.Pci.Reserved[0] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[1] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[2] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[3] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[4] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[5] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[6] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[7] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[8] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[9] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[10] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->DeviceHandle.Pci.Reserved[11] = EFI_ACPI_RESERVED_BYTE; + } else { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Invalid Device Handle Type.\n" + )); + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + GenInitAff->Flags = GenInitAffInfo->Flags; + GenInitAff->Reserved2[0] = EFI_ACPI_RESERVED_BYTE; + GenInitAff->Reserved2[1] = EFI_ACPI_RESERVED_BYTE; + + // Next + GenInitAff++; + GenInitAffInfo++; + }// while + return Status; +} + +/** Construct the SRAT ACPI table. + + Called by the Dynamic Table Manager, 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. + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. +**/ +STATIC +EFI_STATUS +EFIAPI +BuildSratTable ( + 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 GicItsCount; + UINT32 MemAffCount; + UINT32 GenInitiatorAffCount; + + UINT32 GicCAffOffset; + UINT32 GicItsAffOffset; + UINT32 MemAffOffset; + UINT32 GenInitiatorAffOffset; + + CM_ARM_GICC_INFO * GicCInfo; + CM_ARM_GIC_ITS_INFO * GicItsInfo; + CM_ARM_MEMORY_AFFINITY_INFO * MemAffInfo; + CM_ARM_GENERIC_INITIATOR_AFFINITY_INFO * GenInitiatorAffInfo; + + EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER * Srat; + + ASSERT ( + (This != NULL) && + (AcpiTableInfo != NULL) && + (CfgMgrProtocol != NULL) && + (Table != NULL) && + (AcpiTableInfo->TableGeneratorId == This->GeneratorID) && + (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature) + ); + + if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) || + (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Requested table revision = %d is not supported. " + "Supported table revisions: 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: SRAT: Failed to get GICC Info. Status = %r\n", + Status + )); + goto error_handler; + } + + if (GicCCount == 0) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: GIC CPU Interface information not provided.\n" + )); + ASSERT (0); + Status = EFI_INVALID_PARAMETER; + goto error_handler; + } + + Status = GetEArmObjGicItsInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &GicItsInfo, + &GicItsCount + ); + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to get GIC ITS Info. Status = %r\n", + Status + )); + goto error_handler; + } + + Status = GetEArmObjMemoryAffinityInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &MemAffInfo, + &MemAffCount + ); + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to get Memory Affinity Info. Status = %r\n", + Status + )); + goto error_handler; + } + + Status = GetEArmObjGenericInitiatorAffinityInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &GenInitiatorAffInfo, + &GenInitiatorAffCount + ); + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to get Generic Initiator Affinity Info." + " Status = %r\n", + Status + )); + goto error_handler; + } + + // Calculate the size of the SRAT table + TableSize = sizeof (EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER); + + GicCAffOffset = TableSize; + TableSize += (sizeof (EFI_ACPI_6_3_GICC_AFFINITY_STRUCTURE) * GicCCount); + + if (GicItsCount != 0) { + GicItsAffOffset = TableSize; + TableSize += (sizeof (EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE) * + GicItsCount); + } + + if (MemAffCount != 0) { + MemAffOffset = TableSize; + TableSize += (sizeof (EFI_ACPI_6_3_MEMORY_AFFINITY_STRUCTURE) * + MemAffCount); + } + + if (GenInitiatorAffCount != 0) { + GenInitiatorAffOffset = TableSize; + TableSize += (sizeof (EFI_ACPI_6_3_GENERIC_INITIATOR_AFFINITY_STRUCTURE) * + GenInitiatorAffCount); + } + + // Allocate the Buffer for SRAT table + *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize); + if (*Table == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to allocate memory for SRAT Table, Size = %d," \ + " Status = %r\n", + TableSize, + Status + )); + goto error_handler; + } + + Srat = (EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER*)*Table; + + DEBUG (( + DEBUG_INFO, + "SRAT: Srat = 0x%p TableSize = 0x%x\n", + Srat, + TableSize + )); + + Status = AddAcpiHeader ( + CfgMgrProtocol, + This, + &Srat->Header, + AcpiTableInfo, + TableSize + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to add ACPI header. Status = %r\n", + Status + )); + goto error_handler; + } + + // Setup the Reserved fields + // Reserved1 must be set to 1 for backward compatibility + Srat->Reserved1 = 1; + Srat->Reserved2 = EFI_ACPI_RESERVED_QWORD; + + Status = AddGICCAffinity ( + CfgMgrProtocol, + Srat, + GicCAffOffset, + GicCInfo, + GicCCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to add GICC Affinity structures. Status = %r\n", + Status + )); + goto error_handler; + } + + if (GicItsCount != 0) { + Status = AddGICItsAffinity ( + CfgMgrProtocol, + Srat, + GicItsAffOffset, + GicItsInfo, + GicItsCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to add GIC ITS Affinity structures. Status = %r\n", + Status + )); + goto error_handler; + } + } + + if (MemAffCount != 0) { + Status = AddMemoryAffinity ( + CfgMgrProtocol, + Srat, + MemAffOffset, + MemAffInfo, + MemAffCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to add Memory Affinity structures. Status = %r\n", + Status + )); + goto error_handler; + } + } + + if (GenInitiatorAffCount != 0) { + Status = AddGenericInitiatorAffinity ( + CfgMgrProtocol, + Srat, + GenInitiatorAffOffset, + GenInitiatorAffInfo, + GenInitiatorAffCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SRAT: Failed to add Generic Initiator Affinity structures." + " Status = %r\n", + Status + )); + goto error_handler; + } + } + + return Status; + +error_handler: + + if (*Table != NULL) { + FreePool (*Table); + *Table = NULL; + } + + return Status; +} + +/** Free any resources allocated for constructing the SRAT. + + @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 +FreeSratTableResources ( + 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) && + (AcpiTableInfo != NULL) && + (CfgMgrProtocol != NULL) && + (AcpiTableInfo->TableGeneratorId == This->GeneratorID) && + (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature) + ); + + if ((Table == NULL) || (*Table == NULL)) { + DEBUG ((DEBUG_ERROR, "ERROR: SRAT: Invalid Table Pointer\n")); + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + FreePool (*Table); + *Table = NULL; + return EFI_SUCCESS; +} + +/** The SRAT Table Generator revision. +*/ +#define SRAT_GENERATOR_REVISION CREATE_REVISION (1, 0) + +/** The interface for the SRAT Table Generator. +*/ +STATIC +CONST +ACPI_TABLE_GENERATOR SratGenerator = { + // Generator ID + CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSrat), + // Generator Description + L"ACPI.STD.SRAT.GENERATOR", + // ACPI Table Signature + EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE, + // ACPI Table Revision supported by this Generator + EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION, + // Minimum supported ACPI Table Revision + EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION, + // Creator ID + TABLE_GENERATOR_CREATOR_ID_ARM, + // Creator Revision + SRAT_GENERATOR_REVISION, + // Build Table function + BuildSratTable, + // Free Resource function + FreeSratTableResources, + // 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 +AcpiSratLibConstructor ( + IN CONST EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE * CONST SystemTable + ) +{ + EFI_STATUS Status; + Status = RegisterAcpiTableGenerator (&SratGenerator); + DEBUG ((DEBUG_INFO, "SRAT: 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 +AcpiSratLibDestructor ( + IN CONST EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE * CONST SystemTable + ) +{ + EFI_STATUS Status; + Status = DeregisterAcpiTableGenerator (&SratGenerator); + DEBUG ((DEBUG_INFO, "SRAT: Deregister Generator. Status = %r\n", Status)); + ASSERT_EFI_ERROR (Status); + return Status; +}