/** @file X64 SRAT Table Generator Copyright (c) 2019 - 2020, Arm Limited. All rights reserved. Copyright (C) 2025 Advanced Micro Devices, Inc. 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 #include "SratGenerator.h" /** This macro is used to get the object information for the Local APIC X2APIC Affinity object. */ GET_OBJECT_LIST ( EObjNameSpaceX64, EX64ObjLocalApicX2ApicAffinityInfo, CM_X64_LOCAL_APIC_X2APIC_AFFINITY_INFO ); /** Enum of the X64 specific CM objects required to build the arch specific information of the SRAT table. */ typedef enum X64SratSubTableType { EX64LocalApicX2ApicAffinityTableType, EX64SubTableTypeMax } EX64_SRAT_SUB_TABLE_TYPE; typedef struct SratSubTable { /// Start offset of the arch specific sub-table. UINT32 Offset; /// Count UINT32 Count; /// Array of CmInfo objects of the relevant type. VOID *CmInfo; } SRAT_SUB_TABLE; STATIC SRAT_SUB_TABLE mSratSubTable[EX64SubTableTypeMax]; /** Reserve arch sub-tables space. @param [in] CfgMgrProtocol Pointer to the Configuration Manager @param [in, out] ArchOffset On input, contains the offset where arch specific sub-tables can be written. It is expected that there enough space to write all the arch specific sub-tables from this offset onward. On ouput, contains the ending offset of the arch specific sub-tables. @retval EFI_SUCCESS Table generated successfully. @retval EFI_UNSUPPORTED Not supported. @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. **/ EFI_STATUS EFIAPI ArchReserveOffsets ( IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol, IN OUT UINT32 *ArchOffset ) { CM_X64_LOCAL_APIC_X2APIC_AFFINITY_INFO *CmX2ApicAffinity; EFI_STATUS Status; LOCAL_APIC_MODE ApicMode; UINT32 CmCount; UINT32 Index; ASSERT (CfgMgrProtocol != NULL); ASSERT (ArchOffset != NULL); Status = GetEX64ObjLocalApicX2ApicAffinityInfo ( CfgMgrProtocol, CM_NULL_TOKEN, &CmX2ApicAffinity, &CmCount ); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "ERROR: SRAT: Failed to get Local Apic/X2Apic Affinity Info. Status = %r\n", Status )); return Status; } if (CmCount == 0) { DEBUG (( DEBUG_ERROR, "ERROR: SRAT: Local Apic/X2Apic Affinity information not provided.\n" )); ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); return EFI_INVALID_PARAMETER; } ApicMode = CmX2ApicAffinity[0].ApicMode; for (Index = 0; Index < CmCount; Index++) { if ((CmX2ApicAffinity[Index].Flags & ~EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED) != 0) { DEBUG (( DEBUG_ERROR, "ERROR: SRAT: Invalid Flags. Flags = 0x%x\n", CmX2ApicAffinity[Index].Flags )); ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); return EFI_INVALID_PARAMETER; } if (CmX2ApicAffinity[Index].ApicMode == LocalApicModeXApic) { if (CmX2ApicAffinity[Index].ApicId > MAX_UINT8) { DEBUG (( DEBUG_ERROR, "ERROR: SRAT: Local Apic Id is invalid. ApicId = 0x%x\n", CmX2ApicAffinity[Index].ApicId )); ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); return EFI_INVALID_PARAMETER; } } if (CmX2ApicAffinity[Index].ApicMode != ApicMode) { DEBUG (( DEBUG_ERROR, "ERROR: SRAT: Mixed Apic Modes are not supported.\n" )); ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); return EFI_INVALID_PARAMETER; } } mSratSubTable[EX64LocalApicX2ApicAffinityTableType].CmInfo = CmX2ApicAffinity; mSratSubTable[EX64LocalApicX2ApicAffinityTableType].Count = CmCount; mSratSubTable[EX64LocalApicX2ApicAffinityTableType].Offset = *ArchOffset; if (CmX2ApicAffinity[0].ApicMode == LocalApicModeX2Apic) { *ArchOffset += sizeof (EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE) * CmCount; } else { *ArchOffset += sizeof (EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE) * CmCount; } return EFI_SUCCESS; } /** Add the arch specific sub-tables to the SRAT table. These sub-tables are written in the space reserved beforehand. @param [in] CfgMgrProtocol Pointer to the Configuration Manager Protocol Interface. @param [in] Srat Pointer to the SRAT Table. @retval EFI_SUCCESS Table generated successfully. @retval EFI_UNSUPPORTED Not supported. **/ EFI_STATUS EFIAPI AddArchObjects ( IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol, IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER *CONST Srat ) { CM_X64_LOCAL_APIC_X2APIC_AFFINITY_INFO *CmX2ApicAffinity; EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE *ApicAffinity; EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE *X2ApicAffinity; CmX2ApicAffinity = (CM_X64_LOCAL_APIC_X2APIC_AFFINITY_INFO *) mSratSubTable[EX64LocalApicX2ApicAffinityTableType].CmInfo; if (CmX2ApicAffinity->ApicMode == LocalApicModeX2Apic) { X2ApicAffinity = (EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE *) ((UINT8 *)Srat + mSratSubTable[EX64LocalApicX2ApicAffinityTableType].Offset); while (mSratSubTable[EX64LocalApicX2ApicAffinityTableType].Count-- != 0) { X2ApicAffinity->Type = EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_AFFINITY; X2ApicAffinity->Length = sizeof (EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE); X2ApicAffinity->Reserved1[0] = EFI_ACPI_RESERVED_BYTE; X2ApicAffinity->Reserved1[1] = EFI_ACPI_RESERVED_BYTE; X2ApicAffinity->ProximityDomain = CmX2ApicAffinity->ProximityDomain; X2ApicAffinity->X2ApicId = CmX2ApicAffinity->ApicId; X2ApicAffinity->Flags = CmX2ApicAffinity->Flags; X2ApicAffinity->ClockDomain = CmX2ApicAffinity->ClockDomain; X2ApicAffinity->Reserved2[0] = EFI_ACPI_RESERVED_BYTE; X2ApicAffinity->Reserved2[1] = EFI_ACPI_RESERVED_BYTE; X2ApicAffinity->Reserved2[2] = EFI_ACPI_RESERVED_BYTE; X2ApicAffinity->Reserved2[3] = EFI_ACPI_RESERVED_BYTE; X2ApicAffinity++; // Next CmX2ApicAffinity++; } } else { ApicAffinity = (EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE *) ((UINT8 *)Srat + mSratSubTable[EX64LocalApicX2ApicAffinityTableType].Offset); while (mSratSubTable[EX64LocalApicX2ApicAffinityTableType].Count-- != 0) { ApicAffinity->Type = EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY; ApicAffinity->Length = sizeof (EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE); ApicAffinity->ProximityDomain7To0 = (CmX2ApicAffinity->ProximityDomain & MAX_UINT8); ApicAffinity->ApicId = CmX2ApicAffinity->ApicId & MAX_UINT8; ApicAffinity->Flags = CmX2ApicAffinity->Flags; ApicAffinity->LocalSapicEid = 0; ApicAffinity->ProximityDomain31To8[0] = (CmX2ApicAffinity->ProximityDomain >> 8) & MAX_UINT8; ApicAffinity->ProximityDomain31To8[0] = (CmX2ApicAffinity->ProximityDomain >> 16) & MAX_UINT8; ApicAffinity->ProximityDomain31To8[0] = (CmX2ApicAffinity->ProximityDomain >> 24) & MAX_UINT8; ApicAffinity->ClockDomain = CmX2ApicAffinity->ClockDomain; ApicAffinity++; CmX2ApicAffinity++; } // while } return EFI_SUCCESS; }