/** @file ACPI Platform Driver Hooks @copyright Copyright 1996 - 2020 Intel Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ // // Statements that include other files // #include "AcpiPlatformLibLocal.h" #include #include #include #include #include extern BIOS_ACPI_PARAM *mAcpiParameter; EFI_PLATFORM_INFO *mPlatformInfo; EFI_CPU_CSR_ACCESS_PROTOCOL *mCpuCsrAccess; EFI_ACPI_TABLE_PROTOCOL *mAcpiTable; extern EFI_IIO_UDS_PROTOCOL *mIioUds; CPU_CSR_ACCESS_VAR *mCpuCsrAccessVarPtr; UINT32 mNumOfBitShift; BOOLEAN mX2ApicEnabled; SYSTEM_MEMORY_MAP_HOB *mSystemMemoryMap; SOCKET_MEMORY_CONFIGURATION mSocketMemoryConfiguration; SOCKET_MP_LINK_CONFIGURATION mSocketMpLinkConfiguration; SOCKET_IIO_CONFIGURATION mSocketIioConfiguration; SOCKET_POWERMANAGEMENT_CONFIGURATION mSocketPowermanagementConfiguration; SOCKET_COMMONRC_CONFIGURATION mSocketCommonRcConfiguration; SOCKET_PROCESSORCORE_CONFIGURATION mSocketProcessorCoreConfiguration; CPU_CONFIG_CONTEXT_BUFFER *mCpuConfigLibConfigContextBuffer = NULL; EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE *mSpcrTable = NULL; /** The constructor function of AcpiPlatormL Library. The constructor function caches the value of PCD entry @param ImageHandle The firmware allocated handle for the EFI image. @param SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. **/ EFI_STATUS EFIAPI AcpiPlatformLibConstructor ( VOID ) { EFI_STATUS Status; EFI_HOB_GUID_TYPE *GuidHob; DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL; mCpuConfigLibConfigContextBuffer = (CPU_CONFIG_CONTEXT_BUFFER *) (UINTN) PcdGet64 (PcdCpuConfigContextBuffer); if (mCpuConfigLibConfigContextBuffer == NULL) { ASSERT_EFI_ERROR (RETURN_NOT_FOUND); return RETURN_NOT_FOUND; } Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, (VOID **) &DynamicSiLibraryProtocol); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR (Status); return Status; } GuidHob = GetFirstGuidHob (&gEfiPlatformInfoGuid); if (GuidHob == NULL) { ASSERT (GuidHob != NULL); return EFI_NOT_FOUND; } mPlatformInfo = GET_GUID_HOB_DATA (GuidHob); // // Locate the IIO Protocol Interface // Status = gBS->LocateProtocol (&gEfiIioUdsProtocolGuid, NULL, (VOID **) &mIioUds); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR (Status); return Status; } Status = gBS->LocateProtocol (&gEfiCpuCsrAccessGuid, NULL, (VOID **) &mCpuCsrAccess); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR (Status); return Status; } mCpuCsrAccessVarPtr = DynamicSiLibraryProtocol->GetSysCpuCsrAccessVar (); mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData (); ASSERT (mSystemMemoryMap != NULL); mMpService = NULL; Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **) &mMpService); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR (Status); return Status; } // // Determine the number of processors // mMpService->GetNumberOfProcessors ( mMpService, &mNumberOfCPUs, &mNumberOfEnabledCPUs ); ASSERT (mNumberOfCPUs <= MAX_CPU_NUM && mNumberOfEnabledCPUs >= 1); if (mNumberOfCPUs > MAX_CPU_NUM) { mNumberOfCPUs = MAX_CPU_NUM; } Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &mAcpiTable); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR (Status); return Status; } return EFI_SUCCESS; } /** Platform hook to initialize Platform Specific ACPI Parameters @retval EFI_SUCCESS Platform specific parameters in mAcpiParameter initialized successfully. @retval EFI_INVALID_PARAMETER mAcpiParameter global was NULL. **/ EFI_STATUS PlatformHookAfterAcpiParamInit ( VOID ) { EFI_STATUS Status; Status = EFI_SUCCESS; if (mAcpiParameter == NULL) { ASSERT (mAcpiParameter != NULL); return EFI_INVALID_PARAMETER; } DEBUG ((DEBUG_INFO, "ACPI Parameter Block Address: 0x%X\n", mAcpiParameter)); // // Call for Local APIC ID Reorder // Status = SortCpuLocalApicInTable (); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "[ACPI] ERROR: SortCpuLocalApicInTable failed: %r\n", Status)); return Status; } return Status; } EFI_STATUS AcpiPlatformHooksIsActiveTable ( IN OUT EFI_ACPI_COMMON_HEADER *Table ) { EFI_NFIT_TABLE_UPDATE_PROTOCOL *NfitTableUpdateProtocol; EFI_ACPI_DESCRIPTION_HEADER *TableHeader; EFI_STATUS Status; SETUP_DATA SetupData; SYSTEM_CONFIGURATION SystemConfiguration; UINT8 *OemSkuAcpiName; Status = GetEntireConfig (&SetupData); ASSERT_EFI_ERROR (Status); CopyMem (&SystemConfiguration, &(SetupData.SystemConfig), sizeof(SYSTEM_CONFIGURATION)); if (mSystemMemoryMap == NULL) { ASSERT (FALSE); return EFI_NOT_FOUND; } TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table; if (TableHeader->Signature == ACPI_PMTT_TABLE_SIGNATURE) { if (!mSystemMemoryMap->DcpmmPresent) { return EFI_NOT_FOUND; } } if (TableHeader->Signature == EFI_BDAT_TABLE_SIGNATURE) { if (mSocketMemoryConfiguration.bdatEn == 0) { return EFI_NOT_FOUND; } } if (TableHeader->Signature == NVDIMM_PLATFORM_CONFIG_ATTRIBUTE_TABLE_SIGNATURE) { if (mSystemMemoryMap->DcpmmPresent == 0) { return EFI_NOT_FOUND; } } if (TableHeader->Signature == NVDIMM_FW_INTERFACE_TABLE_SIGNATURE) { Status = gBS->LocateProtocol (&gEfiNfitTableUpdateProtocolGuid, NULL, (VOID **) &NfitTableUpdateProtocol); if (EFI_ERROR (Status)){ // If NfitTableUpdateProtocol is not found we assume no NVDIMM is present - it means don't publish NFIT DEBUG ((DEBUG_ERROR, "NfitTableUpdateProtocol is not installed.\n")); return EFI_NOT_FOUND; } } if (TableHeader->Signature == EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE) { // // Initialize the SPCR table pointer. // SPCR table is not ready yet, update it before booting. // mSpcrTable = (EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE *) Table; return EFI_NOT_READY; } if ((TableHeader->Signature == EFI_ACPI_6_2_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE) || (TableHeader->Signature == EFI_ACPI_6_2_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE) || (TableHeader->Signature == EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE) || TableHeader->Signature == EFI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE) { // // Only publish SRAT/SLIT/MSCT/HMAT if NUMA is enabled in setup. // if (!mSocketCommonRcConfiguration.NumaEn) { DEBUG ((DEBUG_INFO, "[ACPI] NUMA disabled, do not publish '%c%c%c%c' table\n", ((CHAR8*)&TableHeader->Signature)[0], ((CHAR8*)&TableHeader->Signature)[1], ((CHAR8*)&TableHeader->Signature)[2], ((CHAR8*)&TableHeader->Signature)[3])); return EFI_NOT_FOUND; } } if (TableHeader->Signature == EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE) { return EFI_NOT_FOUND; } if (TableHeader->Signature == EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { OemSkuAcpiName = PcdGetPtr (PcdOemSkuAcpiName); if (OemSkuAcpiName == NULL) { return EFI_UNSUPPORTED; } if ( (0 == CompareMem (&(TableHeader->OemTableId), OemSkuAcpiName, 8)) ) { Status = PlatformGetAcpiFixTableDataPointer ((VOID ** ) &mAmlOffsetTablePointer); if (!EFI_ERROR(Status)) { DEBUG((DEBUG_INFO, "[ACPI] Platform DSDT Fixup table found\n")); DEBUG((DEBUG_INFO, "[ACPI] Platform SRP: Using %a DSDT\n", OemSkuAcpiName)); return EFI_SUCCESS; } else { DEBUG((DEBUG_ERROR, "[ACPI] Platform DSDT Fixup table not found.\n")); return EFI_UNSUPPORTED; } } else { DEBUG ((DEBUG_INFO, "[ACPI] Platform DSDT OemSkuAcpiName '%c%c%c%c%c%c%c%c':\n", ((CHAR8*)OemSkuAcpiName)[0], ((CHAR8*)OemSkuAcpiName)[1], ((CHAR8*)OemSkuAcpiName)[2], ((CHAR8*)OemSkuAcpiName)[3], ((CHAR8*)OemSkuAcpiName)[4], ((CHAR8*)OemSkuAcpiName)[5], ((CHAR8*)OemSkuAcpiName)[6], ((CHAR8*)OemSkuAcpiName)[7])); DEBUG ((DEBUG_INFO, " no match for OemTableId '%c%c%c%c%c%c%c%c' from FwVol.\n", ((CHAR8*)&TableHeader->OemTableId)[0], ((CHAR8*)&TableHeader->OemTableId)[1], ((CHAR8*)&TableHeader->OemTableId)[2], ((CHAR8*)&TableHeader->OemTableId)[3], ((CHAR8*)&TableHeader->OemTableId)[4], ((CHAR8*)&TableHeader->OemTableId)[5], ((CHAR8*)&TableHeader->OemTableId)[6], ((CHAR8*)&TableHeader->OemTableId)[7])); return EFI_UNSUPPORTED; } } // // Hooks for checking additional platform ACPI Table is active or not. // If ACPI Table is not in list, it should be reported and returned EFI_SUCCESS. // return PlatformAcpiReportHooksTableIsActive (Table); } /** This function will update any runtime platform specific information. This currently includes: Setting OEM table values, ID, table ID, creator ID and creator revision. Enabling the proper processor entries in the APIC tables. @param Table - The table to update @retval EFI_SUCCESS - The function completed successfully. **/ EFI_STATUS PlatformUpdateTables ( IN OUT EFI_ACPI_COMMON_HEADER *Table, IN OUT EFI_ACPI_TABLE_VERSION *Version ) { EFI_ACPI_DESCRIPTION_HEADER *TableHeader; EFI_STATUS Status; ACPI_APIC_STRUCTURE_PTR *ProcessorLocalApicEntry; UINT64 TempOemTableId; UINT32 Data32; DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, (VOID **) &DynamicSiLibraryProtocol2); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR (Status); return Status; } TableHeader = NULL; ProcessorLocalApicEntry = NULL; Status = EFI_SUCCESS; // // By default, a table belongs in all ACPI table versions published. // Some tables will override this because they have different versions of the table. // *Version = EFI_ACPI_TABLE_VERSION_2_0; if (Table->Signature != EFI_ACPI_6_2_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE && Table->Signature != EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE && Table->Signature != SIGNATURE_32('N', 'F', 'I', 'T') && Table->Signature != SIGNATURE_32('P', 'C', 'A', 'T') && Table->Signature != SIGNATURE_32('O', 'E', 'M', '1') && Table->Signature != SIGNATURE_32('O', 'E', 'M', '2') && Table->Signature != SIGNATURE_32('O', 'E', 'M', '3') && Table->Signature != SIGNATURE_32('O', 'E', 'M', '4')) { TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table; // // Update the OEMID and OEM Table ID. // TempOemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); CopyMem (TableHeader->OemId, PcdGetPtr(PcdAcpiDefaultOemId), sizeof(TableHeader->OemId)); CopyMem (&TableHeader->OemTableId, &TempOemTableId, sizeof(TableHeader->OemTableId)); // // Update the creator ID // TableHeader->CreatorId = EFI_ACPI_CREATOR_ID; // // Update the creator revision // TableHeader->CreatorRevision = EFI_ACPI_CREATOR_REVISION; } // // Complete this function // //ASSERT (mMaxNumberOfCPUs <= MAX_CPU_NUM && mNumberOfEnabledCPUs >= 1); // // Assign a invalid intial value for update // // // Update the processors in the APIC table // DEBUG ((DEBUG_INFO, "[ACPI] Patching '%c%c%c%c' table...\n", ((CHAR8*)&Table->Signature)[0], ((CHAR8*)&Table->Signature)[1], ((CHAR8*)&Table->Signature)[2], ((CHAR8*)&Table->Signature)[3])); switch (Table->Signature) { // // Do not allow a prebuilt MADT, since it is built dynamically. // case EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE: DEBUG ((DEBUG_ERROR, "[ACPI] ERROR: Prebuilt MADT found\n")); Status = EFI_INVALID_PARAMETER; ASSERT_EFI_ERROR (Status); break; case EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE: Status = PatchFadtTable (Table); break; case EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE: // // Patch the memory resource // Status = PatchDsdtTable (Table); break; case EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE: Status = PatchSsdtTable (Table,Version); break; case EFI_ACPI_6_2_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE: // // Adjust HPET Table to correct the Base Address // Get the address bits in RCRB that configure HPET MMIO space // and create an offset to the pre-defined HEPT base address // DynamicSiLibraryProtocol2->PchHpetBaseGet (&Data32); // // Add the offset to the base address and copy into HPET DSDT table // ((EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *) Table)->BaseAddressLower32Bit.Address = Data32; break; case EFI_ACPI_6_2_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE: Status = PatchMcfgAcpiTable (Table); break; case EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE: Status = PatchSpcrAcpiTable (Table); break; case ACPI_PMTT_TABLE_SIGNATURE: if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) { Status = PatchPlatformMemoryTopologyTable (Table); } break; case EFI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE: if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) { Status = PatchHmatAcpiTable (Table); } break; case EFI_ACPI_6_2_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE: if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) { Status = PatchMsctAcpiTable (Table); } break; case EFI_MIGT_ACPI_TABLE_SIGNATURE: if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) { if (PcdGetBool (ReservedB)) { Status = PatchMigtAcpiTable (Table); } } break; case EFI_BDAT_TABLE_SIGNATURE: if (!PcdGetBool (PcdPlatformNotSupportAcpiBdatTable)) { Status = PatchBdatAcpiTable (Table); } break; case NVDIMM_FW_INTERFACE_TABLE_SIGNATURE: Status = UpdateNfitTable (Table); break; case NVDIMM_PLATFORM_CONFIG_ATTRIBUTE_TABLE_SIGNATURE: Status = UpdatePcatTable (Table); break; //Patch Dynamic OEM SSDT table case OEM1_SSDT_TABLE_SIGNATURE: Status = PatchOem1SsdtTable (Table); //CPU EIST break; case OEM2_SSDT_TABLE_SIGNATURE: Status = PatchOem2SsdtTable (Table); //CPU HWP break; case OEM3_SSDT_TABLE_SIGNATURE: Status = PatchOem3SsdtTable (Table); //CPU TST break; case OEM4_SSDT_TABLE_SIGNATURE: Status = PatchOem4SsdtTable (Table); //CPU CST break; case ACPI_WSMT_SIGNATURE: (((ACPI_WINDOWS_SMM_SECURITY_MITIGATIONS_TABLE *)Table)->ProtectionFlags.Flags) = (UINT32 ) (WSMT_PROTECTION_FLAG & PcdGet32(PcdWsmtProtectionFlags)); DEBUG ((DEBUG_INFO, "[WSMT] ProtectionFlags = 0x%x\n", (((ACPI_WINDOWS_SMM_SECURITY_MITIGATIONS_TABLE *)Table)->ProtectionFlags.Flags))); break; default: // // Hooks for Platform only table. If the ACPI Table is Platform only, add this table in below hook. then continue to update other Table. // Status = PatchPlatformSpecificAcpiTableHooks (Table); break; } // // // Update the hardware signature in the FACS structure // // // return Status; } /** Give the platform a chance to build tables. Some tables can be built from scratch more efficiently than being prebuilt and updated. This function builds any such tables for the platform. @retval EFI_SUCCESS Any platform tables were successfully built. **/ EFI_STATUS PlatformBuildTables ( VOID ) { EFI_STATUS ReturnStatus = EFI_SUCCESS; EFI_STATUS Status; Status = InstallMadtFromScratch (); if (EFI_ERROR (Status)) { ReturnStatus = Status; } if (mSocketCommonRcConfiguration.NumaEn) { Status = InstallSlitTable (); if (EFI_ERROR (Status)) { ReturnStatus = Status; } Status = InstallSratTable (); if (EFI_ERROR (Status)) { ReturnStatus = Status; } } // // Return the first error code that occured, or success. // return ReturnStatus; }