From d1cf93333f3a9394c2f746db4deb374b6ba374fd Mon Sep 17 00:00:00 2001 From: Jeff Fan Date: Wed, 15 Jul 2015 03:40:41 +0000 Subject: [PATCH] UefiCpuPkg/CpuMpPei: Load microcode on BSP and APs Add DetectMicrocode() to load microcode on BSP and APs. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Feng Tian Reviewed-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18002 6f19259b-4bc3-4df7-8a09-765794883524 --- UefiCpuPkg/CpuMpPei/CpuMpPei.c | 8 +- UefiCpuPkg/CpuMpPei/CpuMpPei.h | 5 + UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 4 + UefiCpuPkg/CpuMpPei/Microcode.c | 200 +++++++++++++++++++++++++++++++ UefiCpuPkg/CpuMpPei/Microcode.h | 68 +++++++++++ 5 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 UefiCpuPkg/CpuMpPei/Microcode.c create mode 100644 UefiCpuPkg/CpuMpPei/Microcode.h diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index e39a813cdd..d63b1ff231 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -119,9 +119,10 @@ ApCFunction ( PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId (); PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData; // - // Sync BSP's Mtrr table to all wakeup APs + // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs. // MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable); + MicrocodeDetect (); } // @@ -288,7 +289,10 @@ CountProcessorNumber ( IN PEI_CPU_MP_DATA *PeiCpuMpData ) { - + // + // Load Microcode on BSP + // + MicrocodeDetect (); // // Store BSP's MTRR setting // diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index 466ddc0558..7a34a98242 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -19,6 +19,8 @@ #include +#include + #include #include #include @@ -31,6 +33,9 @@ #include #include #include + +#include "Microcode.h" + // // AP state // diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf index e195f8c3d8..1bb4daef2b 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf @@ -30,6 +30,8 @@ [Sources] CpuMpPei.h CpuMpPei.c + Microcode.h + Microcode.c [Sources.IA32] Ia32/MpEqu.inc @@ -66,6 +68,8 @@ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize + gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress + gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize [Depex] gEfiPeiMemoryDiscoveredPpiGuid diff --git a/UefiCpuPkg/CpuMpPei/Microcode.c b/UefiCpuPkg/CpuMpPei/Microcode.c new file mode 100644 index 0000000000..eb2e76b6a7 --- /dev/null +++ b/UefiCpuPkg/CpuMpPei/Microcode.c @@ -0,0 +1,200 @@ +/** @file + Implementation of loading microcode on processors. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuMpPei.h" + +/** + Get microcode update signature of currently loaded microcode update. + + @return Microcode signature. + +**/ +UINT32 +GetCurrentMicrocodeSignature ( + VOID + ) +{ + UINT64 Signature; + + AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0); + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL); + Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID); + return (UINT32) RShiftU64 (Signature, 32); +} + +/** + Detect whether specified processor can find matching microcode patch and load it. + +**/ +VOID +MicrocodeDetect ( + VOID + ) +{ + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + UINT32 ExtendedTableLength; + UINT32 ExtendedTableCount; + EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable; + EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader; + EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN Index; + UINT8 PlatformId; + UINT32 RegEax; + UINT32 LatestRevision; + UINTN TotalSize; + UINT32 CheckSum32; + BOOLEAN CorrectMicrocode; + INT32 CurrentSignature; + MICROCODE_INFO MicrocodeInfo; + + ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO)); + MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress); + MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize); + if (MicrocodePatchRegionSize == 0) { + // + // There is no microcode patches + // + return; + } + + ExtendedTableLength = 0; + // + // Here data of CPUID leafs have not been collected into context buffer, so + // GetProcessorCpuid() cannot be used here to retrieve CPUID data. + // + AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL); + + // + // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID + // + PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52); + + LatestRevision = 0; + MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize); + MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress; + do { + // + // Check if the microcode is for the Cpu and the version is newer + // and the update can be processed on the platform + // + CorrectMicrocode = FALSE; + if (MicrocodeEntryPoint->HeaderVersion == 0x1) { + // + // It is the microcode header. It is not the padding data between microcode patches + // becasue the padding data should not include 0x00000001 and it should be the repeated + // byte format (like 0xXYXYXYXY....). + // + if (MicrocodeEntryPoint->ProcessorId == RegEax && + MicrocodeEntryPoint->UpdateRevision > LatestRevision && + (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId)) + ) { + if (MicrocodeEntryPoint->DataSize == 0) { + CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048); + } else { + CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER)); + } + if (CheckSum32 == 0) { + CorrectMicrocode = TRUE; + } + } else if ((MicrocodeEntryPoint->DataSize != 0) && + (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) { + 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 + sizeof (EFI_CPU_MICROCODE_HEADER)); + // + // Calculate Extended Checksum + // + if ((ExtendedTableLength % 4) == 0) { + CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength); + if (CheckSum32 == 0) { + // + // Checksum correct + // + ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount; + ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1); + for (Index = 0; Index < ExtendedTableCount; Index ++) { + CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE)); + if (CheckSum32 == 0) { + // + // Verify Header + // + if ((ExtendedTable->ProcessorSignature == RegEax) && + (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) { + // + // Find one + // + CorrectMicrocode = TRUE; + break; + } + } + ExtendedTable ++; + } + } + } + } + } + } else { + // + // It is the padding data between the microcode patches for microcode patches alignment. + // Because the microcode patch is the multiple of 1-KByte, the padding data should not + // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode + // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to + // find the next possible microcode patch header. + // + MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB); + continue; + } + // + // Get the next patch. + // + if (MicrocodeEntryPoint->DataSize == 0) { + TotalSize = 2048; + } else { + TotalSize = MicrocodeEntryPoint->TotalSize; + } + + if (CorrectMicrocode) { + LatestRevision = MicrocodeEntryPoint->UpdateRevision; + MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER)); + MicrocodeInfo.MicrocodeSize = TotalSize; + MicrocodeInfo.ProcessorId = RegEax; + } + + MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize); + } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd)); + + if (LatestRevision > 0) { + // + // Get microcode update signature of currently loaded microcode update + // + CurrentSignature = GetCurrentMicrocodeSignature (); + // + // If no microcode update has been loaded, then trigger microcode load. + // + if (CurrentSignature == 0) { + AsmWriteMsr64 ( + EFI_MSR_IA32_BIOS_UPDT_TRIG, + (UINT64) (UINTN) MicrocodeInfo.MicrocodeData + ); + MicrocodeInfo.Load = TRUE; + } else { + MicrocodeInfo.Load = FALSE; + } + } +} diff --git a/UefiCpuPkg/CpuMpPei/Microcode.h b/UefiCpuPkg/CpuMpPei/Microcode.h new file mode 100644 index 0000000000..6f93e2f044 --- /dev/null +++ b/UefiCpuPkg/CpuMpPei/Microcode.h @@ -0,0 +1,68 @@ +/** @file + Definitions for loading microcode on processors. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _CPU_MICROCODE_H_ +#define _CPU_MICROCODE_H_ + +#define EFI_MSR_IA32_PLATFORM_ID 0x17 +#define EFI_MSR_IA32_BIOS_UPDT_TRIG 0x79 +#define EFI_MSR_IA32_BIOS_SIGN_ID 0x8b + +#define MAX_MICROCODE_DESCRIPTOR_LENGTH 100 + +typedef struct { + VOID *MicrocodeData; + UINTN MicrocodeSize; + UINT32 ProcessorId; + BOOLEAN Load; +} MICROCODE_INFO; + +// +// Definition for IA32 microcode format +// +typedef struct { + UINT32 HeaderVersion; + UINT32 UpdateRevision; + UINT32 Date; + UINT32 ProcessorId; + UINT32 Checksum; + UINT32 LoaderRevision; + UINT32 ProcessorFlags; + UINT32 DataSize; + UINT32 TotalSize; + UINT8 Reserved[12]; +} EFI_CPU_MICROCODE_HEADER; + +typedef struct { + UINT32 ExtendedSignatureCount; + UINT32 ExtendedTableChecksum; + UINT8 Reserved[12]; +} EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER; + +typedef struct { + UINT32 ProcessorSignature; + UINT32 ProcessorFlag; + UINT32 ProcessorChecksum; +} EFI_CPU_MICROCODE_EXTENDED_TABLE; + +/** + Detect whether specified processor can find matching microcode patch and load it. + +**/ +VOID +MicrocodeDetect ( + VOID + ); + +#endif -- 2.39.2