| /** @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 <Library/AcpiLib.h> | |
| #include <Library/BaseLib.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/CmObjHelperLib.h> | |
| #include <Library/TableHelperLib.h> | |
| #include <Protocol/ConfigurationManagerProtocol.h> | |
| #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 | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT32 ProximityDomain; | |
| 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->X2ApicId = CmX2ApicAffinity->ApicId; | |
| X2ApicAffinity->Flags = CmX2ApicAffinity->Flags; | |
| 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; | |
| Status = GetProximityDomainId ( | |
| CfgMgrProtocol, | |
| CmX2ApicAffinity->ProximityDomain, | |
| CmX2ApicAffinity->ProximityDomainToken, | |
| &X2ApicAffinity->ProximityDomain | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| Status = GetProximityDomainId ( | |
| CfgMgrProtocol, | |
| CmX2ApicAffinity->ClockDomain, | |
| CmX2ApicAffinity->ClockDomainToken, | |
| &X2ApicAffinity->ClockDomain | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| 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->ApicId = CmX2ApicAffinity->ApicId & MAX_UINT8; | |
| ApicAffinity->Flags = CmX2ApicAffinity->Flags; | |
| ApicAffinity->LocalSapicEid = 0; | |
| ApicAffinity->ClockDomain = CmX2ApicAffinity->ClockDomain; | |
| Status = GetProximityDomainId ( | |
| CfgMgrProtocol, | |
| CmX2ApicAffinity->ProximityDomain, | |
| CmX2ApicAffinity->ProximityDomainToken, | |
| &ProximityDomain | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| ApicAffinity->ProximityDomain7To0 = (ProximityDomain & MAX_UINT8); | |
| ApicAffinity->ProximityDomain31To8[0] = (ProximityDomain >> 8) & MAX_UINT8; | |
| ApicAffinity->ProximityDomain31To8[1] = (ProximityDomain >> 16) & MAX_UINT8; | |
| ApicAffinity->ProximityDomain31To8[2] = (ProximityDomain >> 24) & MAX_UINT8; | |
| Status = GetProximityDomainId ( | |
| CfgMgrProtocol, | |
| CmX2ApicAffinity->ClockDomain, | |
| CmX2ApicAffinity->ClockDomainToken, | |
| &ApicAffinity->ClockDomain | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| ApicAffinity++; | |
| CmX2ApicAffinity++; | |
| } // while | |
| } | |
| return EFI_SUCCESS; | |
| } |