diff options
Diffstat (limited to 'ReferenceCode/Haswell/CpuS3/Pei/Microcode.c')
-rw-r--r-- | ReferenceCode/Haswell/CpuS3/Pei/Microcode.c | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/CpuS3/Pei/Microcode.c b/ReferenceCode/Haswell/CpuS3/Pei/Microcode.c new file mode 100644 index 0000000..4d596d3 --- /dev/null +++ b/ReferenceCode/Haswell/CpuS3/Pei/Microcode.c @@ -0,0 +1,472 @@ +/** @file + CPU microcode update PEIM + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement + +**/ + +/// +/// External include files do NOT need to be explicitly specified in real EDKII +/// environment +/// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGluePeim.h" +#include "MpCommon.h" +#define SKIP_MICROCODE_CHECKSUM_CHECK 1 +#endif +/// +/// Array of pointers which each points to 1 microcode update binary (in memory) +/// +EFI_CPU_MICROCODE_HEADER **mMicrocodePointerBuffer; + +/// +/// Function declarations +/// +EFI_STATUS +FindLoadMicrocode ( + IN UINT32 Cpuid, + IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer, + IN OUT UINT32 *Revision + ); + +/** + Check number of cores in the package. + + @retval Number of cores in the package. +**/ +UINT8 +GetCoreNumber ( + VOID + ) +{ + EFI_CPUID_REGISTER Cpuid; + AsmCpuidEx ( + 4, + 0, + &Cpuid.RegEax, + NULL, + NULL, + NULL + ); + return (UINT8) ((RShiftU64 (Cpuid.RegEax, 26) & 0x3f) + 1); +} + +/** + Check if this is non-core processor - HT AP thread + + @retval TRUE if this is HT AP thread + @retval FALSE if this is core thread +**/ +BOOLEAN +IsSecondaryThread ( + VOID + ) +{ + UINT32 ApicID; + EFI_CPUID_REGISTER CpuidRegisters; + UINT8 CpuCount; + UINT8 CoreCount; + UINT8 CpuPerCore; + UINT32 Mask; + + ApicID = GetApicID (); + + AsmCpuid ( + CPUID_VERSION_INFO, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + if ((CpuidRegisters.RegEdx & 0x10000000) == 0) { + return FALSE; + } + + CpuCount = (UINT8) ((CpuidRegisters.RegEbx >> 16) & 0xff); + if (CpuCount == 1) { + return FALSE; + } + + AsmCpuid ( + CPUID_SIGNATURE, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + if (CpuidRegisters.RegEax > 3) { + + CoreCount = GetCoreNumber (); + } else { + CoreCount = 1; + } + /// + /// Assumes there is symmetry across core boundary, i.e. each core within a package has the same number of logical processors + /// + if (CpuCount == CoreCount) { + return FALSE; + } + + CpuPerCore = CpuCount / CoreCount; + + /// + /// Assume 1 Core has no more than 8 threads + /// + if (CpuPerCore == 2) { + Mask = 0x1; + } else if (CpuPerCore <= 4) { + Mask = 0x3; + } else { + Mask = 0x7; + } + + if ((ApicID & Mask) == 0) { + return FALSE; + } else { + return TRUE; + } +} + +/** + Returns the processor microcode revision of the processor installed in the system. + + @retval Processor Microcode Revision +**/ +UINT32 +GetCpuUcodeRevision ( + VOID + ) +{ + AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0); + EfiCpuid (CPUID_VERSION_INFO, NULL); + return (UINT32) RShiftU64 (AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID), 32); +} + +/** + Wait till all primary threads done the microcode load + + @param[in] ExchangeInfo - Pointer to the exchange info buffer for output. +**/ +VOID +WaitForPrimaryThreadMcuUpdate ( + IN MP_CPU_EXCHANGE_INFO *ExchangeInfo + ) +{ + UINTN CoreNumber; + CoreNumber = (UINTN) ((RShiftU64 (AsmReadMsr64 (MSR_CORE_THREAD_COUNT), 16)) & 0xffff); + if (IsSecondaryThread ()) { + while (ExchangeInfo->McuLoadCount < CoreNumber) { + CpuPause (); + } + } +} + +/** + This function checks the MCU revision to decide if BIOS needs to load + microcode. + + @param[in] MicrocodePointer - Microcode in memory + @param[in] Revision - Current CPU microcode revision + + @retval EFI_SUCCESS - BIOS needs to load microcode + @retval EFI_ABORTED - Don't need to update microcode +**/ +EFI_STATUS +CheckMcuRevision ( + IN EFI_CPU_MICROCODE_HEADER *MicrocodePointer, + IN UINT32 Revision + ) +{ + EFI_STATUS Status; + Status = EFI_ABORTED; + + if (Revision == 0) { + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + This will locate a processor microcode and if it finds a newer revision, it will + load it to the processor. + + @param[in] ExchangeInfo - Pointer to the exchange info buffer for output. + @param[in] MicrocodePointerBuffer - The Array of pointers which each points to 1 microcode update binary (in memory) + @param[in] FailedRevision - The microcode revision that fails to be loaded + + @retval EFI_SUCCESS - A new microcode update is loaded + @retval Other - Due to some reason, no new microcode update is loaded +**/ +EFI_STATUS +InitializeMicrocode ( + IN MP_CPU_EXCHANGE_INFO *ExchangeInfo, + IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer, + OUT UINT32 *FailedRevision + ) +{ + EFI_STATUS Status; + EFI_CPUID_REGISTER Cpuid; + UINT32 UcodeRevision; + ACPI_CPU_DATA *mAcpiCpuData; + + mAcpiCpuData = (ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress); + + AsmCpuid ( + CPUID_VERSION_INFO, + &Cpuid.RegEax, + &Cpuid.RegEbx, + &Cpuid.RegEcx, + &Cpuid.RegEdx + ); + + WaitForPrimaryThreadMcuUpdate (ExchangeInfo); + UcodeRevision = GetCpuUcodeRevision (); + Status = FindLoadMicrocode ( + Cpuid.RegEax, + MicrocodePointerBuffer, + &UcodeRevision + ); + *FailedRevision = UcodeRevision; + + InterlockedIncrement (&(ExchangeInfo->McuLoadCount)); + return Status; +} + +/** + This will load the microcode to the processors. + + @param[in] MicrocodeEntryPoint - The microcode update pointer + @param[in] Revision - The current (before load this microcode update) microcode revision + + @retval EFI_SUCCESS - Microcode loaded + @retval EFI_LOAD_ERROR - Microcode not loaded +**/ +EFI_STATUS +LoadMicrocode ( + IN EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint, + IN UINT32 *Revision + ) +{ + /// + /// Load the Processor Microcode + /// + AsmWriteMsr64 ( + MSR_IA32_BIOS_UPDT_TRIG, + (UINT64) ((UINTN) MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER)) + ); + + /// + /// Verify that the microcode has been loaded + /// + if (GetCpuUcodeRevision () == *Revision) { + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Verify the DWORD type checksum + + @param[in] ChecksumAddr - The start address to be checkumed + @param[in] ChecksumLen - The length of data to be checksumed + + @retval EFI_SUCCESS - Checksum correct + @retval EFI_CRC_ERROR - Checksum incorrect +**/ +EFI_STATUS +Checksum32Verify ( + IN UINT32 *ChecksumAddr, + IN UINT32 ChecksumLen + ) +{ +#if SKIP_MICROCODE_CHECKSUM_CHECK + return EFI_SUCCESS; +#else + UINT32 Checksum; + UINT32 Index; + + Checksum = 0; + + for (Index = 0; Index < ChecksumLen; Index++) { + Checksum += ChecksumAddr[Index]; + } + + return (Checksum == 0) ? EFI_SUCCESS : EFI_CRC_ERROR; +#endif +} + +/** + Find microcode data + + @param[in] Cpuid - processor CPUID + @param[in] MicrocodePointerBuffer - the pointer for microcode buffer + @param[in] Revision - revision of microcode + + @retval The pointer of microcode header +**/ +EFI_CPU_MICROCODE_HEADER * +FindMicrocode ( + IN UINTN Cpuid, + IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer, + IN UINT32 *Revision + ) +{ + EFI_STATUS Status; + EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINT8 Index; + UINT8 ExtendedIndex; + UINT8 MsrPlatform; + UINT32 ExtendedTableLength; + UINT32 ExtendedTableCount; + BOOLEAN CorrectMicrocode; + EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable; + EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader; + + Status = EFI_NOT_FOUND; + ExtendedTableLength = 0; + MicrocodeEntryPoint = NULL; + CorrectMicrocode = FALSE; + + /// + /// The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID + /// + MsrPlatform = (UINT8) (RShiftU64 (AsmReadMsr64 (MSR_IA32_PLATFORM_ID), 50) & 0x07); + + Index = 0; + while (MicrocodePointerBuffer[Index] != NULL) { + MicrocodeEntryPoint = MicrocodePointerBuffer[Index]; + CorrectMicrocode = FALSE; + /// + /// Check if the microcode is for the Cpu and the version is newer + /// and the update can be processed on the platform + /// + if ((MicrocodeEntryPoint->HeaderVersion == 0x00000001) && + !EFI_ERROR (CheckMcuRevision (MicrocodeEntryPoint, *Revision)) + ) { + if ((MicrocodeEntryPoint->ProcessorId == Cpuid) && (MicrocodeEntryPoint->ProcessorFlags & (1 << MsrPlatform))) { + if (MicrocodeEntryPoint->DataSize == 0) { + Status = Checksum32Verify ((UINT32 *) MicrocodeEntryPoint, 2048 / sizeof (UINT32)); + } else { + Status = Checksum32Verify ( + (UINT32 *) MicrocodeEntryPoint, + (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER)) / sizeof (UINT32) + ); + } + + if (!EFI_ERROR (Status)) { + CorrectMicrocode = TRUE; + } + } else if ((MicrocodeEntryPoint->DataSize != 0)) { + /// + /// Check the Extended Signature if the entended signature exist + /// Only the data size != 0 the extended signature may exist + /// + ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER)); + if (ExtendedTableLength != 0) { + /// + /// Extended Table exist, check if the CPU in support list + /// + ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + 48); + /// + /// Calulate Extended Checksum + /// + if ((ExtendedTableLength % 4) == 0) { + Status = Checksum32Verify ((UINT32 *) ExtendedTableHeader, ExtendedTableLength / sizeof (UINT32)); + if (!EFI_ERROR (Status)) { + /// + /// Checksum correct + /// + ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount; + ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1); + for (ExtendedIndex = 0; ExtendedIndex < ExtendedTableCount; ExtendedIndex++) { + /// + /// Verify Header + /// + if ((ExtendedTable->ProcessorSignature == Cpuid) && (ExtendedTable->ProcessorFlag & (1 << MsrPlatform))) { + Status = Checksum32Verify ( + (UINT32 *) ExtendedTable, + sizeof (EFI_CPU_MICROCODE_EXTENDED_TABLE) / sizeof (UINT32) + ); + if (!EFI_ERROR (Status)) { + /// + /// Find one + /// + CorrectMicrocode = TRUE; + break; + } + } + + ExtendedTable++; + } + } + } + } + } + } + + if (CorrectMicrocode) { + break; + } + + Index += 2; + } + + if (!CorrectMicrocode) { + MicrocodeEntryPoint = NULL; + } + + return MicrocodeEntryPoint; +} + +/** + This will locate a processor microcode and if it finds a newer revision, it will + load it to the processor. + + @param[in] Cpuid - Data returned by cpuid instruction + @param[in] MicrocodePointerBuffer - The Array of pointers which each points to 1 microcode update binary (in memory) + @param[in] Revision - As input parameter, the current microcode revision; + as output parameter, the microcode revision after microcode update is loaded + + @retval EFI_SUCCESS - A new microcode update is loaded + @retval Other - Due to some reason, no new microcode update is loaded +**/ +EFI_STATUS +FindLoadMicrocode ( + IN UINT32 Cpuid, + IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer, + IN OUT UINT32 *Revision + ) +{ + EFI_STATUS Status; + EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + + Status = EFI_NOT_FOUND; + + MicrocodeEntryPoint = FindMicrocode ( + Cpuid, + MicrocodePointerBuffer, + Revision + ); + + if (MicrocodeEntryPoint != NULL) { + Status = LoadMicrocode (MicrocodeEntryPoint, Revision); + *Revision = MicrocodeEntryPoint->UpdateRevision; + } + + return Status; +} |