mirror of https://github.com/acidanthera/audk.git
982 lines
37 KiB
C
982 lines
37 KiB
C
/** @file
|
|
SetImage instance to update Microcode.
|
|
|
|
Caution: This module requires additional review when modified.
|
|
This module will have external input - capsule image.
|
|
This external input must be validated carefully to avoid security issue like
|
|
buffer overflow, integer overflow.
|
|
|
|
MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.
|
|
|
|
Copyright (c) 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 "MicrocodeUpdate.h"
|
|
|
|
/**
|
|
Get Microcode Region.
|
|
|
|
@param[out] MicrocodePatchAddress The address of Microcode
|
|
@param[out] MicrocodePatchRegionSize The region size of Microcode
|
|
|
|
@retval TRUE The Microcode region is returned.
|
|
@retval FALSE No Microcode region.
|
|
**/
|
|
BOOLEAN
|
|
GetMicrocodeRegion (
|
|
OUT VOID **MicrocodePatchAddress,
|
|
OUT UINTN *MicrocodePatchRegionSize
|
|
)
|
|
{
|
|
*MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);
|
|
*MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);
|
|
|
|
if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Get Microcode update signature of currently loaded Microcode update.
|
|
|
|
@return Microcode signature.
|
|
|
|
**/
|
|
UINT32
|
|
GetCurrentMicrocodeSignature (
|
|
VOID
|
|
)
|
|
{
|
|
UINT64 Signature;
|
|
|
|
AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0);
|
|
AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
|
|
Signature = AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID);
|
|
return (UINT32)RShiftU64(Signature, 32);
|
|
}
|
|
|
|
/**
|
|
Get current processor signature.
|
|
|
|
@return current processor signature.
|
|
**/
|
|
UINT32
|
|
GetCurrentProcessorSignature (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 RegEax;
|
|
AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
|
|
return RegEax;
|
|
}
|
|
|
|
/**
|
|
Get current platform ID.
|
|
|
|
@return current platform ID.
|
|
**/
|
|
UINT8
|
|
GetCurrentPlatformId (
|
|
VOID
|
|
)
|
|
{
|
|
UINT8 PlatformId;
|
|
|
|
PlatformId = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52);
|
|
return PlatformId;
|
|
}
|
|
|
|
/**
|
|
Load new Microcode.
|
|
|
|
@param[in] Address The address of new Microcode.
|
|
|
|
@return Loaded Microcode signature.
|
|
|
|
**/
|
|
UINT32
|
|
LoadMicrocode (
|
|
IN UINT64 Address
|
|
)
|
|
{
|
|
AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address);
|
|
return GetCurrentMicrocodeSignature();
|
|
}
|
|
|
|
/**
|
|
Load Microcode on an Application Processor.
|
|
The function prototype for invoking a function on an Application Processor.
|
|
|
|
@param[in,out] Buffer The pointer to private data buffer.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
MicrocodeLoadAp (
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
MICROCODE_LOAD_BUFFER *MicrocodeLoadBuffer;
|
|
|
|
MicrocodeLoadBuffer = Buffer;
|
|
MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);
|
|
}
|
|
|
|
/**
|
|
Load new Microcode on this processor
|
|
|
|
@param[in] MicrocodeFmpPrivate The Microcode driver private data
|
|
@param[in] CpuIndex The index of the processor.
|
|
@param[in] Address The address of new Microcode.
|
|
|
|
@return Loaded Microcode signature.
|
|
|
|
**/
|
|
UINT32
|
|
LoadMicrocodeOnThis (
|
|
IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
|
|
IN UINTN CpuIndex,
|
|
IN UINT64 Address
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_MP_SERVICES_PROTOCOL *MpService;
|
|
MICROCODE_LOAD_BUFFER MicrocodeLoadBuffer;
|
|
|
|
if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {
|
|
return LoadMicrocode (Address);
|
|
} else {
|
|
MpService = MicrocodeFmpPrivate->MpService;
|
|
MicrocodeLoadBuffer.Address = Address;
|
|
MicrocodeLoadBuffer.Revision = 0;
|
|
Status = MpService->StartupThisAP (
|
|
MpService,
|
|
MicrocodeLoadAp,
|
|
CpuIndex,
|
|
NULL,
|
|
0,
|
|
&MicrocodeLoadBuffer,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR(Status);
|
|
return MicrocodeLoadBuffer.Revision;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Collect processor information.
|
|
The function prototype for invoking a function on an Application Processor.
|
|
|
|
@param[in,out] Buffer The pointer to private data buffer.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
CollectProcessorInfo (
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
PROCESSOR_INFO *ProcessorInfo;
|
|
|
|
ProcessorInfo = Buffer;
|
|
ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();
|
|
ProcessorInfo->PlatformId = GetCurrentPlatformId();
|
|
ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();
|
|
}
|
|
|
|
/**
|
|
Get current Microcode information.
|
|
|
|
The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
|
|
in MicrocodeFmpPrivate must be initialized.
|
|
|
|
The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
|
|
in MicrocodeFmpPrivate may not be avaiable in this function.
|
|
|
|
@param[in] MicrocodeFmpPrivate The Microcode driver private data
|
|
@param[in] DescriptorCount The count of Microcode ImageDescriptor allocated.
|
|
@param[out] ImageDescriptor Microcode ImageDescriptor
|
|
@param[out] MicrocodeInfo Microcode information
|
|
|
|
@return Microcode count
|
|
**/
|
|
UINTN
|
|
GetMicrocodeInfo (
|
|
IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
|
|
IN UINTN DescriptorCount, OPTIONAL
|
|
OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL
|
|
OUT MICROCODE_INFO *MicrocodeInfo OPTIONAL
|
|
)
|
|
{
|
|
VOID *MicrocodePatchAddress;
|
|
UINTN MicrocodePatchRegionSize;
|
|
CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
|
|
UINTN MicrocodeEnd;
|
|
UINTN TotalSize;
|
|
UINTN Count;
|
|
UINT64 ImageAttributes;
|
|
BOOLEAN IsInUse;
|
|
EFI_STATUS Status;
|
|
UINT32 AttemptStatus;
|
|
UINTN TargetCpuIndex;
|
|
|
|
MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
|
|
MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
|
|
|
|
DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));
|
|
|
|
Count = 0;
|
|
|
|
MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;
|
|
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
|
|
do {
|
|
if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {
|
|
//
|
|
// It is the microcode header. It is not the padding data between microcode patches
|
|
// becasue the padding data should not include 0x00000001 and it should be the repeated
|
|
// byte format (like 0xXYXYXYXY....).
|
|
//
|
|
if (MicrocodeEntryPoint->DataSize == 0) {
|
|
TotalSize = 2048;
|
|
} else {
|
|
TotalSize = MicrocodeEntryPoint->TotalSize;
|
|
}
|
|
|
|
TargetCpuIndex = (UINTN)-1;
|
|
Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);
|
|
if (!EFI_ERROR(Status)) {
|
|
IsInUse = TRUE;
|
|
ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
|
|
MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;
|
|
} else {
|
|
IsInUse = FALSE;
|
|
}
|
|
|
|
if (ImageDescriptor != NULL && DescriptorCount > Count) {
|
|
ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);
|
|
CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);
|
|
ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32;
|
|
ImageDescriptor[Count].ImageIdName = NULL;
|
|
ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision;
|
|
ImageDescriptor[Count].VersionName = NULL;
|
|
ImageDescriptor[Count].Size = TotalSize;
|
|
ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;
|
|
if (IsInUse) {
|
|
ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;
|
|
}
|
|
ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;
|
|
ImageDescriptor[Count].AttributesSetting = ImageAttributes;
|
|
ImageDescriptor[Count].Compatibilities = 0;
|
|
ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback
|
|
ImageDescriptor[Count].LastAttemptVersion = 0;
|
|
ImageDescriptor[Count].LastAttemptStatus = 0;
|
|
ImageDescriptor[Count].HardwareInstance = 0;
|
|
}
|
|
if (MicrocodeInfo != NULL && DescriptorCount > Count) {
|
|
MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;
|
|
MicrocodeInfo[Count].TotalSize = TotalSize;
|
|
MicrocodeInfo[Count].InUse = IsInUse;
|
|
}
|
|
} 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;
|
|
}
|
|
|
|
Count++;
|
|
ASSERT(Count < 0xFF);
|
|
|
|
//
|
|
// Get the next patch.
|
|
//
|
|
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
|
|
} while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
|
|
|
|
return Count;
|
|
}
|
|
|
|
/**
|
|
Return matched processor information.
|
|
|
|
@param[in] MicrocodeFmpPrivate The Microcode driver private data
|
|
@param[in] ProcessorSignature The processor signature to be matched
|
|
@param[in] ProcessorFlags The processor flags to be matched
|
|
@param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
|
|
On output, the index of target CPU which matches the Microcode.
|
|
|
|
@return matched processor information.
|
|
**/
|
|
PROCESSOR_INFO *
|
|
GetMatchedProcessor (
|
|
IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
|
|
IN UINT32 ProcessorSignature,
|
|
IN UINT32 ProcessorFlags,
|
|
IN OUT UINTN *TargetCpuIndex
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
if (*TargetCpuIndex != (UINTN)-1) {
|
|
Index = *TargetCpuIndex;
|
|
if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
|
|
((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
|
|
return &MicrocodeFmpPrivate->ProcessorInfo[Index];
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {
|
|
if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
|
|
((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
|
|
*TargetCpuIndex = Index;
|
|
return &MicrocodeFmpPrivate->ProcessorInfo[Index];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Verify Microcode.
|
|
|
|
Caution: This function may receive untrusted input.
|
|
|
|
@param[in] MicrocodeFmpPrivate The Microcode driver private data
|
|
@param[in] Image The Microcode image buffer.
|
|
@param[in] ImageSize The size of Microcode image buffer in bytes.
|
|
@param[in] TryLoad Try to load Microcode or not.
|
|
@param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
|
|
@param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
|
|
details for the aborted operation. The buffer is allocated by this function
|
|
with AllocatePool(), and it is the caller's responsibility to free it with a
|
|
call to FreePool().
|
|
@param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
|
|
On output, the index of target CPU which matches the Microcode.
|
|
|
|
@retval EFI_SUCCESS The Microcode image passes verification.
|
|
@retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
|
|
@retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
|
|
@retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.
|
|
@retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
|
|
**/
|
|
EFI_STATUS
|
|
VerifyMicrocode (
|
|
IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
|
|
IN VOID *Image,
|
|
IN UINTN ImageSize,
|
|
IN BOOLEAN TryLoad,
|
|
OUT UINT32 *LastAttemptStatus,
|
|
OUT CHAR16 **AbortReason, OPTIONAL
|
|
IN OUT UINTN *TargetCpuIndex
|
|
)
|
|
{
|
|
UINTN Index;
|
|
CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
|
|
UINTN TotalSize;
|
|
UINTN DataSize;
|
|
UINT32 CurrentRevision;
|
|
PROCESSOR_INFO *ProcessorInfo;
|
|
UINT32 CheckSum32;
|
|
UINTN ExtendedTableLength;
|
|
UINT32 ExtendedTableCount;
|
|
CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
|
|
CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
|
|
BOOLEAN CorrectMicrocode;
|
|
|
|
//
|
|
// Check HeaderVersion
|
|
//
|
|
MicrocodeEntryPoint = Image;
|
|
if (MicrocodeEntryPoint->HeaderVersion != 0x1) {
|
|
DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
|
|
if (AbortReason != NULL) {
|
|
*AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion");
|
|
}
|
|
return EFI_INCOMPATIBLE_VERSION;
|
|
}
|
|
//
|
|
// Check LoaderRevision
|
|
//
|
|
if (MicrocodeEntryPoint->LoaderRevision != 0x1) {
|
|
DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
|
|
if (AbortReason != NULL) {
|
|
*AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion");
|
|
}
|
|
return EFI_INCOMPATIBLE_VERSION;
|
|
}
|
|
//
|
|
// Check Size
|
|
//
|
|
if (MicrocodeEntryPoint->DataSize == 0) {
|
|
TotalSize = 2048;
|
|
} else {
|
|
TotalSize = MicrocodeEntryPoint->TotalSize;
|
|
}
|
|
if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) {
|
|
DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
|
|
if (AbortReason != NULL) {
|
|
*AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
|
|
}
|
|
return EFI_VOLUME_CORRUPTED;
|
|
}
|
|
if (TotalSize != ImageSize) {
|
|
DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on TotalSize\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
|
|
if (AbortReason != NULL) {
|
|
*AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");
|
|
}
|
|
return EFI_VOLUME_CORRUPTED;
|
|
}
|
|
//
|
|
// Check CheckSum32
|
|
//
|
|
if (MicrocodeEntryPoint->DataSize == 0) {
|
|
DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);
|
|
} else {
|
|
DataSize = MicrocodeEntryPoint->DataSize;
|
|
}
|
|
if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) {
|
|
DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
|
|
if (AbortReason != NULL) {
|
|
*AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");
|
|
}
|
|
return EFI_VOLUME_CORRUPTED;
|
|
}
|
|
if ((DataSize & 0x3) != 0) {
|
|
DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize not aligned\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
|
|
if (AbortReason != NULL) {
|
|
*AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");
|
|
}
|
|
return EFI_VOLUME_CORRUPTED;
|
|
}
|
|
CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));
|
|
if (CheckSum32 != 0) {
|
|
DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;
|
|
if (AbortReason != NULL) {
|
|
*AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum");
|
|
}
|
|
return EFI_VOLUME_CORRUPTED;
|
|
}
|
|
|
|
//
|
|
// Check ProcessorSignature/ProcessorFlags
|
|
//
|
|
|
|
ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);
|
|
if (ProcessorInfo == NULL) {
|
|
CorrectMicrocode = FALSE;
|
|
ExtendedTableLength = TotalSize - (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) + DataSize + sizeof(CPU_MICROCODE_HEADER));
|
|
//
|
|
// Calculate Extended Checksum
|
|
//
|
|
if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) != 0)) {
|
|
CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
|
|
if (CheckSum32 == 0) {
|
|
//
|
|
// Checksum correct
|
|
//
|
|
ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
|
|
if (ExtendedTableCount <= (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {
|
|
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
|
|
//
|
|
ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);
|
|
if (ProcessorInfo != NULL) {
|
|
//
|
|
// Find one
|
|
//
|
|
CorrectMicrocode = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
ExtendedTable++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!CorrectMicrocode) {
|
|
if (TryLoad) {
|
|
DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));
|
|
}
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
|
|
if (AbortReason != NULL) {
|
|
*AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature/ProcessorFlags"), L"UnsupportedProcessSignature/ProcessorFlags");
|
|
}
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check UpdateRevision
|
|
//
|
|
CurrentRevision = ProcessorInfo->MicrocodeRevision;
|
|
if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||
|
|
(TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {
|
|
if (TryLoad) {
|
|
DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));
|
|
}
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
|
|
if (AbortReason != NULL) {
|
|
*AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");
|
|
}
|
|
return EFI_INCOMPATIBLE_VERSION;
|
|
}
|
|
|
|
//
|
|
// try load MCU
|
|
//
|
|
if (TryLoad) {
|
|
CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));
|
|
if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {
|
|
DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;
|
|
if (AbortReason != NULL) {
|
|
*AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");
|
|
}
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get next Microcode entrypoint.
|
|
|
|
@param[in] MicrocodeFmpPrivate The Microcode driver private data
|
|
@param[in] MicrocodeEntryPoint Current Microcode entrypoint
|
|
|
|
@return next Microcode entrypoint.
|
|
**/
|
|
CPU_MICROCODE_HEADER *
|
|
GetNextMicrocode (
|
|
IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
|
|
IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
|
|
if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {
|
|
if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {
|
|
// it is last one
|
|
return NULL;
|
|
} else {
|
|
// return next one
|
|
return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Get current Microcode used region size.
|
|
|
|
@param[in] MicrocodeFmpPrivate The Microcode driver private data
|
|
|
|
@return current Microcode used region size.
|
|
**/
|
|
UINTN
|
|
GetCurrentMicrocodeUsedRegionSize (
|
|
IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
|
|
)
|
|
{
|
|
if (MicrocodeFmpPrivate->DescriptorCount == 0) {
|
|
return 0;
|
|
}
|
|
|
|
return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint
|
|
+ (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize
|
|
- (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;
|
|
}
|
|
|
|
/**
|
|
Update Microcode.
|
|
|
|
@param[in] Address The flash address of Microcode.
|
|
@param[in] Image The Microcode image buffer.
|
|
@param[in] ImageSize The size of Microcode image buffer in bytes.
|
|
@param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
|
|
|
|
@retval EFI_SUCCESS The Microcode image is updated.
|
|
@retval EFI_WRITE_PROTECTED The flash device is read only.
|
|
**/
|
|
EFI_STATUS
|
|
UpdateMicrocode (
|
|
IN UINT64 Address,
|
|
IN VOID *Image,
|
|
IN UINTN ImageSize,
|
|
OUT UINT32 *LastAttemptStatus
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG((DEBUG_INFO, "PlatformUpdate:"));
|
|
DEBUG((DEBUG_INFO, " Address - 0x%lx,", Address));
|
|
DEBUG((DEBUG_INFO, " Legnth - 0x%x\n", ImageSize));
|
|
|
|
Status = MicrocodeFlashWrite (
|
|
Address,
|
|
Image,
|
|
ImageSize
|
|
);
|
|
if (!EFI_ERROR(Status)) {
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
|
|
} else {
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Update Microcode flash region.
|
|
|
|
@param[in] MicrocodeFmpPrivate The Microcode driver private data
|
|
@param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated
|
|
@param[in] Image The Microcode image buffer.
|
|
@param[in] ImageSize The size of Microcode image buffer in bytes.
|
|
@param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
|
|
|
|
@retval EFI_SUCCESS The Microcode image is written.
|
|
@retval EFI_WRITE_PROTECTED The flash device is read only.
|
|
**/
|
|
EFI_STATUS
|
|
UpdateMicrocodeFlashRegion (
|
|
IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
|
|
IN CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint,
|
|
IN VOID *Image,
|
|
IN UINTN ImageSize,
|
|
OUT UINT32 *LastAttemptStatus
|
|
)
|
|
{
|
|
VOID *MicrocodePatchAddress;
|
|
UINTN MicrocodePatchRegionSize;
|
|
UINTN TargetTotalSize;
|
|
UINTN UsedRegionSize;
|
|
EFI_STATUS Status;
|
|
VOID *MicrocodePatchScratchBuffer;
|
|
UINT8 *ScratchBufferPtr;
|
|
UINTN ScratchBufferSize;
|
|
UINTN RestSize;
|
|
UINTN AvailableSize;
|
|
VOID *NextMicrocodeEntryPoint;
|
|
MICROCODE_INFO *MicrocodeInfo;
|
|
UINTN MicrocodeCount;
|
|
UINTN Index;
|
|
|
|
DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));
|
|
|
|
MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
|
|
MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
|
|
|
|
MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);
|
|
if (MicrocodePatchScratchBuffer == NULL) {
|
|
DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
ScratchBufferPtr = MicrocodePatchScratchBuffer;
|
|
ScratchBufferSize = 0;
|
|
|
|
//
|
|
// Target data collection
|
|
//
|
|
TargetTotalSize = 0;
|
|
AvailableSize = 0;
|
|
NextMicrocodeEntryPoint = NULL;
|
|
if (TargetMicrocodeEntryPoint != NULL) {
|
|
if (TargetMicrocodeEntryPoint->DataSize == 0) {
|
|
TargetTotalSize = 2048;
|
|
} else {
|
|
TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;
|
|
}
|
|
DEBUG((DEBUG_INFO, " TargetTotalSize - 0x%x\n", TargetTotalSize));
|
|
NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);
|
|
DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));
|
|
if (NextMicrocodeEntryPoint != NULL) {
|
|
ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
|
|
AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;
|
|
} else {
|
|
AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;
|
|
}
|
|
DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));
|
|
}
|
|
ASSERT (AvailableSize >= TargetTotalSize);
|
|
UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);
|
|
DEBUG((DEBUG_INFO, " UsedRegionSize - 0x%x\n", UsedRegionSize));
|
|
ASSERT (UsedRegionSize >= TargetTotalSize);
|
|
if (TargetMicrocodeEntryPoint != NULL) {
|
|
ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
|
|
}
|
|
//
|
|
// Total Size means the Microcode data size.
|
|
// Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.
|
|
//
|
|
// (1)
|
|
// +------+-----------+-----+------+===================+
|
|
// | MCU1 | Microcode | PAD | MCU2 | Empty |
|
|
// +------+-----------+-----+------+===================+
|
|
// | TotalSize |
|
|
// |<-AvailableSize->|
|
|
// |<- UsedRegionSize ->|
|
|
//
|
|
// (2)
|
|
// +------+-----------+===================+
|
|
// | MCU | Microcode | Empty |
|
|
// +------+-----------+===================+
|
|
// | TotalSize |
|
|
// |<- AvailableSize ->|
|
|
// |<-UsedRegionSize->|
|
|
//
|
|
|
|
//
|
|
// Update based on policy
|
|
//
|
|
|
|
//
|
|
// 1. If there is enough space to update old one in situ, replace old microcode in situ.
|
|
//
|
|
if (AvailableSize >= ImageSize) {
|
|
DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));
|
|
//
|
|
// +------+------------+------+===================+
|
|
// |Other1| Old Image |Other2| Empty |
|
|
// +------+------------+------+===================+
|
|
//
|
|
// +------+---------+--+------+===================+
|
|
// |Other1|New Image|FF|Other2| Empty |
|
|
// +------+---------+--+------+===================+
|
|
//
|
|
// 1.1. Copy new image
|
|
CopyMem (ScratchBufferPtr, Image, ImageSize);
|
|
ScratchBufferSize += ImageSize;
|
|
ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
|
|
// 1.2. Pad 0xFF
|
|
RestSize = AvailableSize - ImageSize;
|
|
if (RestSize > 0) {
|
|
SetMem (ScratchBufferPtr, RestSize, 0xFF);
|
|
ScratchBufferSize += RestSize;
|
|
ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
|
|
}
|
|
Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.
|
|
//
|
|
if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {
|
|
if (TargetMicrocodeEntryPoint == NULL) {
|
|
DEBUG((DEBUG_INFO, "Append new microcode\n"));
|
|
//
|
|
// +------+------------+------+===================+
|
|
// |Other1| Other |Other2| Empty |
|
|
// +------+------------+------+===================+
|
|
//
|
|
// +------+------------+------+-----------+=======+
|
|
// |Other1| Other |Other2| New Image | Empty |
|
|
// +------+------------+------+-----------+=======+
|
|
//
|
|
Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);
|
|
} else {
|
|
DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));
|
|
//
|
|
// +------+------------+------+===================+
|
|
// |Other1| Old Image |Other2| Empty |
|
|
// +------+------------+------+===================+
|
|
//
|
|
// +------+---------------+------+================+
|
|
// |Other1| New Image |Other2| Empty |
|
|
// +------+---------------+------+================+
|
|
//
|
|
// 2.1. Copy new image
|
|
CopyMem (ScratchBufferPtr, Image, ImageSize);
|
|
ScratchBufferSize += ImageSize;
|
|
ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
|
|
// 2.2. Copy rest images after the old image.
|
|
if (NextMicrocodeEntryPoint != 0) {
|
|
RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);
|
|
CopyMem (ScratchBufferPtr, (UINT8 *)TargetMicrocodeEntryPoint + TargetTotalSize, RestSize);
|
|
ScratchBufferSize += RestSize;
|
|
ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
|
|
}
|
|
Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// 3. The new image can be put in MCU region, but not all others can be put.
|
|
// So all the unused MCU is removed.
|
|
//
|
|
if (MicrocodePatchRegionSize >= ImageSize) {
|
|
//
|
|
// +------+------------+------+===================+
|
|
// |Other1| Old Image |Other2| Empty |
|
|
// +------+------------+------+===================+
|
|
//
|
|
// +-------------------------------------+--------+
|
|
// | New Image | Other |
|
|
// +-------------------------------------+--------+
|
|
//
|
|
DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));
|
|
|
|
MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;
|
|
MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
|
|
|
|
// 3.1. Copy new image
|
|
CopyMem (ScratchBufferPtr, Image, ImageSize);
|
|
ScratchBufferSize += ImageSize;
|
|
ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
|
|
// 3.2. Copy some others to rest buffer
|
|
for (Index = 0; Index < MicrocodeCount; Index++) {
|
|
if (!MicrocodeInfo[Index].InUse) {
|
|
continue;
|
|
}
|
|
if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {
|
|
continue;
|
|
}
|
|
if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {
|
|
CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);
|
|
ScratchBufferSize += MicrocodeInfo[Index].TotalSize;
|
|
ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
|
|
}
|
|
}
|
|
// 3.3. Pad 0xFF
|
|
RestSize = MicrocodePatchRegionSize - ScratchBufferSize;
|
|
if (RestSize > 0) {
|
|
SetMem (ScratchBufferPtr, RestSize, 0xFF);
|
|
ScratchBufferSize += RestSize;
|
|
ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
|
|
}
|
|
Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// 4. The new image size is bigger than the whole MCU region.
|
|
//
|
|
DEBUG((DEBUG_ERROR, "Microcode too big\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Write Microcode.
|
|
|
|
Caution: This function may receive untrusted input.
|
|
|
|
@param[in] MicrocodeFmpPrivate The Microcode driver private data
|
|
@param[in] Image The Microcode image buffer.
|
|
@param[in] ImageSize The size of Microcode image buffer in bytes.
|
|
@param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
|
|
@param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
|
|
@param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
|
|
details for the aborted operation. The buffer is allocated by this function
|
|
with AllocatePool(), and it is the caller's responsibility to free it with a
|
|
call to FreePool().
|
|
|
|
@retval EFI_SUCCESS The Microcode image is written.
|
|
@retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
|
|
@retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
|
|
@retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
|
|
@retval EFI_WRITE_PROTECTED The flash device is read only.
|
|
**/
|
|
EFI_STATUS
|
|
MicrocodeWrite (
|
|
IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,
|
|
IN VOID *Image,
|
|
IN UINTN ImageSize,
|
|
OUT UINT32 *LastAttemptVersion,
|
|
OUT UINT32 *LastAttemptStatus,
|
|
OUT CHAR16 **AbortReason
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *AlignedImage;
|
|
CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint;
|
|
UINTN TargetCpuIndex;
|
|
UINTN TargetMicrcodeIndex;
|
|
|
|
//
|
|
// MCU must be 16 bytes aligned
|
|
//
|
|
AlignedImage = AllocateCopyPool(ImageSize, Image);
|
|
if (AlignedImage == NULL) {
|
|
DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));
|
|
*LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
*LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;
|
|
TargetCpuIndex = (UINTN)-1;
|
|
Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);
|
|
if (EFI_ERROR(Status)) {
|
|
DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));
|
|
FreePool(AlignedImage);
|
|
return Status;
|
|
}
|
|
DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));
|
|
|
|
DEBUG((DEBUG_INFO, " TargetCpuIndex - 0x%x\n", TargetCpuIndex));
|
|
ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
|
|
TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;
|
|
DEBUG((DEBUG_INFO, " TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));
|
|
if (TargetMicrcodeIndex != (UINTN)-1) {
|
|
ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);
|
|
TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;
|
|
} else {
|
|
TargetMicrocodeEntryPoint = NULL;
|
|
}
|
|
DEBUG((DEBUG_INFO, " TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));
|
|
|
|
Status = UpdateMicrocodeFlashRegion(
|
|
MicrocodeFmpPrivate,
|
|
TargetMicrocodeEntryPoint,
|
|
AlignedImage,
|
|
ImageSize,
|
|
LastAttemptStatus
|
|
);
|
|
|
|
FreePool(AlignedImage);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|