mirror of https://github.com/acidanthera/audk.git
UefiCpuPkg/MpInitLib: Consume MicrocodeLib to remove duplicated code
Signed-off-by: Ray Ni <ray.ni@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com> Acked-by: Laszlo Ersek <lersek@redhat.com> Cc: Rahul Kumar <rahul1.kumar@intel.com>
This commit is contained in:
parent
83c7f8178b
commit
bce0328431
|
@ -52,6 +52,7 @@
|
||||||
SynchronizationLib
|
SynchronizationLib
|
||||||
PcdLib
|
PcdLib
|
||||||
VmgExitLib
|
VmgExitLib
|
||||||
|
MicrocodeLib
|
||||||
|
|
||||||
[Protocols]
|
[Protocols]
|
||||||
gEfiTimerArchProtocolGuid ## SOMETIMES_CONSUMES
|
gEfiTimerArchProtocolGuid ## SOMETIMES_CONSUMES
|
||||||
|
|
|
@ -1,70 +1,16 @@
|
||||||
/** @file
|
/** @file
|
||||||
Implementation of loading microcode on processors.
|
Implementation of loading microcode on processors.
|
||||||
|
|
||||||
Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
|
||||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#include "MpLib.h"
|
#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.
|
Detect whether specified processor can find matching microcode patch and load it.
|
||||||
|
|
||||||
Microcode Payload as the following format:
|
|
||||||
+----------------------------------------+------------------+
|
|
||||||
| CPU_MICROCODE_HEADER | |
|
|
||||||
+----------------------------------------+ CheckSum Part1 |
|
|
||||||
| Microcode Binary | |
|
|
||||||
+----------------------------------------+------------------+
|
|
||||||
| CPU_MICROCODE_EXTENDED_TABLE_HEADER | |
|
|
||||||
+----------------------------------------+ CheckSum Part2 |
|
|
||||||
| CPU_MICROCODE_EXTENDED_TABLE | |
|
|
||||||
| ... | |
|
|
||||||
+----------------------------------------+------------------+
|
|
||||||
|
|
||||||
There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.
|
|
||||||
The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount
|
|
||||||
of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.
|
|
||||||
|
|
||||||
When we are trying to verify the CheckSum32 with extended table.
|
|
||||||
We should use the fields of exnteded table to replace the corresponding
|
|
||||||
fields in CPU_MICROCODE_HEADER structure, and recalculate the
|
|
||||||
CheckSum32 with CPU_MICROCODE_HEADER + Microcode Binary. We named
|
|
||||||
it as CheckSum Part3.
|
|
||||||
|
|
||||||
The CheckSum Part2 is used to verify the CPU_MICROCODE_EXTENDED_TABLE_HEADER
|
|
||||||
and CPU_MICROCODE_EXTENDED_TABLE parts. We should make sure CheckSum Part2
|
|
||||||
is correct before we are going to verify each CPU_MICROCODE_EXTENDED_TABLE.
|
|
||||||
|
|
||||||
Only ProcessorSignature, ProcessorFlag and CheckSum are different between
|
|
||||||
CheckSum Part1 and CheckSum Part3. To avoid multiple computing CheckSum Part3.
|
|
||||||
Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
|
|
||||||
When we are going to calculate CheckSum32, just should use the corresponding part
|
|
||||||
of the ProcessorSignature, ProcessorFlag and CheckSum with in-complete CheckSum32.
|
|
||||||
|
|
||||||
Notes: CheckSum32 is not a strong verification.
|
|
||||||
It does not guarantee that the data has not been modified.
|
|
||||||
CPU has its own mechanism to verify Microcode Binary part.
|
|
||||||
|
|
||||||
@param[in] CpuMpData The pointer to CPU MP Data structure.
|
@param[in] CpuMpData The pointer to CPU MP Data structure.
|
||||||
@param[in] ProcessorNumber The handle number of the processor. The range is
|
@param[in] ProcessorNumber The handle number of the processor. The range is
|
||||||
from 0 to the total number of logical processors
|
from 0 to the total number of logical processors
|
||||||
|
@ -76,26 +22,13 @@ MicrocodeDetect (
|
||||||
IN UINTN ProcessorNumber
|
IN UINTN ProcessorNumber
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UINT32 ExtendedTableLength;
|
CPU_MICROCODE_HEADER *Microcode;
|
||||||
UINT32 ExtendedTableCount;
|
|
||||||
CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
|
|
||||||
CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
|
|
||||||
CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
|
|
||||||
UINTN MicrocodeEnd;
|
UINTN MicrocodeEnd;
|
||||||
UINTN Index;
|
CPU_AP_DATA *BspData;
|
||||||
UINT8 PlatformId;
|
|
||||||
CPUID_VERSION_INFO_EAX Eax;
|
|
||||||
CPU_AP_DATA *CpuData;
|
|
||||||
UINT32 CurrentRevision;
|
|
||||||
UINT32 LatestRevision;
|
UINT32 LatestRevision;
|
||||||
UINTN TotalSize;
|
CPU_MICROCODE_HEADER *LatestMicrocode;
|
||||||
UINT32 CheckSum32;
|
|
||||||
UINT32 InCompleteCheckSum32;
|
|
||||||
BOOLEAN CorrectMicrocode;
|
|
||||||
VOID *MicrocodeData;
|
|
||||||
MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
|
|
||||||
UINT32 ThreadId;
|
UINT32 ThreadId;
|
||||||
BOOLEAN IsBspCallIn;
|
EDKII_PEI_MICROCODE_CPU_ID MicrocodeCpuId;
|
||||||
|
|
||||||
if (CpuMpData->MicrocodePatchRegionSize == 0) {
|
if (CpuMpData->MicrocodePatchRegionSize == 0) {
|
||||||
//
|
//
|
||||||
|
@ -104,9 +37,6 @@ MicrocodeDetect (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentRevision = GetCurrentMicrocodeSignature ();
|
|
||||||
IsBspCallIn = (ProcessorNumber == (UINTN)CpuMpData->BspNumber) ? TRUE : FALSE;
|
|
||||||
|
|
||||||
GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
|
GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
|
||||||
if (ThreadId != 0) {
|
if (ThreadId != 0) {
|
||||||
//
|
//
|
||||||
|
@ -115,156 +45,35 @@ MicrocodeDetect (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtendedTableLength = 0;
|
GetProcessorMicrocodeCpuId (&MicrocodeCpuId);
|
||||||
//
|
|
||||||
// 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, &Eax.Uint32, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
//
|
if (ProcessorNumber != (UINTN) CpuMpData->BspNumber) {
|
||||||
// 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;
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Check whether AP has same processor with BSP.
|
|
||||||
// If yes, direct use microcode info saved by BSP.
|
|
||||||
//
|
|
||||||
if (!IsBspCallIn) {
|
|
||||||
//
|
//
|
||||||
// Get the CPU data for BSP
|
// Direct use microcode of BSP if AP is the same as BSP.
|
||||||
|
// Assume BSP calls this routine() before AP.
|
||||||
//
|
//
|
||||||
CpuData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);
|
BspData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);
|
||||||
if ((CpuData->ProcessorSignature == Eax.Uint32) &&
|
if ((BspData->ProcessorSignature == MicrocodeCpuId.ProcessorSignature) &&
|
||||||
(CpuData->PlatformId == PlatformId) &&
|
(BspData->PlatformId == MicrocodeCpuId.PlatformId) &&
|
||||||
(CpuData->MicrocodeEntryAddr != 0)) {
|
(BspData->MicrocodeEntryAddr != 0)) {
|
||||||
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN) CpuData->MicrocodeEntryAddr;
|
LatestMicrocode = (CPU_MICROCODE_HEADER *)(UINTN) BspData->MicrocodeEntryAddr;
|
||||||
MicrocodeData = (VOID *) (MicrocodeEntryPoint + 1);
|
LatestRevision = LatestMicrocode->UpdateRevision;
|
||||||
LatestRevision = MicrocodeEntryPoint->UpdateRevision;
|
goto LoadMicrocode;
|
||||||
goto Done;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LatestRevision = 0;
|
//
|
||||||
MicrocodeData = NULL;
|
// BSP or AP which is different from BSP runs here
|
||||||
MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);
|
// Use 0 as the starting revision to search for microcode because MicrocodePatchInfo HOB needs
|
||||||
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
|
// the latest microcode location even it's loaded to the processor.
|
||||||
|
//
|
||||||
|
LatestRevision = 0;
|
||||||
|
LatestMicrocode = NULL;
|
||||||
|
Microcode = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
|
||||||
|
MicrocodeEnd = (UINTN) Microcode + (UINTN) CpuMpData->MicrocodePatchRegionSize;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
//
|
if (!IsValidMicrocode (Microcode, MicrocodeEnd - (UINTN) Microcode, LatestRevision, &MicrocodeCpuId, 1, TRUE)) {
|
||||||
// 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->DataSize == 0) {
|
|
||||||
TotalSize = sizeof (CPU_MICROCODE_HEADER) + 2000;
|
|
||||||
} else {
|
|
||||||
TotalSize = sizeof (CPU_MICROCODE_HEADER) + MicrocodeEntryPoint->DataSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// 0x0 MicrocodeBegin MicrocodeEntry MicrocodeEnd 0xffffffff
|
|
||||||
/// |--------------|---------------|---------------|---------------|
|
|
||||||
/// valid TotalSize
|
|
||||||
/// TotalSize is only valid between 0 and (MicrocodeEnd - MicrocodeEntry).
|
|
||||||
/// And it should be aligned with 4 bytes.
|
|
||||||
/// If the TotalSize is invalid, skip 1KB to check next entry.
|
|
||||||
///
|
|
||||||
if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||
|
|
||||||
((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
|
|
||||||
(TotalSize & 0x3) != 0
|
|
||||||
) {
|
|
||||||
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
|
|
||||||
//
|
|
||||||
InCompleteCheckSum32 = CalculateSum32 (
|
|
||||||
(UINT32 *) MicrocodeEntryPoint,
|
|
||||||
TotalSize
|
|
||||||
);
|
|
||||||
InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;
|
|
||||||
InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;
|
|
||||||
InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;
|
|
||||||
|
|
||||||
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))
|
|
||||||
) {
|
|
||||||
//
|
|
||||||
// Calculate CheckSum Part1.
|
|
||||||
//
|
|
||||||
CheckSum32 = InCompleteCheckSum32;
|
|
||||||
CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;
|
|
||||||
CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;
|
|
||||||
CheckSum32 += MicrocodeEntryPoint->Checksum;
|
|
||||||
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) {
|
|
||||||
//
|
|
||||||
// Calculate CheckSum Part2.
|
|
||||||
//
|
|
||||||
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 ++) {
|
|
||||||
//
|
|
||||||
// Calculate CheckSum Part3.
|
|
||||||
//
|
|
||||||
CheckSum32 = InCompleteCheckSum32;
|
|
||||||
CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;
|
|
||||||
CheckSum32 += ExtendedTable->ProcessorFlag;
|
|
||||||
CheckSum32 += ExtendedTable->Checksum;
|
|
||||||
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.
|
// 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
|
// Because the microcode patch is the multiple of 1-KByte, the padding data should not
|
||||||
|
@ -272,156 +81,40 @@ MicrocodeDetect (
|
||||||
// alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
|
// alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
|
||||||
// find the next possible microcode patch header.
|
// find the next possible microcode patch header.
|
||||||
//
|
//
|
||||||
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
|
Microcode = (CPU_MICROCODE_HEADER *) ((UINTN) Microcode + SIZE_1KB);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//
|
LatestMicrocode = Microcode;
|
||||||
// Get the next patch.
|
LatestRevision = LatestMicrocode->UpdateRevision;
|
||||||
//
|
|
||||||
if (MicrocodeEntryPoint->DataSize == 0) {
|
|
||||||
TotalSize = 2048;
|
|
||||||
} else {
|
|
||||||
TotalSize = MicrocodeEntryPoint->TotalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CorrectMicrocode) {
|
Microcode = (CPU_MICROCODE_HEADER *) (((UINTN) Microcode) + GetMicrocodeLength (Microcode));
|
||||||
LatestRevision = MicrocodeEntryPoint->UpdateRevision;
|
} while ((UINTN) Microcode < MicrocodeEnd);
|
||||||
MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));
|
|
||||||
}
|
|
||||||
|
|
||||||
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
|
LoadMicrocode:
|
||||||
} while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
|
|
||||||
|
|
||||||
Done:
|
|
||||||
if (LatestRevision != 0) {
|
if (LatestRevision != 0) {
|
||||||
//
|
//
|
||||||
// Save the detected microcode patch entry address (including the
|
// Save the detected microcode patch entry address (including the microcode
|
||||||
// microcode patch header) for each processor.
|
// patch header) for each processor even it's the same as the loaded one.
|
||||||
// It will be used when building the microcode patch cache HOB.
|
// It will be used when building the microcode patch cache HOB.
|
||||||
//
|
//
|
||||||
CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr =
|
CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr = (UINTN) LatestMicrocode;
|
||||||
(UINTN) MicrocodeData - sizeof (CPU_MICROCODE_HEADER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LatestRevision > CurrentRevision) {
|
if (LatestRevision > GetProcessorMicrocodeSignature ()) {
|
||||||
//
|
//
|
||||||
// BIOS only authenticate updates that contain a numerically larger revision
|
// BIOS only authenticate updates that contain a numerically larger revision
|
||||||
// than the currently loaded revision, where Current Signature < New Update
|
// than the currently loaded revision, where Current Signature < New Update
|
||||||
// Revision. A processor with no loaded update is considered to have a
|
// Revision. A processor with no loaded update is considered to have a
|
||||||
// revision equal to zero.
|
// revision equal to zero.
|
||||||
//
|
//
|
||||||
ASSERT (MicrocodeData != NULL);
|
LoadMicrocode (LatestMicrocode);
|
||||||
AsmWriteMsr64 (
|
|
||||||
MSR_IA32_BIOS_UPDT_TRIG,
|
|
||||||
(UINT64) (UINTN) MicrocodeData
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
CpuMpData->CpuData[ProcessorNumber].MicrocodeRevision = GetCurrentMicrocodeSignature ();
|
//
|
||||||
|
// It's possible that the microcode fails to load. Just capture the CPU microcode revision after loading.
|
||||||
|
//
|
||||||
|
CpuMpData->CpuData[ProcessorNumber].MicrocodeRevision = GetProcessorMicrocodeSignature ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Determine if a microcode patch matchs the specific processor signature and flag.
|
|
||||||
|
|
||||||
@param[in] CpuMpData The pointer to CPU MP Data structure.
|
|
||||||
@param[in] ProcessorSignature The processor signature field value
|
|
||||||
supported by a microcode patch.
|
|
||||||
@param[in] ProcessorFlags The prcessor flags field value supported by
|
|
||||||
a microcode patch.
|
|
||||||
|
|
||||||
@retval TRUE The specified microcode patch will be loaded.
|
|
||||||
@retval FALSE The specified microcode patch will not be loaded.
|
|
||||||
**/
|
|
||||||
BOOLEAN
|
|
||||||
IsProcessorMatchedMicrocodePatch (
|
|
||||||
IN CPU_MP_DATA *CpuMpData,
|
|
||||||
IN UINT32 ProcessorSignature,
|
|
||||||
IN UINT32 ProcessorFlags
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINTN Index;
|
|
||||||
CPU_AP_DATA *CpuData;
|
|
||||||
|
|
||||||
for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
|
|
||||||
CpuData = &CpuMpData->CpuData[Index];
|
|
||||||
if ((ProcessorSignature == CpuData->ProcessorSignature) &&
|
|
||||||
(ProcessorFlags & (1 << CpuData->PlatformId)) != 0) {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check the 'ProcessorSignature' and 'ProcessorFlags' of the microcode
|
|
||||||
patch header with the CPUID and PlatformID of the processors within
|
|
||||||
system to decide if it will be copied into memory.
|
|
||||||
|
|
||||||
@param[in] CpuMpData The pointer to CPU MP Data structure.
|
|
||||||
@param[in] MicrocodeEntryPoint The pointer to the microcode patch header.
|
|
||||||
|
|
||||||
@retval TRUE The specified microcode patch need to be loaded.
|
|
||||||
@retval FALSE The specified microcode patch dosen't need to be loaded.
|
|
||||||
**/
|
|
||||||
BOOLEAN
|
|
||||||
IsMicrocodePatchNeedLoad (
|
|
||||||
IN CPU_MP_DATA *CpuMpData,
|
|
||||||
CPU_MICROCODE_HEADER *MicrocodeEntryPoint
|
|
||||||
)
|
|
||||||
{
|
|
||||||
BOOLEAN NeedLoad;
|
|
||||||
UINTN DataSize;
|
|
||||||
UINTN TotalSize;
|
|
||||||
CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
|
|
||||||
UINT32 ExtendedTableCount;
|
|
||||||
CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
|
|
||||||
UINTN Index;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Check the 'ProcessorSignature' and 'ProcessorFlags' in microcode patch header.
|
|
||||||
//
|
|
||||||
NeedLoad = IsProcessorMatchedMicrocodePatch (
|
|
||||||
CpuMpData,
|
|
||||||
MicrocodeEntryPoint->ProcessorSignature.Uint32,
|
|
||||||
MicrocodeEntryPoint->ProcessorFlags
|
|
||||||
);
|
|
||||||
|
|
||||||
//
|
|
||||||
// If the Extended Signature Table exists, check if the processor is in the
|
|
||||||
// support list
|
|
||||||
//
|
|
||||||
DataSize = MicrocodeEntryPoint->DataSize;
|
|
||||||
TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;
|
|
||||||
if ((!NeedLoad) && (DataSize != 0) &&
|
|
||||||
(TotalSize - DataSize > sizeof (CPU_MICROCODE_HEADER) +
|
|
||||||
sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))) {
|
|
||||||
ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
|
|
||||||
+ DataSize + sizeof (CPU_MICROCODE_HEADER));
|
|
||||||
ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
|
|
||||||
ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
|
|
||||||
|
|
||||||
for (Index = 0; Index < ExtendedTableCount; Index ++) {
|
|
||||||
//
|
|
||||||
// Check the 'ProcessorSignature' and 'ProcessorFlag' of the Extended
|
|
||||||
// Signature Table entry with the CPUID and PlatformID of the processors
|
|
||||||
// within system to decide if it will be copied into memory
|
|
||||||
//
|
|
||||||
NeedLoad = IsProcessorMatchedMicrocodePatch (
|
|
||||||
CpuMpData,
|
|
||||||
ExtendedTable->ProcessorSignature.Uint32,
|
|
||||||
ExtendedTable->ProcessorFlag
|
|
||||||
);
|
|
||||||
if (NeedLoad) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ExtendedTable ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NeedLoad;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Actual worker function that shadows the required microcode patches into memory.
|
Actual worker function that shadows the required microcode patches into memory.
|
||||||
|
|
||||||
|
@ -491,14 +184,16 @@ ShadowMicrocodePatchByPcd (
|
||||||
IN OUT CPU_MP_DATA *CpuMpData
|
IN OUT CPU_MP_DATA *CpuMpData
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
UINTN Index;
|
||||||
CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
|
CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
|
||||||
UINTN MicrocodeEnd;
|
UINTN MicrocodeEnd;
|
||||||
UINTN DataSize;
|
|
||||||
UINTN TotalSize;
|
UINTN TotalSize;
|
||||||
MICROCODE_PATCH_INFO *PatchInfoBuffer;
|
MICROCODE_PATCH_INFO *PatchInfoBuffer;
|
||||||
UINTN MaxPatchNumber;
|
UINTN MaxPatchNumber;
|
||||||
UINTN PatchCount;
|
UINTN PatchCount;
|
||||||
UINTN TotalLoadSize;
|
UINTN TotalLoadSize;
|
||||||
|
EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds;
|
||||||
|
BOOLEAN Valid;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Initialize the microcode patch related fields in CpuMpData as the values
|
// Initialize the microcode patch related fields in CpuMpData as the values
|
||||||
|
@ -526,12 +221,34 @@ ShadowMicrocodePatchByPcd (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MicrocodeCpuIds = AllocatePages (
|
||||||
|
EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID))
|
||||||
|
);
|
||||||
|
if (MicrocodeCpuIds == NULL) {
|
||||||
|
FreePool (PatchInfoBuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
|
||||||
|
MicrocodeCpuIds[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;
|
||||||
|
MicrocodeCpuIds[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Process the header of each microcode patch within the region.
|
// Process the header of each microcode patch within the region.
|
||||||
// The purpose is to decide which microcode patch(es) will be loaded into memory.
|
// The purpose is to decide which microcode patch(es) will be loaded into memory.
|
||||||
|
// Microcode checksum is not verified because it's slow when performing on flash.
|
||||||
//
|
//
|
||||||
do {
|
do {
|
||||||
if (MicrocodeEntryPoint->HeaderVersion != 0x1) {
|
Valid = IsValidMicrocode (
|
||||||
|
MicrocodeEntryPoint,
|
||||||
|
MicrocodeEnd - (UINTN) MicrocodeEntryPoint,
|
||||||
|
0,
|
||||||
|
MicrocodeCpuIds,
|
||||||
|
CpuMpData->CpuCount,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
if (!Valid) {
|
||||||
//
|
//
|
||||||
// Padding data between the microcode patches, skip 1KB to check next entry.
|
// Padding data between the microcode patches, skip 1KB to check next entry.
|
||||||
//
|
//
|
||||||
|
@ -539,59 +256,44 @@ ShadowMicrocodePatchByPcd (
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataSize = MicrocodeEntryPoint->DataSize;
|
PatchCount++;
|
||||||
TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;
|
if (PatchCount > MaxPatchNumber) {
|
||||||
if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||
|
|
||||||
((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
|
|
||||||
(DataSize & 0x3) != 0 ||
|
|
||||||
(TotalSize & (SIZE_1KB - 1)) != 0 ||
|
|
||||||
TotalSize < DataSize
|
|
||||||
) {
|
|
||||||
//
|
//
|
||||||
// Not a valid microcode header, skip 1KB to check next entry.
|
// Current 'PatchInfoBuffer' cannot hold the information, double the size
|
||||||
|
// and allocate a new buffer.
|
||||||
//
|
//
|
||||||
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
|
if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsMicrocodePatchNeedLoad (CpuMpData, MicrocodeEntryPoint)) {
|
|
||||||
PatchCount++;
|
|
||||||
if (PatchCount > MaxPatchNumber) {
|
|
||||||
//
|
//
|
||||||
// Current 'PatchInfoBuffer' cannot hold the information, double the size
|
// Overflow check for MaxPatchNumber
|
||||||
// and allocate a new buffer.
|
|
||||||
//
|
//
|
||||||
if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {
|
goto OnExit;
|
||||||
//
|
|
||||||
// Overflow check for MaxPatchNumber
|
|
||||||
//
|
|
||||||
goto OnExit;
|
|
||||||
}
|
|
||||||
|
|
||||||
PatchInfoBuffer = ReallocatePool (
|
|
||||||
MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
|
|
||||||
2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
|
|
||||||
PatchInfoBuffer
|
|
||||||
);
|
|
||||||
if (PatchInfoBuffer == NULL) {
|
|
||||||
goto OnExit;
|
|
||||||
}
|
|
||||||
MaxPatchNumber = MaxPatchNumber * 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
PatchInfoBuffer = ReallocatePool (
|
||||||
// Store the information of this microcode patch
|
MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
|
||||||
//
|
2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
|
||||||
PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;
|
PatchInfoBuffer
|
||||||
PatchInfoBuffer[PatchCount - 1].Size = TotalSize;
|
);
|
||||||
TotalLoadSize += TotalSize;
|
if (PatchInfoBuffer == NULL) {
|
||||||
|
goto OnExit;
|
||||||
|
}
|
||||||
|
MaxPatchNumber = MaxPatchNumber * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TotalSize = GetMicrocodeLength (MicrocodeEntryPoint);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Store the information of this microcode patch
|
||||||
|
//
|
||||||
|
PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;
|
||||||
|
PatchInfoBuffer[PatchCount - 1].Size = TotalSize;
|
||||||
|
TotalLoadSize += TotalSize;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Process the next microcode patch
|
// Process the next microcode patch
|
||||||
//
|
//
|
||||||
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
|
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) ((UINTN) MicrocodeEntryPoint + TotalSize);
|
||||||
} while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
|
} while ((UINTN) MicrocodeEntryPoint < MicrocodeEnd);
|
||||||
|
|
||||||
if (PatchCount != 0) {
|
if (PatchCount != 0) {
|
||||||
DEBUG ((
|
DEBUG ((
|
||||||
|
@ -607,7 +309,7 @@ OnExit:
|
||||||
if (PatchInfoBuffer != NULL) {
|
if (PatchInfoBuffer != NULL) {
|
||||||
FreePool (PatchInfoBuffer);
|
FreePool (PatchInfoBuffer);
|
||||||
}
|
}
|
||||||
return;
|
FreePages (MicrocodeCpuIds, EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <Library/MtrrLib.h>
|
#include <Library/MtrrLib.h>
|
||||||
#include <Library/HobLib.h>
|
#include <Library/HobLib.h>
|
||||||
#include <Library/PcdLib.h>
|
#include <Library/PcdLib.h>
|
||||||
|
#include <Library/MicrocodeLib.h>
|
||||||
|
|
||||||
#include <Guid/MicrocodePatchHob.h>
|
#include <Guid/MicrocodePatchHob.h>
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
PeiServicesLib
|
PeiServicesLib
|
||||||
PcdLib
|
PcdLib
|
||||||
VmgExitLib
|
VmgExitLib
|
||||||
|
MicrocodeLib
|
||||||
|
|
||||||
[Pcd]
|
[Pcd]
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES
|
||||||
|
|
Loading…
Reference in New Issue