mirror of https://github.com/acidanthera/audk.git
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 <michael.d.kinney@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan <jeff.fan@intel.com> Reviewed-by: Michael Kinney <michael.d.kinney@intel.com> Tested-by: Laszlo Ersek <lersek@redhat.com> Tested-by: Michael Kinney <michael.d.kinney@intel.com>
This commit is contained in:
parent
68cb933071
commit
94f63c765f
|
@ -39,6 +39,7 @@
|
||||||
DxeMpLib.c
|
DxeMpLib.c
|
||||||
MpLib.c
|
MpLib.c
|
||||||
MpLib.h
|
MpLib.h
|
||||||
|
Microcode.c
|
||||||
|
|
||||||
[Packages]
|
[Packages]
|
||||||
MdePkg/MdePkg.dec
|
MdePkg/MdePkg.dec
|
||||||
|
|
|
@ -0,0 +1,216 @@
|
||||||
|
/** @file
|
||||||
|
Implementation of loading microcode on processors.
|
||||||
|
|
||||||
|
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -294,6 +294,11 @@ MpInitLibInitialize (
|
||||||
CpuMpData->CpuData[Index].StartupApSignal =
|
CpuMpData->CpuData[Index].StartupApSignal =
|
||||||
(UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
|
(UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// Load Microcode on BSP
|
||||||
|
//
|
||||||
|
MicrocodeDetect (CpuMpData);
|
||||||
|
//
|
||||||
// Store BSP's MTRR setting
|
// Store BSP's MTRR setting
|
||||||
//
|
//
|
||||||
MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
|
MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
|
||||||
|
|
|
@ -232,5 +232,15 @@ AsmGetAddressMap (
|
||||||
OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap
|
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
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
PeiMpLib.c
|
PeiMpLib.c
|
||||||
MpLib.c
|
MpLib.c
|
||||||
MpLib.h
|
MpLib.h
|
||||||
|
Microcode.c
|
||||||
|
|
||||||
[Packages]
|
[Packages]
|
||||||
MdePkg/MdePkg.dec
|
MdePkg/MdePkg.dec
|
||||||
|
|
Loading…
Reference in New Issue