From: Jeff Fan Date: Wed, 20 Jul 2016 15:49:35 +0000 (+0800) Subject: UefiCpuPkg/MpInitLib: Add MicrocodeDetect() and load microcode on BSP X-Git-Tag: edk2-stable201903~6015 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=94f63c765fb0b48b287cc1cf3bc61a46dde4f524 UefiCpuPkg/MpInitLib: Add MicrocodeDetect() and load microcode on BSP v4: 1. ProcessorSignature is updated to CPU_MICROCODE_PROCESSOR_SIGNATURE instead of UINT32. Cc: Michael Kinney Cc: Feng Tian Cc: Giri P Mudusuru Cc: Laszlo Ersek Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan Reviewed-by: Michael Kinney Tested-by: Laszlo Ersek Tested-by: Michael Kinney --- diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf index e9a27250a7..03a8994516 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf @@ -39,6 +39,7 @@ DxeMpLib.c MpLib.c MpLib.h + Microcode.c [Packages] MdePkg/MdePkg.dec diff --git a/UefiCpuPkg/Library/MpInitLib/Microcode.c b/UefiCpuPkg/Library/MpInitLib/Microcode.c new file mode 100644 index 0000000000..0fd8e8c51b --- /dev/null +++ b/UefiCpuPkg/Library/MpInitLib/Microcode.c @@ -0,0 +1,216 @@ +/** @file + Implementation of loading microcode on processors. + + Copyright (c) 2015 - 2016, 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 "MpLib.h" + +/** + Get microcode update signature of currently loaded microcode update. + + @return Microcode signature. +**/ +UINT32 +GetCurrentMicrocodeSignature ( + VOID + ) +{ + MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr; + + AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0); + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL); + BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID); + return BiosSignIdMsr.Bits.MicrocodeUpdateSignature; +} + +/** + Detect whether specified processor can find matching microcode patch and load it. + + @param[in] PeiCpuMpData Pointer to PEI CPU MP Data +**/ +VOID +MicrocodeDetect ( + IN CPU_MP_DATA *CpuMpData + ) +{ + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + UINT32 ExtendedTableLength; + UINT32 ExtendedTableCount; + CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable; + CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN Index; + UINT8 PlatformId; + CPUID_VERSION_INFO_EAX Eax; + UINT32 CurrentRevision; + UINT32 LatestRevision; + UINTN TotalSize; + UINT32 CheckSum32; + BOOLEAN CorrectMicrocode; + VOID *MicrocodeData; + MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr; + + MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress); + MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize); + if (MicrocodePatchRegionSize == 0) { + // + // There is no microcode patches + // + return; + } + + CurrentRevision = GetCurrentMicrocodeSignature (); + if (CurrentRevision != 0) { + // + // Skip loading microcode if it has been loaded successfully + // + return; + } + + ExtendedTableLength = 0; + // + // Here data of CPUID leafs have not been collected into context buffer, so + // GetProcessorCpuid() cannot be used here to retrieve sCPUID data. + // + AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL); + + // + // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID + // + PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID); + PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId; + + LatestRevision = 0; + MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize); + MicrocodeEntryPoint = (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 + // because the padding data should not include 0x00000001 and it should be the repeated + // byte format (like 0xXYXYXYXY....). + // + if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 && + MicrocodeEntryPoint->UpdateRevision > LatestRevision && + (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId)) + ) { + if (MicrocodeEntryPoint->DataSize == 0) { + CheckSum32 = CalculateSum32 ((UINT32 *) MicrocodeEntryPoint, 2048); + } else { + CheckSum32 = CalculateSum32 ( + (UINT32 *) MicrocodeEntryPoint, + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER) + ); + } + if (CheckSum32 == 0) { + CorrectMicrocode = TRUE; + } + } else if ((MicrocodeEntryPoint->DataSize != 0) && + (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) { + ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + + sizeof (CPU_MICROCODE_HEADER)); + if (ExtendedTableLength != 0) { + // + // Extended Table exist, check if the CPU in support list + // + ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint) + + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)); + // + // Calculate Extended Checksum + // + if ((ExtendedTableLength % 4) == 0) { + CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength); + if (CheckSum32 == 0) { + // + // Checksum correct + // + ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount; + ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1); + for (Index = 0; Index < ExtendedTableCount; Index ++) { + CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE)); + if (CheckSum32 == 0) { + // + // Verify Header + // + if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) && + (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 = (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; + MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER)); + } + + MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize); + } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd)); + + if (LatestRevision > CurrentRevision) { + // + // BIOS only authenticate updates that contain a numerically larger revision + // than the currently loaded revision, where Current Signature < New Update + // Revision. A processor with no loaded update is considered to have a + // revision equal to zero. + // + AsmWriteMsr64 ( + MSR_IA32_BIOS_UPDT_TRIG, + (UINT64) (UINTN) MicrocodeData + ); + // + // Get and check new microcode signature + // + CurrentRevision = GetCurrentMicrocodeSignature (); + if (CurrentRevision != LatestRevision) { + AcquireSpinLock(&CpuMpData->MpLock); + DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \ + loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision)); + ReleaseSpinLock(&CpuMpData->MpLock); + } + } +} diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index 0832228d71..7384f5d0d2 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -294,6 +294,11 @@ MpInitLibInitialize ( CpuMpData->CpuData[Index].StartupApSignal = (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index); } + // + // Load Microcode on BSP + // + MicrocodeDetect (CpuMpData); + // // Store BSP's MTRR setting // MtrrGetAllMtrrs (&CpuMpData->MtrrTable); diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h index ca8bd445ba..625d061221 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h @@ -232,5 +232,15 @@ AsmGetAddressMap ( OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap ); +/** + Detect whether specified processor can find matching microcode patch and load it. + + @param[in] PeiCpuMpData Pointer to PEI CPU MP Data +**/ +VOID +MicrocodeDetect ( + IN CPU_MP_DATA *CpuMpData + ); + #endif diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf index c195a38f59..0c6873da79 100644 --- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf @@ -39,6 +39,7 @@ PeiMpLib.c MpLib.c MpLib.h + Microcode.c [Packages] MdePkg/MdePkg.dec