+++ /dev/null
-/** @file\r
- Implementation of loading microcode on processors.\r
-\r
- Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include "CpuMpPei.h"\r
-\r
-/**\r
- Get microcode update signature of currently loaded microcode update.\r
-\r
- @return Microcode signature.\r
-\r
-**/\r
-UINT32\r
-GetCurrentMicrocodeSignature (\r
- VOID\r
- )\r
-{\r
- UINT64 Signature;\r
-\r
- AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0);\r
- AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
- Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID);\r
- return (UINT32) RShiftU64 (Signature, 32);\r
-}\r
-\r
-/**\r
- Detect whether specified processor can find matching microcode patch and load it.\r
-\r
- @param PeiCpuMpData Pointer to PEI CPU MP Data\r
-**/\r
-VOID\r
-MicrocodeDetect (\r
- IN PEI_CPU_MP_DATA *PeiCpuMpData\r
- )\r
-{\r
- UINT64 MicrocodePatchAddress;\r
- UINT64 MicrocodePatchRegionSize;\r
- UINT32 ExtendedTableLength;\r
- UINT32 ExtendedTableCount;\r
- EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
- EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
- EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
- UINTN MicrocodeEnd;\r
- UINTN Index;\r
- UINT8 PlatformId;\r
- UINT32 RegEax;\r
- UINT32 CurrentRevision;\r
- UINT32 LatestRevision;\r
- UINTN TotalSize;\r
- UINT32 CheckSum32;\r
- BOOLEAN CorrectMicrocode;\r
- MICROCODE_INFO MicrocodeInfo;\r
-\r
- ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));\r
- MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
- MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
- if (MicrocodePatchRegionSize == 0) {\r
- //\r
- // There is no microcode patches\r
- //\r
- return;\r
- }\r
-\r
- CurrentRevision = GetCurrentMicrocodeSignature ();\r
- if (CurrentRevision != 0) {\r
- //\r
- // Skip loading microcode if it has been loaded successfully\r
- //\r
- return;\r
- }\r
-\r
- ExtendedTableLength = 0;\r
- //\r
- // Here data of CPUID leafs have not been collected into context buffer, so\r
- // GetProcessorCpuid() cannot be used here to retrieve CPUID data.\r
- //\r
- AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);\r
-\r
- //\r
- // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID\r
- //\r
- PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);\r
-\r
- LatestRevision = 0;\r
- MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);\r
- MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;\r
- do {\r
- //\r
- // Check if the microcode is for the Cpu and the version is newer\r
- // and the update can be processed on the platform\r
- //\r
- CorrectMicrocode = FALSE;\r
- if (MicrocodeEntryPoint->HeaderVersion == 0x1) {\r
- //\r
- // It is the microcode header. It is not the padding data between microcode patches\r
- // because the padding data should not include 0x00000001 and it should be the repeated\r
- // byte format (like 0xXYXYXYXY....).\r
- //\r
- if (MicrocodeEntryPoint->ProcessorId == RegEax &&\r
- MicrocodeEntryPoint->UpdateRevision > LatestRevision &&\r
- (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))\r
- ) {\r
- if (MicrocodeEntryPoint->DataSize == 0) {\r
- CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);\r
- } else {\r
- CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));\r
- }\r
- if (CheckSum32 == 0) {\r
- CorrectMicrocode = TRUE;\r
- }\r
- } else if ((MicrocodeEntryPoint->DataSize != 0) &&\r
- (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {\r
- ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));\r
- if (ExtendedTableLength != 0) {\r
- //\r
- // Extended Table exist, check if the CPU in support list\r
- //\r
- ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));\r
- //\r
- // Calculate Extended Checksum\r
- //\r
- if ((ExtendedTableLength % 4) == 0) {\r
- CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);\r
- if (CheckSum32 == 0) {\r
- //\r
- // Checksum correct\r
- //\r
- ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
- ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);\r
- for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
- CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));\r
- if (CheckSum32 == 0) {\r
- //\r
- // Verify Header\r
- //\r
- if ((ExtendedTable->ProcessorSignature == RegEax) &&\r
- (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {\r
- //\r
- // Find one\r
- //\r
- CorrectMicrocode = TRUE;\r
- break;\r
- }\r
- }\r
- ExtendedTable ++;\r
- }\r
- }\r
- }\r
- }\r
- }\r
- } else {\r
- //\r
- // It is the padding data between the microcode patches for microcode patches alignment.\r
- // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
- // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
- // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
- // find the next possible microcode patch header.\r
- //\r
- MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
- continue;\r
- }\r
- //\r
- // Get the next patch.\r
- //\r
- if (MicrocodeEntryPoint->DataSize == 0) {\r
- TotalSize = 2048;\r
- } else {\r
- TotalSize = MicrocodeEntryPoint->TotalSize;\r
- }\r
-\r
- if (CorrectMicrocode) {\r
- LatestRevision = MicrocodeEntryPoint->UpdateRevision;\r
- MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));\r
- MicrocodeInfo.MicrocodeSize = TotalSize;\r
- MicrocodeInfo.ProcessorId = RegEax;\r
- }\r
-\r
- MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
- } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
-\r
- if (LatestRevision > CurrentRevision) {\r
- //\r
- // BIOS only authenticate updates that contain a numerically larger revision\r
- // than the currently loaded revision, where Current Signature < New Update\r
- // Revision. A processor with no loaded update is considered to have a\r
- // revision equal to zero.\r
- //\r
- AsmWriteMsr64 (\r
- EFI_MSR_IA32_BIOS_UPDT_TRIG,\r
- (UINT64) (UINTN) MicrocodeInfo.MicrocodeData\r
- );\r
- //\r
- // Get and check new microcode signature\r
- //\r
- CurrentRevision = GetCurrentMicrocodeSignature ();\r
- if (CurrentRevision != LatestRevision) {\r
- AcquireSpinLock(&PeiCpuMpData->MpLock);\r
- DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \\r
- loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));\r
- ReleaseSpinLock(&PeiCpuMpData->MpLock);\r
- }\r
- }\r
-}\r