/** @file\r
Implementation of loading microcode on processors.\r
\r
- Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
/**\r
Detect whether specified processor can find matching microcode patch and load it.\r
\r
- @param[in] CpuMpData The pointer to CPU MP Data structure.\r
- @param[in] IsBspCallIn Indicate whether the caller is BSP or not.\r
+ Microcode Payload as the following format:\r
+ +----------------------------------------+------------------+\r
+ | CPU_MICROCODE_HEADER | |\r
+ +----------------------------------------+ CheckSum Part1 |\r
+ | Microcode Binary | |\r
+ +----------------------------------------+------------------+\r
+ | CPU_MICROCODE_EXTENDED_TABLE_HEADER | |\r
+ +----------------------------------------+ CheckSum Part2 |\r
+ | CPU_MICROCODE_EXTENDED_TABLE | |\r
+ | ... | |\r
+ +----------------------------------------+------------------+\r
+\r
+ There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.\r
+ The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount\r
+ of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.\r
+\r
+ When we are trying to verify the CheckSum32 with extended table.\r
+ We should use the fields of exnteded table to replace the corresponding\r
+ fields in CPU_MICROCODE_HEADER structure, and recalculate the\r
+ CheckSum32 with CPU_MICROCODE_HEADER + Microcode Binary. We named\r
+ it as CheckSum Part3.\r
+\r
+ The CheckSum Part2 is used to verify the CPU_MICROCODE_EXTENDED_TABLE_HEADER\r
+ and CPU_MICROCODE_EXTENDED_TABLE parts. We should make sure CheckSum Part2\r
+ is correct before we are going to verify each CPU_MICROCODE_EXTENDED_TABLE.\r
+\r
+ Only ProcessorSignature, ProcessorFlag and CheckSum are different between\r
+ CheckSum Part1 and CheckSum Part3. To avoid multiple computing CheckSum Part3.\r
+ Save an in-complete CheckSum32 from CheckSum Part1 for common parts.\r
+ When we are going to calculate CheckSum32, just should use the corresponding part\r
+ of the ProcessorSignature, ProcessorFlag and CheckSum with in-complete CheckSum32.\r
+\r
+ Notes: CheckSum32 is not a strong verification.\r
+ It does not guarantee that the data has not been modified.\r
+ CPU has its own mechanism to verify Microcode Binary part.\r
+\r
+ @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+ @param[in] ProcessorNumber The handle number of the processor. The range is\r
+ from 0 to the total number of logical processors\r
+ minus 1.\r
**/\r
VOID\r
MicrocodeDetect (\r
IN CPU_MP_DATA *CpuMpData,\r
- IN BOOLEAN IsBspCallIn\r
+ IN UINTN ProcessorNumber\r
)\r
{\r
UINT32 ExtendedTableLength;\r
UINTN Index;\r
UINT8 PlatformId;\r
CPUID_VERSION_INFO_EAX Eax;\r
+ CPU_AP_DATA *CpuData;\r
UINT32 CurrentRevision;\r
UINT32 LatestRevision;\r
UINTN TotalSize;\r
UINT32 CheckSum32;\r
+ UINT32 InCompleteCheckSum32;\r
BOOLEAN CorrectMicrocode;\r
VOID *MicrocodeData;\r
- MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;\r
- UINT32 ProcessorFlags;\r
UINT32 ThreadId;\r
+ BOOLEAN IsBspCallIn;\r
\r
if (CpuMpData->MicrocodePatchRegionSize == 0) {\r
//\r
}\r
\r
CurrentRevision = GetCurrentMicrocodeSignature ();\r
+ IsBspCallIn = (ProcessorNumber == (UINTN)CpuMpData->BspNumber) ? TRUE : FALSE;\r
if (CurrentRevision != 0 && !IsBspCallIn) {\r
//\r
// Skip loading microcode if it has been loaded successfully\r
}\r
\r
ExtendedTableLength = 0;\r
- //\r
- // Here data of CPUID leafs have not been collected into context buffer, so\r
- // GetProcessorCpuid() cannot be used here to retrieve CPUID data.\r
- //\r
- AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);\r
-\r
- //\r
- // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID\r
- //\r
- PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);\r
- PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;\r
+ Eax.Uint32 = CpuMpData->CpuData[ProcessorNumber].ProcessorSignature;\r
+ PlatformId = CpuMpData->CpuData[ProcessorNumber].PlatformId;\r
\r
//\r
// Check whether AP has same processor with BSP.\r
// If yes, direct use microcode info saved by BSP.\r
//\r
if (!IsBspCallIn) {\r
- if ((CpuMpData->ProcessorSignature == Eax.Uint32) &&\r
- (CpuMpData->ProcessorFlags & (1 << PlatformId)) != 0) {\r
- MicrocodeData = (VOID *)(UINTN) CpuMpData->MicrocodeDataAddress;\r
- LatestRevision = CpuMpData->MicrocodeRevision;\r
- goto Done;\r
+ //\r
+ // Get the CPU data for BSP\r
+ //\r
+ CpuData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);\r
+ if ((CpuData->ProcessorSignature == Eax.Uint32) &&\r
+ (CpuData->PlatformId == PlatformId) &&\r
+ (CpuData->MicrocodeEntryAddr != 0)) {\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN) CpuData->MicrocodeEntryAddr;\r
+ MicrocodeData = (VOID *) (MicrocodeEntryPoint + 1);\r
+ LatestRevision = MicrocodeEntryPoint->UpdateRevision;\r
+ goto Done;\r
}\r
}\r
\r
MicrocodeData = NULL;\r
MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);\r
MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
+\r
do {\r
//\r
// Check if the microcode is for the Cpu and the version is newer\r
// and the update can be processed on the platform\r
//\r
CorrectMicrocode = FALSE;\r
+\r
+ if (MicrocodeEntryPoint->DataSize == 0) {\r
+ TotalSize = sizeof (CPU_MICROCODE_HEADER) + 2000;\r
+ } else {\r
+ TotalSize = sizeof (CPU_MICROCODE_HEADER) + MicrocodeEntryPoint->DataSize;\r
+ }\r
+\r
+ ///\r
+ /// 0x0 MicrocodeBegin MicrocodeEntry MicrocodeEnd 0xffffffff\r
+ /// |--------------|---------------|---------------|---------------|\r
+ /// valid TotalSize\r
+ /// TotalSize is only valid between 0 and (MicrocodeEnd - MicrocodeEntry).\r
+ /// And it should be aligned with 4 bytes.\r
+ /// If the TotalSize is invalid, skip 1KB to check next entry.\r
+ ///\r
+ if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||\r
+ ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||\r
+ (TotalSize & 0x3) != 0\r
+ ) {\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Save an in-complete CheckSum32 from CheckSum Part1 for common parts.\r
+ //\r
+ InCompleteCheckSum32 = CalculateSum32 (\r
+ (UINT32 *) MicrocodeEntryPoint,\r
+ TotalSize\r
+ );\r
+ InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
+ InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;\r
+ InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;\r
+\r
if (MicrocodeEntryPoint->HeaderVersion == 0x1) {\r
//\r
// It is the microcode header. It is not the padding data between microcode patches\r
MicrocodeEntryPoint->UpdateRevision > LatestRevision &&\r
(MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))\r
) {\r
- if (MicrocodeEntryPoint->DataSize == 0) {\r
- CheckSum32 = CalculateSum32 ((UINT32 *) MicrocodeEntryPoint, 2048);\r
- } else {\r
- CheckSum32 = CalculateSum32 (\r
- (UINT32 *) MicrocodeEntryPoint,\r
- MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)\r
- );\r
- }\r
+ //\r
+ // Calculate CheckSum Part1.\r
+ //\r
+ CheckSum32 = InCompleteCheckSum32;\r
+ CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
+ CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;\r
+ CheckSum32 += MicrocodeEntryPoint->Checksum;\r
if (CheckSum32 == 0) {\r
CorrectMicrocode = TRUE;\r
- ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags;\r
}\r
} else if ((MicrocodeEntryPoint->DataSize != 0) &&\r
(MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {\r
// Calculate Extended Checksum\r
//\r
if ((ExtendedTableLength % 4) == 0) {\r
+ //\r
+ // Calculate CheckSum Part2.\r
+ //\r
CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);\r
if (CheckSum32 == 0) {\r
//\r
ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);\r
for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
- CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));\r
+ //\r
+ // Calculate CheckSum Part3.\r
+ //\r
+ CheckSum32 = InCompleteCheckSum32;\r
+ CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;\r
+ CheckSum32 += ExtendedTable->ProcessorFlag;\r
+ CheckSum32 += ExtendedTable->Checksum;\r
if (CheckSum32 == 0) {\r
//\r
// Verify Header\r
// Find one\r
//\r
CorrectMicrocode = TRUE;\r
- ProcessorFlags = ExtendedTable->ProcessorFlag;\r
break;\r
}\r
}\r
} while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
\r
Done:\r
+ if (LatestRevision != 0) {\r
+ //\r
+ // Save the detected microcode patch entry address (including the\r
+ // microcode patch header) for each processor.\r
+ // It will be used when building the microcode patch cache HOB.\r
+ //\r
+ CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr =\r
+ (UINTN) MicrocodeData - sizeof (CPU_MICROCODE_HEADER);\r
+ }\r
+\r
if (LatestRevision > CurrentRevision) {\r
//\r
// BIOS only authenticate updates that contain a numerically larger revision\r
ReleaseSpinLock(&CpuMpData->MpLock);\r
}\r
}\r
+}\r
+\r
+/**\r
+ Determine if a microcode patch will be loaded into memory.\r
+\r
+ @param[in] CpuMpData The pointer to CPU MP Data structure.\r
+ @param[in] ProcessorSignature The processor signature field value\r
+ supported by a microcode patch.\r
+ @param[in] ProcessorFlags The prcessor flags field value supported by\r
+ a microcode patch.\r
+\r
+ @retval TRUE The specified microcode patch will be loaded.\r
+ @retval FALSE The specified microcode patch will not be loaded.\r
+**/\r
+BOOLEAN\r
+IsMicrocodePatchNeedLoad (\r
+ IN CPU_MP_DATA *CpuMpData,\r
+ IN UINT32 ProcessorSignature,\r
+ IN UINT32 ProcessorFlags\r
+ )\r
+{\r
+ UINTN Index;\r
+ CPU_AP_DATA *CpuData;\r
+\r
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+ CpuData = &CpuMpData->CpuData[Index];\r
+ if ((ProcessorSignature == CpuData->ProcessorSignature) &&\r
+ (ProcessorFlags & (1 << CpuData->PlatformId)) != 0) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Actual worker function that loads the required microcode patches into memory.\r
+\r
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
+ @param[in] Patches The pointer to an array of information on\r
+ the microcode patches that will be loaded\r
+ into memory.\r
+ @param[in] PatchCount The number of microcode patches that will\r
+ be loaded into memory.\r
+ @param[in] TotalLoadSize The total size of all the microcode patches\r
+ to be loaded.\r
+**/\r
+VOID\r
+LoadMicrocodePatchWorker (\r
+ IN OUT CPU_MP_DATA *CpuMpData,\r
+ IN MICROCODE_PATCH_INFO *Patches,\r
+ IN UINTN PatchCount,\r
+ IN UINTN TotalLoadSize\r
+ )\r
+{\r
+ UINTN Index;\r
+ VOID *MicrocodePatchInRam;\r
+ UINT8 *Walker;\r
+\r
+ ASSERT ((Patches != NULL) && (PatchCount != 0));\r
+\r
+ MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));\r
+ if (MicrocodePatchInRam == NULL) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Load all the required microcode patches into memory\r
+ //\r
+ for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {\r
+ CopyMem (\r
+ Walker,\r
+ (VOID *) Patches[Index].Address,\r
+ Patches[Index].Size\r
+ );\r
+\r
+ //\r
+ // Zero-fill the padding area\r
+ // Please note that AlignedSize will be no less than Size\r
+ //\r
+ ZeroMem (\r
+ Walker + Patches[Index].Size,\r
+ Patches[Index].AlignedSize - Patches[Index].Size\r
+ );\r
+\r
+ Walker += Patches[Index].AlignedSize;\r
+ }\r
+\r
+ //\r
+ // Update the microcode patch related fields in CpuMpData\r
+ //\r
+ CpuMpData->MicrocodePatchAddress = (UINTN) MicrocodePatchInRam;\r
+ CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",\r
+ __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize\r
+ ));\r
+\r
+ return;\r
+}\r
+\r
+/**\r
+ Load the required microcode patches data into memory.\r
+\r
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+LoadMicrocodePatch (\r
+ IN OUT CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
+ UINTN MicrocodeEnd;\r
+ UINTN DataSize;\r
+ UINTN TotalSize;\r
+ CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
+ UINT32 ExtendedTableCount;\r
+ CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
+ MICROCODE_PATCH_INFO *PatchInfoBuffer;\r
+ UINTN MaxPatchNumber;\r
+ UINTN PatchCount;\r
+ UINTN TotalLoadSize;\r
+ UINTN Index;\r
+ BOOLEAN NeedLoad;\r
+\r
+ //\r
+ // Initialize the microcode patch related fields in CpuMpData as the values\r
+ // specified by the PCD pair. If the microcode patches are loaded into memory,\r
+ // these fields will be updated.\r
+ //\r
+ CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
+ CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
+\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
+ MicrocodeEnd = (UINTN) MicrocodeEntryPoint +\r
+ (UINTN) CpuMpData->MicrocodePatchRegionSize;\r
+ if ((MicrocodeEntryPoint == NULL) || ((UINTN) MicrocodeEntryPoint == MicrocodeEnd)) {\r
+ //\r
+ // There is no microcode patches\r
+ //\r
+ return;\r
+ }\r
+\r
+ PatchCount = 0;\r
+ MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM;\r
+ TotalLoadSize = 0;\r
+ PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));\r
+ if (PatchInfoBuffer == NULL) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Process the header of each microcode patch within the region.\r
+ // The purpose is to decide which microcode patch(es) will be loaded into memory.\r
+ //\r
+ do {\r
+ if (MicrocodeEntryPoint->HeaderVersion != 0x1) {\r
+ //\r
+ // Padding data between the microcode patches, skip 1KB to check next entry.\r
+ //\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+ continue;\r
+ }\r
+\r
+ DataSize = MicrocodeEntryPoint->DataSize;\r
+ TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;\r
+ if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||\r
+ ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||\r
+ (DataSize & 0x3) != 0 ||\r
+ (TotalSize & (SIZE_1KB - 1)) != 0 ||\r
+ TotalSize < DataSize\r
+ ) {\r
+ //\r
+ // Not a valid microcode header, skip 1KB to check next entry.\r
+ //\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+ continue;\r
+ }\r
\r
- if (IsBspCallIn && (LatestRevision != 0)) {\r
//\r
- // Save BSP processor info and microcode info for later AP use.\r
+ // Check the 'ProcessorSignature' and 'ProcessorFlags' of the microcode\r
+ // patch header with the CPUID and PlatformID of the processors within\r
+ // system to decide if it will be copied into memory\r
+ //\r
+ NeedLoad = IsMicrocodePatchNeedLoad (\r
+ CpuMpData,\r
+ MicrocodeEntryPoint->ProcessorSignature.Uint32,\r
+ MicrocodeEntryPoint->ProcessorFlags\r
+ );\r
+\r
//\r
- CpuMpData->ProcessorSignature = Eax.Uint32;\r
- CpuMpData->ProcessorFlags = ProcessorFlags;\r
- CpuMpData->MicrocodeDataAddress = (UINTN) MicrocodeData;\r
- CpuMpData->MicrocodeRevision = LatestRevision;\r
- DEBUG ((DEBUG_INFO, "BSP Microcode:: signature [0x%08x], ProcessorFlags [0x%08x], \\r
- MicroData [0x%08x], Revision [0x%08x]\n", Eax.Uint32, ProcessorFlags, (UINTN) MicrocodeData, LatestRevision));\r
+ // If the Extended Signature Table exists, check if the processor is in the\r
+ // support list\r
+ //\r
+ if ((!NeedLoad) && (DataSize != 0) &&\r
+ (TotalSize - DataSize > sizeof (CPU_MICROCODE_HEADER) +\r
+ sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))) {\r
+ ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)\r
+ + DataSize + sizeof (CPU_MICROCODE_HEADER));\r
+ ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
+ ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);\r
+\r
+ for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
+ //\r
+ // Avoid access content beyond MicrocodeEnd\r
+ //\r
+ if ((UINTN) ExtendedTable > MicrocodeEnd - sizeof (CPU_MICROCODE_EXTENDED_TABLE)) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Check the 'ProcessorSignature' and 'ProcessorFlag' of the Extended\r
+ // Signature Table entry with the CPUID and PlatformID of the processors\r
+ // within system to decide if it will be copied into memory\r
+ //\r
+ NeedLoad = IsMicrocodePatchNeedLoad (\r
+ CpuMpData,\r
+ ExtendedTable->ProcessorSignature.Uint32,\r
+ ExtendedTable->ProcessorFlag\r
+ );\r
+ if (NeedLoad) {\r
+ break;\r
+ }\r
+ ExtendedTable ++;\r
+ }\r
+ }\r
+\r
+ if (NeedLoad) {\r
+ PatchCount++;\r
+ if (PatchCount > MaxPatchNumber) {\r
+ //\r
+ // Current 'PatchInfoBuffer' cannot hold the information, double the size\r
+ // and allocate a new buffer.\r
+ //\r
+ if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {\r
+ //\r
+ // Overflow check for MaxPatchNumber\r
+ //\r
+ goto OnExit;\r
+ }\r
+\r
+ PatchInfoBuffer = ReallocatePool (\r
+ MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),\r
+ 2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),\r
+ PatchInfoBuffer\r
+ );\r
+ if (PatchInfoBuffer == NULL) {\r
+ goto OnExit;\r
+ }\r
+ MaxPatchNumber = MaxPatchNumber * 2;\r
+ }\r
+\r
+ //\r
+ // Store the information of this microcode patch\r
+ //\r
+ if (TotalSize > ALIGN_VALUE (TotalSize, SIZE_1KB) ||\r
+ ALIGN_VALUE (TotalSize, SIZE_1KB) > MAX_UINTN - TotalLoadSize) {\r
+ goto OnExit;\r
+ }\r
+ PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;\r
+ PatchInfoBuffer[PatchCount - 1].Size = TotalSize;\r
+ PatchInfoBuffer[PatchCount - 1].AlignedSize = ALIGN_VALUE (TotalSize, SIZE_1KB);\r
+ TotalLoadSize += PatchInfoBuffer[PatchCount - 1].AlignedSize;\r
+ }\r
+\r
+ //\r
+ // Process the next microcode patch\r
+ //\r
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
+ } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
+\r
+ if (PatchCount != 0) {\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",\r
+ __FUNCTION__, PatchCount, TotalLoadSize\r
+ ));\r
+\r
+ LoadMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);\r
+ }\r
+\r
+OnExit:\r
+ if (PatchInfoBuffer != NULL) {\r
+ FreePool (PatchInfoBuffer);\r
}\r
+ return;\r
}\r