summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/CpuS3/Pei/Microcode.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Haswell/CpuS3/Pei/Microcode.c')
-rw-r--r--ReferenceCode/Haswell/CpuS3/Pei/Microcode.c472
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;
+}