2016-07-20 17:49:35 +02:00
|
|
|
/** @file
|
|
|
|
Implementation of loading microcode on processors.
|
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
|
2019-04-04 01:07:22 +02:00
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
2016-07-20 17:49:35 +02:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "MpLib.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
Detect whether specified processor can find matching microcode patch and load it.
|
|
|
|
|
2019-12-23 07:32:49 +01:00
|
|
|
@param[in] CpuMpData The pointer to CPU MP Data structure.
|
|
|
|
@param[in] ProcessorNumber The handle number of the processor. The range is
|
|
|
|
from 0 to the total number of logical processors
|
|
|
|
minus 1.
|
2016-07-20 17:49:35 +02:00
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
MicrocodeDetect (
|
2018-07-11 13:07:28 +02:00
|
|
|
IN CPU_MP_DATA *CpuMpData,
|
2019-12-23 07:32:49 +01:00
|
|
|
IN UINTN ProcessorNumber
|
2016-07-20 17:49:35 +02:00
|
|
|
)
|
|
|
|
{
|
2021-04-01 18:32:44 +02:00
|
|
|
CPU_MICROCODE_HEADER *Microcode;
|
2016-07-20 17:49:35 +02:00
|
|
|
UINTN MicrocodeEnd;
|
2021-04-01 18:32:44 +02:00
|
|
|
CPU_AP_DATA *BspData;
|
2016-07-20 17:49:35 +02:00
|
|
|
UINT32 LatestRevision;
|
2021-04-01 18:32:44 +02:00
|
|
|
CPU_MICROCODE_HEADER *LatestMicrocode;
|
2018-07-12 12:21:01 +02:00
|
|
|
UINT32 ThreadId;
|
2021-04-01 18:32:44 +02:00
|
|
|
EDKII_PEI_MICROCODE_CPU_ID MicrocodeCpuId;
|
2016-07-20 17:49:35 +02:00
|
|
|
|
2017-10-19 04:40:16 +02:00
|
|
|
if (CpuMpData->MicrocodePatchRegionSize == 0) {
|
2016-07-20 17:49:35 +02:00
|
|
|
//
|
|
|
|
// There is no microcode patches
|
|
|
|
//
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-12 12:21:01 +02:00
|
|
|
GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
|
|
|
|
if (ThreadId != 0) {
|
|
|
|
//
|
|
|
|
// Skip loading microcode if it is not the first thread in one core.
|
|
|
|
//
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
GetProcessorMicrocodeCpuId (&MicrocodeCpuId);
|
2016-07-20 17:49:35 +02:00
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
if (ProcessorNumber != (UINTN)CpuMpData->BspNumber) {
|
2019-12-24 08:02:23 +01:00
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
// Direct use microcode of BSP if AP is the same as BSP.
|
|
|
|
// Assume BSP calls this routine() before AP.
|
2019-12-24 08:02:23 +01:00
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
BspData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);
|
|
|
|
if ((BspData->ProcessorSignature == MicrocodeCpuId.ProcessorSignature) &&
|
|
|
|
(BspData->PlatformId == MicrocodeCpuId.PlatformId) &&
|
|
|
|
(BspData->MicrocodeEntryAddr != 0))
|
|
|
|
{
|
|
|
|
LatestMicrocode = (CPU_MICROCODE_HEADER *)(UINTN)BspData->MicrocodeEntryAddr;
|
|
|
|
LatestRevision = LatestMicrocode->UpdateRevision;
|
|
|
|
goto LoadMicrocode;
|
2018-07-11 13:07:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
//
|
|
|
|
// BSP or AP which is different from BSP runs here
|
|
|
|
// Use 0 as the starting revision to search for microcode because MicrocodePatchInfo HOB needs
|
|
|
|
// 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;
|
2019-02-15 07:29:41 +01:00
|
|
|
|
2016-07-20 17:49:35 +02:00
|
|
|
do {
|
2021-04-01 18:32:44 +02:00
|
|
|
if (!IsValidMicrocode (Microcode, MicrocodeEnd - (UINTN)Microcode, LatestRevision, &MicrocodeCpuId, 1, TRUE)) {
|
2016-07-20 17:49:35 +02:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
Microcode = (CPU_MICROCODE_HEADER *)((UINTN)Microcode + SIZE_1KB);
|
2016-07-20 17:49:35 +02:00
|
|
|
continue;
|
|
|
|
}
|
2021-12-05 23:54:17 +01:00
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
LatestMicrocode = Microcode;
|
|
|
|
LatestRevision = LatestMicrocode->UpdateRevision;
|
2016-07-20 17:49:35 +02:00
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
Microcode = (CPU_MICROCODE_HEADER *)(((UINTN)Microcode) + GetMicrocodeLength (Microcode));
|
|
|
|
} while ((UINTN)Microcode < MicrocodeEnd);
|
2016-07-20 17:49:35 +02:00
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
LoadMicrocode:
|
2019-12-23 07:32:49 +01:00
|
|
|
if (LatestRevision != 0) {
|
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
// Save the detected microcode patch entry address (including the microcode
|
|
|
|
// patch header) for each processor even it's the same as the loaded one.
|
2019-12-23 07:32:49 +01:00
|
|
|
// It will be used when building the microcode patch cache HOB.
|
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr = (UINTN)LatestMicrocode;
|
2019-12-23 07:32:49 +01:00
|
|
|
}
|
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
if (LatestRevision > GetProcessorMicrocodeSignature ()) {
|
2016-07-20 17:49:35 +02:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
LoadMicrocode (LatestMicrocode);
|
2019-12-19 07:33:44 +01:00
|
|
|
}
|
2021-12-05 23:54:17 +01:00
|
|
|
|
2020-01-08 04:22:30 +01:00
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
// It's possible that the microcode fails to load. Just capture the CPU microcode revision after loading.
|
2020-01-08 04:22:30 +01:00
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
CpuMpData->CpuData[ProcessorNumber].MicrocodeRevision = GetProcessorMicrocodeSignature ();
|
2020-01-08 04:22:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Actual worker function that shadows the required microcode patches into memory.
|
2019-12-19 07:33:44 +01:00
|
|
|
|
|
|
|
@param[in, out] CpuMpData The pointer to CPU MP Data structure.
|
|
|
|
@param[in] Patches The pointer to an array of information on
|
|
|
|
the microcode patches that will be loaded
|
|
|
|
into memory.
|
|
|
|
@param[in] PatchCount The number of microcode patches that will
|
|
|
|
be loaded into memory.
|
|
|
|
@param[in] TotalLoadSize The total size of all the microcode patches
|
|
|
|
to be loaded.
|
|
|
|
**/
|
|
|
|
VOID
|
2020-01-08 04:22:30 +01:00
|
|
|
ShadowMicrocodePatchWorker (
|
2019-12-19 07:33:44 +01:00
|
|
|
IN OUT CPU_MP_DATA *CpuMpData,
|
|
|
|
IN MICROCODE_PATCH_INFO *Patches,
|
|
|
|
IN UINTN PatchCount,
|
|
|
|
IN UINTN TotalLoadSize
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Index;
|
|
|
|
VOID *MicrocodePatchInRam;
|
|
|
|
UINT8 *Walker;
|
|
|
|
|
|
|
|
ASSERT ((Patches != NULL) && (PatchCount != 0));
|
|
|
|
|
|
|
|
MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));
|
|
|
|
if (MicrocodePatchInRam == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Load all the required microcode patches into memory
|
|
|
|
//
|
|
|
|
for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {
|
|
|
|
CopyMem (
|
|
|
|
Walker,
|
|
|
|
(VOID *)Patches[Index].Address,
|
|
|
|
Patches[Index].Size
|
|
|
|
);
|
2020-01-03 08:11:51 +01:00
|
|
|
Walker += Patches[Index].Size;
|
2019-12-19 07:33:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Update the microcode patch related fields in CpuMpData
|
|
|
|
//
|
|
|
|
CpuMpData->MicrocodePatchAddress = (UINTN)MicrocodePatchInRam;
|
|
|
|
CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;
|
|
|
|
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_INFO,
|
|
|
|
"%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
|
2023-04-06 21:49:10 +02:00
|
|
|
__func__,
|
2019-12-19 07:33:44 +01:00
|
|
|
CpuMpData->MicrocodePatchAddress,
|
|
|
|
CpuMpData->MicrocodePatchRegionSize
|
|
|
|
));
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-01-08 04:22:30 +01:00
|
|
|
Shadow the required microcode patches data into memory according to PCD
|
|
|
|
PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize.
|
2019-12-19 07:33:44 +01:00
|
|
|
|
|
|
|
@param[in, out] CpuMpData The pointer to CPU MP Data structure.
|
|
|
|
**/
|
|
|
|
VOID
|
2020-01-08 04:22:30 +01:00
|
|
|
ShadowMicrocodePatchByPcd (
|
2019-12-19 07:33:44 +01:00
|
|
|
IN OUT CPU_MP_DATA *CpuMpData
|
|
|
|
)
|
|
|
|
{
|
2021-04-01 18:32:44 +02:00
|
|
|
UINTN Index;
|
2019-12-19 07:33:44 +01:00
|
|
|
CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
|
|
|
|
UINTN MicrocodeEnd;
|
|
|
|
UINTN TotalSize;
|
|
|
|
MICROCODE_PATCH_INFO *PatchInfoBuffer;
|
|
|
|
UINTN MaxPatchNumber;
|
|
|
|
UINTN PatchCount;
|
|
|
|
UINTN TotalLoadSize;
|
2021-04-01 18:32:44 +02:00
|
|
|
EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds;
|
|
|
|
BOOLEAN Valid;
|
2019-12-19 07:33:44 +01:00
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize the microcode patch related fields in CpuMpData as the values
|
|
|
|
// specified by the PCD pair. If the microcode patches are loaded into memory,
|
|
|
|
// these fields will be updated.
|
|
|
|
//
|
|
|
|
CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
|
|
|
|
CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
|
|
|
|
|
|
|
|
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->MicrocodePatchAddress;
|
|
|
|
MicrocodeEnd = (UINTN)MicrocodeEntryPoint +
|
|
|
|
(UINTN)CpuMpData->MicrocodePatchRegionSize;
|
|
|
|
if ((MicrocodeEntryPoint == NULL) || ((UINTN)MicrocodeEntryPoint == MicrocodeEnd)) {
|
|
|
|
//
|
|
|
|
// There is no microcode patches
|
|
|
|
//
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PatchCount = 0;
|
|
|
|
MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM;
|
|
|
|
TotalLoadSize = 0;
|
|
|
|
PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));
|
|
|
|
if (PatchInfoBuffer == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-12-19 07:33:44 +01:00
|
|
|
//
|
|
|
|
// Process the header of each microcode patch within the region.
|
|
|
|
// The purpose is to decide which microcode patch(es) will be loaded into memory.
|
2021-04-01 18:32:44 +02:00
|
|
|
// Microcode checksum is not verified because it's slow when performing on flash.
|
2019-12-19 07:33:44 +01:00
|
|
|
//
|
|
|
|
do {
|
2021-04-01 18:32:44 +02:00
|
|
|
Valid = IsValidMicrocode (
|
|
|
|
MicrocodeEntryPoint,
|
|
|
|
MicrocodeEnd - (UINTN)MicrocodeEntryPoint,
|
|
|
|
0,
|
|
|
|
MicrocodeCpuIds,
|
|
|
|
CpuMpData->CpuCount,
|
|
|
|
FALSE
|
|
|
|
);
|
|
|
|
if (!Valid) {
|
2019-12-19 07:33:44 +01:00
|
|
|
//
|
|
|
|
// Padding data between the microcode patches, skip 1KB to check next entry.
|
|
|
|
//
|
|
|
|
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + SIZE_1KB);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
PatchCount++;
|
|
|
|
if (PatchCount > MaxPatchNumber) {
|
2019-12-19 07:33:44 +01:00
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
// Current 'PatchInfoBuffer' cannot hold the information, double the size
|
|
|
|
// and allocate a new buffer.
|
2019-12-19 07:33:44 +01:00
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {
|
2019-12-19 07:33:44 +01:00
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
// Overflow check for MaxPatchNumber
|
2019-12-19 07:33:44 +01:00
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
goto OnExit;
|
2019-12-19 07:33:44 +01:00
|
|
|
}
|
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
PatchInfoBuffer = ReallocatePool (
|
|
|
|
MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
|
|
|
|
2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
|
|
|
|
PatchInfoBuffer
|
|
|
|
);
|
|
|
|
if (PatchInfoBuffer == NULL) {
|
|
|
|
goto OnExit;
|
|
|
|
}
|
2021-12-05 23:54:17 +01:00
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
MaxPatchNumber = MaxPatchNumber * 2;
|
2019-12-19 07:33:44 +01:00
|
|
|
}
|
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
TotalSize = GetMicrocodeLength (MicrocodeEntryPoint);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Store the information of this microcode patch
|
|
|
|
//
|
|
|
|
PatchInfoBuffer[PatchCount - 1].Address = (UINTN)MicrocodeEntryPoint;
|
|
|
|
PatchInfoBuffer[PatchCount - 1].Size = TotalSize;
|
|
|
|
TotalLoadSize += TotalSize;
|
|
|
|
|
2019-12-19 07:33:44 +01:00
|
|
|
//
|
|
|
|
// Process the next microcode patch
|
|
|
|
//
|
2021-04-01 18:32:44 +02:00
|
|
|
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)((UINTN)MicrocodeEntryPoint + TotalSize);
|
|
|
|
} while ((UINTN)MicrocodeEntryPoint < MicrocodeEnd);
|
2019-12-19 07:33:44 +01:00
|
|
|
|
|
|
|
if (PatchCount != 0) {
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_INFO,
|
|
|
|
"%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",
|
2023-04-06 21:49:10 +02:00
|
|
|
__func__,
|
2019-12-19 07:33:44 +01:00
|
|
|
PatchCount,
|
|
|
|
TotalLoadSize
|
|
|
|
));
|
|
|
|
|
2020-01-08 04:22:30 +01:00
|
|
|
ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);
|
2019-12-19 07:33:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
OnExit:
|
|
|
|
if (PatchInfoBuffer != NULL) {
|
|
|
|
FreePool (PatchInfoBuffer);
|
|
|
|
}
|
2021-12-05 23:54:17 +01:00
|
|
|
|
2021-04-01 18:32:44 +02:00
|
|
|
FreePages (MicrocodeCpuIds, EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID)));
|
2019-12-19 07:33:44 +01:00
|
|
|
}
|
2020-01-08 04:22:30 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
Shadow the required microcode patches data into memory.
|
|
|
|
|
|
|
|
@param[in, out] CpuMpData The pointer to CPU MP Data structure.
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
ShadowMicrocodeUpdatePatch (
|
|
|
|
IN OUT CPU_MP_DATA *CpuMpData
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
2020-02-11 14:30:48 +01:00
|
|
|
Status = PlatformShadowMicrocode (CpuMpData);
|
2020-01-08 04:22:30 +01:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
ShadowMicrocodePatchByPcd (CpuMpData);
|
|
|
|
}
|
|
|
|
}
|
UefiCpuPkg/MpInitLib: Not pass microcode info between archs in CPU_MP_DATA
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=2465
Commit 89164babec:
UefiCpuPkg/MpInitLib: don't shadow the microcode patch twice.
attempted to use 'MicrocodePatchRegionSize' and 'MicrocodePatchAddress'
fields to avoid loading the microcode patches data into memory again in
the DXE phase.
However, the CPU_MP_DATA structure has members with type 'UINTN' or
pointer before the microcode patch related fields. This may cause issues
when PEI and DXE are of different archs (e.g. PEI - IA32, DXE - x64),
since the microcode patch related fields will have different offsets in
the CPU_MP_DATA structure.
Commit 88bd066166:
UefiCpuPkg/MpInitLib: Relocate microcode patch fields in CPU_MP_DATA
tried to resolve the above-mentioned issue by relocating the fields
'MicrocodePatchRegionSize' and 'MicrocodePatchAddress' before members with
different size between different archs. But it failed to take the case of
pre-built binaries (e.g. FSP) into consideration.
Binaries can be built when the code base had a different version of the
CPU_MP_DATA structure definition. This may cause issues when accessing
these microcode patch related fields, since their offsets are different
(between PEI phase in the binaries and DXE phase in current code
implementation).
This commit will use the newly introduced EDKII microcode patch HOB
instead for the DXE phase to get the information of the loaded microcode
patches data done in the PEI phase. And the 'MicrocodePatchRegionSize' and
'MicrocodePatchAddress' fields in CPU_MP_DATA will not be used to pass
information between phases.
For pre-built binaries, they can be classified into 3 types with regard to
the time when they are being built:
A. Before commit 89164babec
(In other words, 'MicrocodePatchRegionSize' and 'MicrocodePatchAddress'
were not being used to skip microcode load in DXE)
For this case, the EDKII microcode patch HOB will not be produced. This
commit will load the microcode patches data again in DXE. Such behavior is
the same with the code base back then.
B. After commit 89164babec, before commit e1ed55738e
(In other words, 'MicrocodePatchRegionSize' and 'MicrocodePatchAddress'
being used to skip microcode load in DXE, but failed to work properly
between differnt archs.)
For this case, the EDKII microcode patch HOB will not be produced as well.
This commit will also load the microcode patches data again in DXE.
But since commit 89164babec failed to keep the detection and application
of microcode patches working properly in DXE after skipping the load, we
fall back to the origin behavior (that is to load the microcode patches
data again in DXE).
C. After commit e1ed55738e
(In other words, EDKII microcode patch HOB will be produced.)
For this case, it will have the same behavior with the BIOS built from
the current source codes.
Cc: Michael Kubacki <michael.a.kubacki@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Hao A Wu <hao.a.wu@intel.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
2020-01-22 07:02:05 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
Get the cached microcode patch base address and size from the microcode patch
|
|
|
|
information cache HOB.
|
|
|
|
|
|
|
|
@param[out] Address Base address of the microcode patches data.
|
|
|
|
It will be updated if the microcode patch
|
|
|
|
information cache HOB is found.
|
|
|
|
@param[out] RegionSize Size of the microcode patches data.
|
|
|
|
It will be updated if the microcode patch
|
|
|
|
information cache HOB is found.
|
|
|
|
|
|
|
|
@retval TRUE The microcode patch information cache HOB is found.
|
|
|
|
@retval FALSE The microcode patch information cache HOB is not found.
|
|
|
|
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
GetMicrocodePatchInfoFromHob (
|
|
|
|
UINT64 *Address,
|
|
|
|
UINT64 *RegionSize
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_HOB_GUID_TYPE *GuidHob;
|
|
|
|
EDKII_MICROCODE_PATCH_HOB *MicrocodePathHob;
|
|
|
|
|
|
|
|
GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid);
|
|
|
|
if (GuidHob == NULL) {
|
2023-04-06 21:49:10 +02:00
|
|
|
DEBUG ((DEBUG_INFO, "%a: Microcode patch cache HOB is not found.\n", __func__));
|
UefiCpuPkg/MpInitLib: Not pass microcode info between archs in CPU_MP_DATA
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=2465
Commit 89164babec:
UefiCpuPkg/MpInitLib: don't shadow the microcode patch twice.
attempted to use 'MicrocodePatchRegionSize' and 'MicrocodePatchAddress'
fields to avoid loading the microcode patches data into memory again in
the DXE phase.
However, the CPU_MP_DATA structure has members with type 'UINTN' or
pointer before the microcode patch related fields. This may cause issues
when PEI and DXE are of different archs (e.g. PEI - IA32, DXE - x64),
since the microcode patch related fields will have different offsets in
the CPU_MP_DATA structure.
Commit 88bd066166:
UefiCpuPkg/MpInitLib: Relocate microcode patch fields in CPU_MP_DATA
tried to resolve the above-mentioned issue by relocating the fields
'MicrocodePatchRegionSize' and 'MicrocodePatchAddress' before members with
different size between different archs. But it failed to take the case of
pre-built binaries (e.g. FSP) into consideration.
Binaries can be built when the code base had a different version of the
CPU_MP_DATA structure definition. This may cause issues when accessing
these microcode patch related fields, since their offsets are different
(between PEI phase in the binaries and DXE phase in current code
implementation).
This commit will use the newly introduced EDKII microcode patch HOB
instead for the DXE phase to get the information of the loaded microcode
patches data done in the PEI phase. And the 'MicrocodePatchRegionSize' and
'MicrocodePatchAddress' fields in CPU_MP_DATA will not be used to pass
information between phases.
For pre-built binaries, they can be classified into 3 types with regard to
the time when they are being built:
A. Before commit 89164babec
(In other words, 'MicrocodePatchRegionSize' and 'MicrocodePatchAddress'
were not being used to skip microcode load in DXE)
For this case, the EDKII microcode patch HOB will not be produced. This
commit will load the microcode patches data again in DXE. Such behavior is
the same with the code base back then.
B. After commit 89164babec, before commit e1ed55738e
(In other words, 'MicrocodePatchRegionSize' and 'MicrocodePatchAddress'
being used to skip microcode load in DXE, but failed to work properly
between differnt archs.)
For this case, the EDKII microcode patch HOB will not be produced as well.
This commit will also load the microcode patches data again in DXE.
But since commit 89164babec failed to keep the detection and application
of microcode patches working properly in DXE after skipping the load, we
fall back to the origin behavior (that is to load the microcode patches
data again in DXE).
C. After commit e1ed55738e
(In other words, EDKII microcode patch HOB will be produced.)
For this case, it will have the same behavior with the BIOS built from
the current source codes.
Cc: Michael Kubacki <michael.a.kubacki@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Hao A Wu <hao.a.wu@intel.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
2020-01-22 07:02:05 +01:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
MicrocodePathHob = GET_GUID_HOB_DATA (GuidHob);
|
|
|
|
|
|
|
|
*Address = MicrocodePathHob->MicrocodePatchAddress;
|
|
|
|
*RegionSize = MicrocodePathHob->MicrocodePatchRegionSize;
|
|
|
|
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_INFO,
|
|
|
|
"%a: MicrocodeBase = 0x%lx, MicrocodeSize = 0x%lx\n",
|
2023-04-06 21:49:10 +02:00
|
|
|
__func__,
|
UefiCpuPkg/MpInitLib: Not pass microcode info between archs in CPU_MP_DATA
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=2465
Commit 89164babec:
UefiCpuPkg/MpInitLib: don't shadow the microcode patch twice.
attempted to use 'MicrocodePatchRegionSize' and 'MicrocodePatchAddress'
fields to avoid loading the microcode patches data into memory again in
the DXE phase.
However, the CPU_MP_DATA structure has members with type 'UINTN' or
pointer before the microcode patch related fields. This may cause issues
when PEI and DXE are of different archs (e.g. PEI - IA32, DXE - x64),
since the microcode patch related fields will have different offsets in
the CPU_MP_DATA structure.
Commit 88bd066166:
UefiCpuPkg/MpInitLib: Relocate microcode patch fields in CPU_MP_DATA
tried to resolve the above-mentioned issue by relocating the fields
'MicrocodePatchRegionSize' and 'MicrocodePatchAddress' before members with
different size between different archs. But it failed to take the case of
pre-built binaries (e.g. FSP) into consideration.
Binaries can be built when the code base had a different version of the
CPU_MP_DATA structure definition. This may cause issues when accessing
these microcode patch related fields, since their offsets are different
(between PEI phase in the binaries and DXE phase in current code
implementation).
This commit will use the newly introduced EDKII microcode patch HOB
instead for the DXE phase to get the information of the loaded microcode
patches data done in the PEI phase. And the 'MicrocodePatchRegionSize' and
'MicrocodePatchAddress' fields in CPU_MP_DATA will not be used to pass
information between phases.
For pre-built binaries, they can be classified into 3 types with regard to
the time when they are being built:
A. Before commit 89164babec
(In other words, 'MicrocodePatchRegionSize' and 'MicrocodePatchAddress'
were not being used to skip microcode load in DXE)
For this case, the EDKII microcode patch HOB will not be produced. This
commit will load the microcode patches data again in DXE. Such behavior is
the same with the code base back then.
B. After commit 89164babec, before commit e1ed55738e
(In other words, 'MicrocodePatchRegionSize' and 'MicrocodePatchAddress'
being used to skip microcode load in DXE, but failed to work properly
between differnt archs.)
For this case, the EDKII microcode patch HOB will not be produced as well.
This commit will also load the microcode patches data again in DXE.
But since commit 89164babec failed to keep the detection and application
of microcode patches working properly in DXE after skipping the load, we
fall back to the origin behavior (that is to load the microcode patches
data again in DXE).
C. After commit e1ed55738e
(In other words, EDKII microcode patch HOB will be produced.)
For this case, it will have the same behavior with the BIOS built from
the current source codes.
Cc: Michael Kubacki <michael.a.kubacki@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Hao A Wu <hao.a.wu@intel.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
2020-01-22 07:02:05 +01:00
|
|
|
*Address,
|
|
|
|
*RegionSize
|
|
|
|
));
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|