/** @file Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent Module Name: AcpiPlatformHooks.c Abstract: ACPI Platform Driver Hooks --*/ // // Statements that include other files. // #include "AcpiPlatform.h" #include "AcpiPlatformHooks.h" #include "Platform.h" // // Prototypes of the various hook functions. // #include "AcpiPlatformHooksLib.h" extern SYSTEM_CONFIGURATION mSystemConfiguration; ENHANCED_SPEEDSTEP_PROTOCOL *mEistProtocol = NULL; EFI_CPU_ID_MAP mCpuApicIdAcpiIdMapTable[MAX_CPU_NUM]; EFI_STATUS AppendCpuMapTableEntry ( IN EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE *AcpiLocalApic ) { BOOLEAN Added; UINTN Index; for (Index = 0; Index < MAX_CPU_NUM; Index++) { if ((mCpuApicIdAcpiIdMapTable[Index].ApicId == AcpiLocalApic->ApicId) && mCpuApicIdAcpiIdMapTable[Index].Flags) { return EFI_SUCCESS; } } Added = FALSE; for (Index = 0; Index < MAX_CPU_NUM; Index++) { if (!mCpuApicIdAcpiIdMapTable[Index].Flags) { mCpuApicIdAcpiIdMapTable[Index].Flags = 1; mCpuApicIdAcpiIdMapTable[Index].ApicId = AcpiLocalApic->ApicId; mCpuApicIdAcpiIdMapTable[Index].AcpiProcessorId = AcpiLocalApic->AcpiProcessorId; Added = TRUE; break; } } ASSERT (Added); return EFI_SUCCESS; } UINT32 ProcessorId2ApicId ( UINT32 AcpiProcessorId ) { UINTN Index; ASSERT (AcpiProcessorId < MAX_CPU_NUM); for (Index = 0; Index < MAX_CPU_NUM; Index++) { if (mCpuApicIdAcpiIdMapTable[Index].Flags && (mCpuApicIdAcpiIdMapTable[Index].AcpiProcessorId == AcpiProcessorId)) { return mCpuApicIdAcpiIdMapTable[Index].ApicId; } } return (UINT32) -1; } UINT8 GetProcNumberInPackage ( IN UINT8 Package ) { UINTN Index; UINT8 Number; Number = 0; for (Index = 0; Index < MAX_CPU_NUM; Index++) { if (mCpuApicIdAcpiIdMapTable[Index].Flags && (((mCpuApicIdAcpiIdMapTable[Index].ApicId >> 0x04) & 0x01) == Package)) { Number++; } } return Number; } EFI_STATUS LocateCpuEistProtocol ( IN UINT32 CpuIndex, OUT ENHANCED_SPEEDSTEP_PROTOCOL **EistProtocol ) { UINTN HandleCount; EFI_HANDLE *HandleBuffer; ENHANCED_SPEEDSTEP_PROTOCOL *EistProt; UINTN Index; UINT32 ApicId; EFI_STATUS Status; HandleCount = 0; gBS->LocateHandleBuffer ( ByProtocol, &gEnhancedSpeedstepProtocolGuid, NULL, &HandleCount, &HandleBuffer ); Index = 0; EistProt = NULL; Status = EFI_NOT_FOUND; while (Index < HandleCount) { gBS->HandleProtocol ( HandleBuffer[Index], &gEnhancedSpeedstepProtocolGuid, (VOID **) &EistProt ); // // Adjust the CpuIndex by +1 due to the AcpiProcessorId is 1 based. // ApicId = ProcessorId2ApicId (CpuIndex+1); if (ApicId == (UINT32) -1) { break; } if (EistProt->ProcApicId == ApicId) { Status = EFI_SUCCESS; break; } Index++; } if (HandleBuffer != NULL) { gBS->FreePool (HandleBuffer); } if (!EFI_ERROR (Status)) { *EistProtocol = EistProt; } else { *EistProtocol = NULL; } return Status; } EFI_STATUS PlatformHookInit ( VOID ) { EFI_STATUS Status; Status = gBS->LocateProtocol ( &gEnhancedSpeedstepProtocolGuid, NULL, (VOID **) &mEistProtocol ); ASSERT_EFI_ERROR (Status); return Status; } /** Called for every ACPI table found in the BIOS flash. Returns whether a table is active or not. Inactive tables are not published in the ACPI table list. This hook can be used to implement optional SSDT tables or enabling/disabling specific functionality (e.g. SPCR table) based on a setup switch or platform preference. In case of optional SSDT tables,the platform flash will include all the SSDT tables but will return EFI_SUCCESS only for those tables that need to be published. @param[in] *Table Pointer to the active table. @retval EFI_SUCCESS if the table is active. @retval EFI_UNSUPPORTED if the table is not active. **/ EFI_STATUS AcpiPlatformHooksIsActiveTable ( IN OUT EFI_ACPI_COMMON_HEADER *Table ) { EFI_ACPI_DESCRIPTION_HEADER *TableHeader; TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table; if (TableHeader->Signature == EFI_ACPI_2_0_STATIC_RESOURCE_AFFINITY_TABLE_SIGNATURE) { } if ((mSystemConfiguration.ENDBG2 == 0) && (CompareMem (&TableHeader->OemTableId, "INTLDBG2", 8) == 0)) { return EFI_UNSUPPORTED; } return EFI_SUCCESS; } /** Update the GV3 SSDT table. @param[in][out] *TableHeader The table to be set. @retval EFI_SUCCESS Returns Success. **/ EFI_STATUS PatchGv3SsdtTable ( IN OUT EFI_ACPI_DESCRIPTION_HEADER *TableHeader ) { UINT8 *CurrPtr; UINT8 *SsdtPointer; UINT32 Signature; UINT32 CpuFixes; UINT32 NpssFixes; UINT32 SpssFixes; UINT32 CpuIndex; UINT32 PackageSize; UINT32 NewPackageSize; UINT32 AdjustSize; UINTN EntryIndex; UINTN TableIndex; EFI_ACPI_NAME_COMMAND *PssTable; EFI_PSS_PACKAGE *PssTableItemPtr; ENHANCED_SPEEDSTEP_PROTOCOL *EistProt; EIST_INFORMATION *EistInfo; EFI_ACPI_CPU_PSS_STATE *PssState; EFI_ACPI_NAMEPACK_DWORD *NamePtr; // // Loop through the ASL looking for values that we must fix up. // NpssFixes = 0; SpssFixes = 0; CpuFixes = 0; CpuIndex = 0; CurrPtr = (UINT8 *) TableHeader; EistProt = NULL; for (SsdtPointer = CurrPtr; SsdtPointer <= (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); SsdtPointer++) { Signature = *(UINT32 *) SsdtPointer; switch (Signature) { case SIGNATURE_32 ('_', 'P', 'R', '_'): // // _CPUX ('0' to '0xF') // CpuIndex = *(SsdtPointer + 7); if (CpuIndex >= '0' && CpuIndex <= '9') { CpuIndex -= '0'; } else { if (CpuIndex > '9') { CpuIndex -= '7'; } } CpuFixes++; LocateCpuEistProtocol (CpuIndex, &EistProt); break; case SIGNATURE_32 ('D', 'O', 'M', 'N'): NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (SsdtPointer); if (NamePtr->StartByte != AML_NAME_OP) { continue; } if (NamePtr->Size != AML_NAME_DWORD_SIZE) { continue; } NamePtr->Value = 0; if (mCpuApicIdAcpiIdMapTable[CpuIndex].Flags) { NamePtr->Value = (mCpuApicIdAcpiIdMapTable[CpuIndex].ApicId >> 0x04) & 0x01; } break; case SIGNATURE_32 ('N', 'C', 'P', 'U'): NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (SsdtPointer); if (NamePtr->StartByte != AML_NAME_OP) { continue; } if (NamePtr->Size != AML_NAME_DWORD_SIZE) { continue; } NamePtr->Value = 0; if (mCpuApicIdAcpiIdMapTable[CpuIndex].Flags) { NamePtr->Value = GetProcNumberInPackage ((mCpuApicIdAcpiIdMapTable[CpuIndex].ApicId >> 0x04) & 0x01); } break; case SIGNATURE_32 ('N', 'P', 'S', 'S'): case SIGNATURE_32 ('S', 'P', 'S', 'S'): if (EistProt == NULL) { continue; } PssTable = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer); if (PssTable->StartByte != AML_NAME_OP) { continue; } EistProt->GetEistTable (EistProt, &EistInfo, (VOID **) &PssState); AdjustSize = PssTable->NumEntries * sizeof (EFI_PSS_PACKAGE); AdjustSize -= EistInfo->NumStates * sizeof (EFI_PSS_PACKAGE); PackageSize = (PssTable->Size & 0xF) + ((PssTable->Size & 0xFF00) >> 4); NewPackageSize = PackageSize - AdjustSize; PssTable->Size = (UINT16) ((NewPackageSize & 0xF) + ((NewPackageSize & 0x0FF0) << 4)); // // Set most significant two bits of byte zero to 01, meaning two bytes used. // PssTable->Size |= 0x40; // // Set unused table to Noop Code. // SetMem( (UINT8 *) PssTable + NewPackageSize + AML_NAME_PREFIX_SIZE, AdjustSize, AML_NOOP_OP); PssTable->NumEntries = (UINT8) EistInfo->NumStates; PssTableItemPtr = (EFI_PSS_PACKAGE *) ((UINT8 *) PssTable + sizeof (EFI_ACPI_NAME_COMMAND)); // // Update the size. // for (TableIndex = 0; TableIndex < EistInfo->NumStates; TableIndex++) { EntryIndex = EistInfo->NumStates - TableIndex - 1; PssTableItemPtr->CoreFreq = PssState[EntryIndex].CoreFrequency * PssState[EntryIndex].Control; PssTableItemPtr->Power = PssState[EntryIndex].Power * 1000; if (PssTable->NameStr == SIGNATURE_32 ('N', 'P', 'S', 'S')) { PssTableItemPtr->BMLatency = PssState[EntryIndex].BusMasterLatency; PssTableItemPtr->TransLatency = PssState[EntryIndex].TransitionLatency; } else { // // This method should be supported by SMM PPM Handler. // PssTableItemPtr->BMLatency = PssState[EntryIndex].BusMasterLatency * 2; PssTableItemPtr->TransLatency = PssState[EntryIndex].TransitionLatency * 10; } PssTableItemPtr->Control = PssState[EntryIndex].Control; PssTableItemPtr->Status = PssState[EntryIndex].Status; PssTableItemPtr++; } if (PssTable->NameStr == SIGNATURE_32 ('N', 'P', 'S', 'S')) { NpssFixes++; } else { SpssFixes++; } SsdtPointer = (UINT8 *) PssTable + PackageSize; break; } } // // N fixes together currently. // ASSERT (CpuFixes == (UINT32) MAX_CPU_NUM); ASSERT (SpssFixes == NpssFixes); ASSERT (CpuFixes >= SpssFixes); return EFI_SUCCESS; } /** Update the DSDT table. @param[in][out] *TableHeader The table to be set. @retval EFI_SUCCESS Returns EFI_SUCCESS. **/ EFI_STATUS PatchDsdtTable ( IN OUT EFI_ACPI_DESCRIPTION_HEADER *TableHeader ) { UINT8 *CurrPtr; UINT8 *DsdtPointer; UINT32 *Signature; UINT8 *EndPtr; UINT8 *Operation; UINT32 *Address; UINT16 *Size; // // Fix PCI32 resource "FIX0" -- PSYS system status area // CurrPtr = (UINT8*) &((EFI_ACPI_DESCRIPTION_HEADER*) TableHeader)[0]; EndPtr = (UINT8*) TableHeader; EndPtr = EndPtr + TableHeader->Length; while (CurrPtr < (EndPtr-2)) { // // Removed the _S3 tag to indicate that we do not support S3. The 4th byte is blank space // since there are only 3 char "_S3". // if (mSystemConfiguration.AcpiSuspendState == 0) { // // For iasl compiler version 20061109. // if ((CurrPtr[0] == '_') && (CurrPtr[1] == 'S') && (CurrPtr[2] == '3') && (CurrPtr[3] == '_')) { break; } // // For iasl compiler version 20040527. // if ((CurrPtr[0] == '\\') && (CurrPtr[1] == '_') && (CurrPtr[2] == 'S') && (CurrPtr[3] == '3')) { break; } } CurrPtr++; } CurrPtr = (UINT8*) &((EFI_ACPI_DESCRIPTION_HEADER*) TableHeader)[0]; EndPtr = (UINT8*) TableHeader; EndPtr = EndPtr + TableHeader->Length; while (CurrPtr < (EndPtr-2)) { // // For mipi dsi port select _DEP. // if (mSystemConfiguration.MipiDsi== 1) { // // For iasl compiler version 20061109. // if ((CurrPtr[0] == 'N') && (CurrPtr[1] == 'D') && (CurrPtr[2] == 'E') && (CurrPtr[3] == 'P')) { CurrPtr[0] = '_'; break; } } else { if ((CurrPtr[0] == 'P') && (CurrPtr[1] == 'D') && (CurrPtr[2] == 'E') && (CurrPtr[3] == 'P')) { CurrPtr[0] = '_'; break; } } CurrPtr++; } // // Loop through the ASL looking for values that we must fix up. // CurrPtr = (UINT8 *) TableHeader; for (DsdtPointer = CurrPtr; DsdtPointer <= (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); DsdtPointer++) { Signature = (UINT32 *) DsdtPointer; switch (*Signature) { // // GNVS operation region. // case (SIGNATURE_32 ('G', 'N', 'V', 'S')): // // Conditional match. For Region Objects, the Operator will always be the // byte immediately before the specific name. Therefore, subtract 1 to check // the Operator. // Operation = DsdtPointer - 1; if (*Operation == AML_OPREGION_OP) { Address = (UINT32 *) (DsdtPointer + 6); *Address = (UINT32) (UINTN) mGlobalNvsArea.Area; Size = (UINT16 *) (DsdtPointer + 11); *Size = sizeof (EFI_GLOBAL_NVS_AREA); } break; default: break; } } return EFI_SUCCESS; }