]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/Microcode.c
a9d06dd4099a81b1f0e557cec1cacab884c6e8b5
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / Microcode.c
1 /** @file
2 Implementation of loading microcode on processors.
3
4 Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "MpLib.h"
10
11 /**
12 Get microcode update signature of currently loaded microcode update.
13
14 @return Microcode signature.
15 **/
16 UINT32
17 GetCurrentMicrocodeSignature (
18 VOID
19 )
20 {
21 MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr;
22
23 AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);
24 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
25 BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);
26 return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;
27 }
28
29 /**
30 Detect whether specified processor can find matching microcode patch and load it.
31
32 Microcode Payload as the following format:
33 +----------------------------------------+------------------+
34 | CPU_MICROCODE_HEADER | |
35 +----------------------------------------+ CheckSum Part1 |
36 | Microcode Binary | |
37 +----------------------------------------+------------------+
38 | CPU_MICROCODE_EXTENDED_TABLE_HEADER | |
39 +----------------------------------------+ CheckSum Part2 |
40 | CPU_MICROCODE_EXTENDED_TABLE | |
41 | ... | |
42 +----------------------------------------+------------------+
43
44 There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.
45 The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount
46 of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.
47
48 When we are trying to verify the CheckSum32 with extended table.
49 We should use the fields of exnteded table to replace the corresponding
50 fields in CPU_MICROCODE_HEADER structure, and recalculate the
51 CheckSum32 with CPU_MICROCODE_HEADER + Microcode Binary. We named
52 it as CheckSum Part3.
53
54 The CheckSum Part2 is used to verify the CPU_MICROCODE_EXTENDED_TABLE_HEADER
55 and CPU_MICROCODE_EXTENDED_TABLE parts. We should make sure CheckSum Part2
56 is correct before we are going to verify each CPU_MICROCODE_EXTENDED_TABLE.
57
58 Only ProcessorSignature, ProcessorFlag and CheckSum are different between
59 CheckSum Part1 and CheckSum Part3. To avoid multiple computing CheckSum Part3.
60 Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
61 When we are going to calculate CheckSum32, just should use the corresponding part
62 of the ProcessorSignature, ProcessorFlag and CheckSum with in-complete CheckSum32.
63
64 Notes: CheckSum32 is not a strong verification.
65 It does not guarantee that the data has not been modified.
66 CPU has its own mechanism to verify Microcode Binary part.
67
68 @param[in] CpuMpData The pointer to CPU MP Data structure.
69 @param[in] ProcessorNumber The handle number of the processor. The range is
70 from 0 to the total number of logical processors
71 minus 1.
72 **/
73 VOID
74 MicrocodeDetect (
75 IN CPU_MP_DATA *CpuMpData,
76 IN UINTN ProcessorNumber
77 )
78 {
79 UINT32 ExtendedTableLength;
80 UINT32 ExtendedTableCount;
81 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
82 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
83 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
84 UINTN MicrocodeEnd;
85 UINTN Index;
86 UINT8 PlatformId;
87 CPUID_VERSION_INFO_EAX Eax;
88 CPU_AP_DATA *CpuData;
89 UINT32 CurrentRevision;
90 UINT32 LatestRevision;
91 UINTN TotalSize;
92 UINT32 CheckSum32;
93 UINT32 InCompleteCheckSum32;
94 BOOLEAN CorrectMicrocode;
95 VOID *MicrocodeData;
96 UINT32 ThreadId;
97 BOOLEAN IsBspCallIn;
98
99 if (CpuMpData->MicrocodePatchRegionSize == 0) {
100 //
101 // There is no microcode patches
102 //
103 return;
104 }
105
106 CurrentRevision = GetCurrentMicrocodeSignature ();
107 IsBspCallIn = (ProcessorNumber == (UINTN)CpuMpData->BspNumber) ? TRUE : FALSE;
108 if (CurrentRevision != 0 && !IsBspCallIn) {
109 //
110 // Skip loading microcode if it has been loaded successfully
111 //
112 return;
113 }
114
115 GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
116 if (ThreadId != 0) {
117 //
118 // Skip loading microcode if it is not the first thread in one core.
119 //
120 return;
121 }
122
123 ExtendedTableLength = 0;
124 Eax.Uint32 = CpuMpData->CpuData[ProcessorNumber].ProcessorSignature;
125 PlatformId = CpuMpData->CpuData[ProcessorNumber].PlatformId;
126
127 //
128 // Check whether AP has same processor with BSP.
129 // If yes, direct use microcode info saved by BSP.
130 //
131 if (!IsBspCallIn) {
132 //
133 // Get the CPU data for BSP
134 //
135 CpuData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);
136 if ((CpuData->ProcessorSignature == Eax.Uint32) &&
137 (CpuData->PlatformId == PlatformId) &&
138 (CpuData->MicrocodeEntryAddr != 0)) {
139 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN) CpuData->MicrocodeEntryAddr;
140 MicrocodeData = (VOID *) (MicrocodeEntryPoint + 1);
141 LatestRevision = MicrocodeEntryPoint->UpdateRevision;
142 goto Done;
143 }
144 }
145
146 LatestRevision = 0;
147 MicrocodeData = NULL;
148 MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);
149 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
150
151 do {
152 //
153 // Check if the microcode is for the Cpu and the version is newer
154 // and the update can be processed on the platform
155 //
156 CorrectMicrocode = FALSE;
157
158 if (MicrocodeEntryPoint->DataSize == 0) {
159 TotalSize = sizeof (CPU_MICROCODE_HEADER) + 2000;
160 } else {
161 TotalSize = sizeof (CPU_MICROCODE_HEADER) + MicrocodeEntryPoint->DataSize;
162 }
163
164 ///
165 /// 0x0 MicrocodeBegin MicrocodeEntry MicrocodeEnd 0xffffffff
166 /// |--------------|---------------|---------------|---------------|
167 /// valid TotalSize
168 /// TotalSize is only valid between 0 and (MicrocodeEnd - MicrocodeEntry).
169 /// And it should be aligned with 4 bytes.
170 /// If the TotalSize is invalid, skip 1KB to check next entry.
171 ///
172 if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||
173 ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
174 (TotalSize & 0x3) != 0
175 ) {
176 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
177 continue;
178 }
179
180 //
181 // Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
182 //
183 InCompleteCheckSum32 = CalculateSum32 (
184 (UINT32 *) MicrocodeEntryPoint,
185 TotalSize
186 );
187 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;
188 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;
189 InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;
190
191 if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
192 //
193 // It is the microcode header. It is not the padding data between microcode patches
194 // because the padding data should not include 0x00000001 and it should be the repeated
195 // byte format (like 0xXYXYXYXY....).
196 //
197 if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&
198 MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
199 (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
200 ) {
201 //
202 // Calculate CheckSum Part1.
203 //
204 CheckSum32 = InCompleteCheckSum32;
205 CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;
206 CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;
207 CheckSum32 += MicrocodeEntryPoint->Checksum;
208 if (CheckSum32 == 0) {
209 CorrectMicrocode = TRUE;
210 }
211 } else if ((MicrocodeEntryPoint->DataSize != 0) &&
212 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
213 ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +
214 sizeof (CPU_MICROCODE_HEADER));
215 if (ExtendedTableLength != 0) {
216 //
217 // Extended Table exist, check if the CPU in support list
218 //
219 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
220 + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));
221 //
222 // Calculate Extended Checksum
223 //
224 if ((ExtendedTableLength % 4) == 0) {
225 //
226 // Calculate CheckSum Part2.
227 //
228 CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);
229 if (CheckSum32 == 0) {
230 //
231 // Checksum correct
232 //
233 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
234 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
235 for (Index = 0; Index < ExtendedTableCount; Index ++) {
236 //
237 // Calculate CheckSum Part3.
238 //
239 CheckSum32 = InCompleteCheckSum32;
240 CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;
241 CheckSum32 += ExtendedTable->ProcessorFlag;
242 CheckSum32 += ExtendedTable->Checksum;
243 if (CheckSum32 == 0) {
244 //
245 // Verify Header
246 //
247 if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&
248 (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
249 //
250 // Find one
251 //
252 CorrectMicrocode = TRUE;
253 break;
254 }
255 }
256 ExtendedTable ++;
257 }
258 }
259 }
260 }
261 }
262 } else {
263 //
264 // It is the padding data between the microcode patches for microcode patches alignment.
265 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
266 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
267 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
268 // find the next possible microcode patch header.
269 //
270 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
271 continue;
272 }
273 //
274 // Get the next patch.
275 //
276 if (MicrocodeEntryPoint->DataSize == 0) {
277 TotalSize = 2048;
278 } else {
279 TotalSize = MicrocodeEntryPoint->TotalSize;
280 }
281
282 if (CorrectMicrocode) {
283 LatestRevision = MicrocodeEntryPoint->UpdateRevision;
284 MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));
285 }
286
287 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
288 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
289
290 Done:
291 if (LatestRevision != 0) {
292 //
293 // Save the detected microcode patch entry address (including the
294 // microcode patch header) for each processor.
295 // It will be used when building the microcode patch cache HOB.
296 //
297 CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr =
298 (UINTN) MicrocodeData - sizeof (CPU_MICROCODE_HEADER);
299 }
300
301 if (LatestRevision > CurrentRevision) {
302 //
303 // BIOS only authenticate updates that contain a numerically larger revision
304 // than the currently loaded revision, where Current Signature < New Update
305 // Revision. A processor with no loaded update is considered to have a
306 // revision equal to zero.
307 //
308 ASSERT (MicrocodeData != NULL);
309 AsmWriteMsr64 (
310 MSR_IA32_BIOS_UPDT_TRIG,
311 (UINT64) (UINTN) MicrocodeData
312 );
313 //
314 // Get and check new microcode signature
315 //
316 CurrentRevision = GetCurrentMicrocodeSignature ();
317 if (CurrentRevision != LatestRevision) {
318 AcquireSpinLock(&CpuMpData->MpLock);
319 DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \
320 loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));
321 ReleaseSpinLock(&CpuMpData->MpLock);
322 }
323 }
324 }
325
326 /**
327 Determine if a microcode patch will be loaded into memory.
328
329 @param[in] CpuMpData The pointer to CPU MP Data structure.
330 @param[in] ProcessorSignature The processor signature field value
331 supported by a microcode patch.
332 @param[in] ProcessorFlags The prcessor flags field value supported by
333 a microcode patch.
334
335 @retval TRUE The specified microcode patch will be loaded.
336 @retval FALSE The specified microcode patch will not be loaded.
337 **/
338 BOOLEAN
339 IsMicrocodePatchNeedLoad (
340 IN CPU_MP_DATA *CpuMpData,
341 IN UINT32 ProcessorSignature,
342 IN UINT32 ProcessorFlags
343 )
344 {
345 UINTN Index;
346 CPU_AP_DATA *CpuData;
347
348 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
349 CpuData = &CpuMpData->CpuData[Index];
350 if ((ProcessorSignature == CpuData->ProcessorSignature) &&
351 (ProcessorFlags & (1 << CpuData->PlatformId)) != 0) {
352 return TRUE;
353 }
354 }
355
356 return FALSE;
357 }
358
359 /**
360 Actual worker function that loads the required microcode patches into memory.
361
362 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
363 @param[in] Patches The pointer to an array of information on
364 the microcode patches that will be loaded
365 into memory.
366 @param[in] PatchCount The number of microcode patches that will
367 be loaded into memory.
368 @param[in] TotalLoadSize The total size of all the microcode patches
369 to be loaded.
370 **/
371 VOID
372 LoadMicrocodePatchWorker (
373 IN OUT CPU_MP_DATA *CpuMpData,
374 IN MICROCODE_PATCH_INFO *Patches,
375 IN UINTN PatchCount,
376 IN UINTN TotalLoadSize
377 )
378 {
379 UINTN Index;
380 VOID *MicrocodePatchInRam;
381 UINT8 *Walker;
382
383 ASSERT ((Patches != NULL) && (PatchCount != 0));
384
385 MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));
386 if (MicrocodePatchInRam == NULL) {
387 return;
388 }
389
390 //
391 // Load all the required microcode patches into memory
392 //
393 for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {
394 CopyMem (
395 Walker,
396 (VOID *) Patches[Index].Address,
397 Patches[Index].Size
398 );
399
400 Walker += Patches[Index].Size;
401 }
402
403 //
404 // Update the microcode patch related fields in CpuMpData
405 //
406 CpuMpData->MicrocodePatchAddress = (UINTN) MicrocodePatchInRam;
407 CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;
408
409 DEBUG ((
410 DEBUG_INFO,
411 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
412 __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize
413 ));
414
415 return;
416 }
417
418 /**
419 Load the required microcode patches data into memory.
420
421 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
422 **/
423 VOID
424 LoadMicrocodePatch (
425 IN OUT CPU_MP_DATA *CpuMpData
426 )
427 {
428 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
429 UINTN MicrocodeEnd;
430 UINTN DataSize;
431 UINTN TotalSize;
432 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
433 UINT32 ExtendedTableCount;
434 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
435 MICROCODE_PATCH_INFO *PatchInfoBuffer;
436 UINTN MaxPatchNumber;
437 UINTN PatchCount;
438 UINTN TotalLoadSize;
439 UINTN Index;
440 BOOLEAN NeedLoad;
441
442 //
443 // Initialize the microcode patch related fields in CpuMpData as the values
444 // specified by the PCD pair. If the microcode patches are loaded into memory,
445 // these fields will be updated.
446 //
447 CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
448 CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
449
450 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
451 MicrocodeEnd = (UINTN) MicrocodeEntryPoint +
452 (UINTN) CpuMpData->MicrocodePatchRegionSize;
453 if ((MicrocodeEntryPoint == NULL) || ((UINTN) MicrocodeEntryPoint == MicrocodeEnd)) {
454 //
455 // There is no microcode patches
456 //
457 return;
458 }
459
460 PatchCount = 0;
461 MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM;
462 TotalLoadSize = 0;
463 PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));
464 if (PatchInfoBuffer == NULL) {
465 return;
466 }
467
468 //
469 // Process the header of each microcode patch within the region.
470 // The purpose is to decide which microcode patch(es) will be loaded into memory.
471 //
472 do {
473 if (MicrocodeEntryPoint->HeaderVersion != 0x1) {
474 //
475 // Padding data between the microcode patches, skip 1KB to check next entry.
476 //
477 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
478 continue;
479 }
480
481 DataSize = MicrocodeEntryPoint->DataSize;
482 TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;
483 if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||
484 ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
485 (DataSize & 0x3) != 0 ||
486 (TotalSize & (SIZE_1KB - 1)) != 0 ||
487 TotalSize < DataSize
488 ) {
489 //
490 // Not a valid microcode header, skip 1KB to check next entry.
491 //
492 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
493 continue;
494 }
495
496 //
497 // Check the 'ProcessorSignature' and 'ProcessorFlags' of the microcode
498 // patch header with the CPUID and PlatformID of the processors within
499 // system to decide if it will be copied into memory
500 //
501 NeedLoad = IsMicrocodePatchNeedLoad (
502 CpuMpData,
503 MicrocodeEntryPoint->ProcessorSignature.Uint32,
504 MicrocodeEntryPoint->ProcessorFlags
505 );
506
507 //
508 // If the Extended Signature Table exists, check if the processor is in the
509 // support list
510 //
511 if ((!NeedLoad) && (DataSize != 0) &&
512 (TotalSize - DataSize > sizeof (CPU_MICROCODE_HEADER) +
513 sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))) {
514 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
515 + DataSize + sizeof (CPU_MICROCODE_HEADER));
516 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
517 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
518
519 for (Index = 0; Index < ExtendedTableCount; Index ++) {
520 //
521 // Avoid access content beyond MicrocodeEnd
522 //
523 if ((UINTN) ExtendedTable > MicrocodeEnd - sizeof (CPU_MICROCODE_EXTENDED_TABLE)) {
524 break;
525 }
526
527 //
528 // Check the 'ProcessorSignature' and 'ProcessorFlag' of the Extended
529 // Signature Table entry with the CPUID and PlatformID of the processors
530 // within system to decide if it will be copied into memory
531 //
532 NeedLoad = IsMicrocodePatchNeedLoad (
533 CpuMpData,
534 ExtendedTable->ProcessorSignature.Uint32,
535 ExtendedTable->ProcessorFlag
536 );
537 if (NeedLoad) {
538 break;
539 }
540 ExtendedTable ++;
541 }
542 }
543
544 if (NeedLoad) {
545 PatchCount++;
546 if (PatchCount > MaxPatchNumber) {
547 //
548 // Current 'PatchInfoBuffer' cannot hold the information, double the size
549 // and allocate a new buffer.
550 //
551 if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {
552 //
553 // Overflow check for MaxPatchNumber
554 //
555 goto OnExit;
556 }
557
558 PatchInfoBuffer = ReallocatePool (
559 MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
560 2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
561 PatchInfoBuffer
562 );
563 if (PatchInfoBuffer == NULL) {
564 goto OnExit;
565 }
566 MaxPatchNumber = MaxPatchNumber * 2;
567 }
568
569 //
570 // Store the information of this microcode patch
571 //
572 PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;
573 PatchInfoBuffer[PatchCount - 1].Size = TotalSize;
574 TotalLoadSize += TotalSize;
575 }
576
577 //
578 // Process the next microcode patch
579 //
580 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
581 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
582
583 if (PatchCount != 0) {
584 DEBUG ((
585 DEBUG_INFO,
586 "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",
587 __FUNCTION__, PatchCount, TotalLoadSize
588 ));
589
590 LoadMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);
591 }
592
593 OnExit:
594 if (PatchInfoBuffer != NULL) {
595 FreePool (PatchInfoBuffer);
596 }
597 return;
598 }