]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/Microcode.c
4162b4a8dcfe5d22cd2eed08b79fe420606abdb0
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / Microcode.c
1 /** @file
2 Implementation of loading microcode on processors.
3
4 Copyright (c) 2015 - 2019, 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 UINT32 CurrentRevision;
89 UINT32 LatestRevision;
90 UINTN TotalSize;
91 UINT32 CheckSum32;
92 UINT32 InCompleteCheckSum32;
93 BOOLEAN CorrectMicrocode;
94 VOID *MicrocodeData;
95 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
96 UINT32 ProcessorFlags;
97 UINT32 ThreadId;
98 BOOLEAN IsBspCallIn;
99
100 //
101 // set ProcessorFlags to suppress incorrect compiler/analyzer warnings
102 //
103 ProcessorFlags = 0;
104
105 if (CpuMpData->MicrocodePatchRegionSize == 0) {
106 //
107 // There is no microcode patches
108 //
109 return;
110 }
111
112 CurrentRevision = GetCurrentMicrocodeSignature ();
113 IsBspCallIn = (ProcessorNumber == (UINTN)CpuMpData->BspNumber) ? TRUE : FALSE;
114 if (CurrentRevision != 0 && !IsBspCallIn) {
115 //
116 // Skip loading microcode if it has been loaded successfully
117 //
118 return;
119 }
120
121 GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
122 if (ThreadId != 0) {
123 //
124 // Skip loading microcode if it is not the first thread in one core.
125 //
126 return;
127 }
128
129 ExtendedTableLength = 0;
130 //
131 // Here data of CPUID leafs have not been collected into context buffer, so
132 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
133 //
134 AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);
135
136 //
137 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
138 //
139 PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
140 PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;
141
142 //
143 // Check whether AP has same processor with BSP.
144 // If yes, direct use microcode info saved by BSP.
145 //
146 if (!IsBspCallIn) {
147 if ((CpuMpData->ProcessorSignature == Eax.Uint32) &&
148 (CpuMpData->ProcessorFlags & (1 << PlatformId)) != 0) {
149 MicrocodeData = (VOID *)(UINTN) CpuMpData->MicrocodeDataAddress;
150 LatestRevision = CpuMpData->MicrocodeRevision;
151 goto Done;
152 }
153 }
154
155 LatestRevision = 0;
156 MicrocodeData = NULL;
157 MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);
158 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
159
160 do {
161 //
162 // Check if the microcode is for the Cpu and the version is newer
163 // and the update can be processed on the platform
164 //
165 CorrectMicrocode = FALSE;
166
167 if (MicrocodeEntryPoint->DataSize == 0) {
168 TotalSize = sizeof (CPU_MICROCODE_HEADER) + 2000;
169 } else {
170 TotalSize = sizeof (CPU_MICROCODE_HEADER) + MicrocodeEntryPoint->DataSize;
171 }
172
173 ///
174 /// 0x0 MicrocodeBegin MicrocodeEntry MicrocodeEnd 0xffffffff
175 /// |--------------|---------------|---------------|---------------|
176 /// valid TotalSize
177 /// TotalSize is only valid between 0 and (MicrocodeEnd - MicrocodeEntry).
178 /// And it should be aligned with 4 bytes.
179 /// If the TotalSize is invalid, skip 1KB to check next entry.
180 ///
181 if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||
182 ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
183 (TotalSize & 0x3) != 0
184 ) {
185 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
186 continue;
187 }
188
189 //
190 // Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
191 //
192 InCompleteCheckSum32 = CalculateSum32 (
193 (UINT32 *) MicrocodeEntryPoint,
194 TotalSize
195 );
196 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;
197 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;
198 InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;
199
200 if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
201 //
202 // It is the microcode header. It is not the padding data between microcode patches
203 // because the padding data should not include 0x00000001 and it should be the repeated
204 // byte format (like 0xXYXYXYXY....).
205 //
206 if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&
207 MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
208 (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
209 ) {
210 //
211 // Calculate CheckSum Part1.
212 //
213 CheckSum32 = InCompleteCheckSum32;
214 CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;
215 CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;
216 CheckSum32 += MicrocodeEntryPoint->Checksum;
217 if (CheckSum32 == 0) {
218 CorrectMicrocode = TRUE;
219 ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags;
220 }
221 } else if ((MicrocodeEntryPoint->DataSize != 0) &&
222 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
223 ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +
224 sizeof (CPU_MICROCODE_HEADER));
225 if (ExtendedTableLength != 0) {
226 //
227 // Extended Table exist, check if the CPU in support list
228 //
229 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
230 + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));
231 //
232 // Calculate Extended Checksum
233 //
234 if ((ExtendedTableLength % 4) == 0) {
235 //
236 // Calculate CheckSum Part2.
237 //
238 CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);
239 if (CheckSum32 == 0) {
240 //
241 // Checksum correct
242 //
243 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
244 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
245 for (Index = 0; Index < ExtendedTableCount; Index ++) {
246 //
247 // Calculate CheckSum Part3.
248 //
249 CheckSum32 = InCompleteCheckSum32;
250 CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;
251 CheckSum32 += ExtendedTable->ProcessorFlag;
252 CheckSum32 += ExtendedTable->Checksum;
253 if (CheckSum32 == 0) {
254 //
255 // Verify Header
256 //
257 if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&
258 (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
259 //
260 // Find one
261 //
262 CorrectMicrocode = TRUE;
263 ProcessorFlags = ExtendedTable->ProcessorFlag;
264 break;
265 }
266 }
267 ExtendedTable ++;
268 }
269 }
270 }
271 }
272 }
273 } else {
274 //
275 // It is the padding data between the microcode patches for microcode patches alignment.
276 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
277 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
278 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
279 // find the next possible microcode patch header.
280 //
281 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
282 continue;
283 }
284 //
285 // Get the next patch.
286 //
287 if (MicrocodeEntryPoint->DataSize == 0) {
288 TotalSize = 2048;
289 } else {
290 TotalSize = MicrocodeEntryPoint->TotalSize;
291 }
292
293 if (CorrectMicrocode) {
294 LatestRevision = MicrocodeEntryPoint->UpdateRevision;
295 MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));
296 }
297
298 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
299 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
300
301 Done:
302 if (LatestRevision != 0) {
303 //
304 // Save the detected microcode patch entry address (including the
305 // microcode patch header) for each processor.
306 // It will be used when building the microcode patch cache HOB.
307 //
308 CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr =
309 (UINTN) MicrocodeData - sizeof (CPU_MICROCODE_HEADER);
310 }
311
312 if (LatestRevision > CurrentRevision) {
313 //
314 // BIOS only authenticate updates that contain a numerically larger revision
315 // than the currently loaded revision, where Current Signature < New Update
316 // Revision. A processor with no loaded update is considered to have a
317 // revision equal to zero.
318 //
319 ASSERT (MicrocodeData != NULL);
320 AsmWriteMsr64 (
321 MSR_IA32_BIOS_UPDT_TRIG,
322 (UINT64) (UINTN) MicrocodeData
323 );
324 //
325 // Get and check new microcode signature
326 //
327 CurrentRevision = GetCurrentMicrocodeSignature ();
328 if (CurrentRevision != LatestRevision) {
329 AcquireSpinLock(&CpuMpData->MpLock);
330 DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \
331 loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));
332 ReleaseSpinLock(&CpuMpData->MpLock);
333 }
334 }
335
336 if (IsBspCallIn && (LatestRevision != 0)) {
337 //
338 // Save BSP processor info and microcode info for later AP use.
339 //
340 CpuMpData->ProcessorSignature = Eax.Uint32;
341 CpuMpData->ProcessorFlags = ProcessorFlags;
342 CpuMpData->MicrocodeDataAddress = (UINTN) MicrocodeData;
343 CpuMpData->MicrocodeRevision = LatestRevision;
344 DEBUG ((DEBUG_INFO, "BSP Microcode:: signature [0x%08x], ProcessorFlags [0x%08x], \
345 MicroData [0x%08x], Revision [0x%08x]\n", Eax.Uint32, ProcessorFlags, (UINTN) MicrocodeData, LatestRevision));
346 }
347 }
348
349 /**
350 Determine if a microcode patch will be loaded into memory.
351
352 @param[in] CpuMpData The pointer to CPU MP Data structure.
353 @param[in] ProcessorSignature The processor signature field value
354 supported by a microcode patch.
355 @param[in] ProcessorFlags The prcessor flags field value supported by
356 a microcode patch.
357
358 @retval TRUE The specified microcode patch will be loaded.
359 @retval FALSE The specified microcode patch will not be loaded.
360 **/
361 BOOLEAN
362 IsMicrocodePatchNeedLoad (
363 IN CPU_MP_DATA *CpuMpData,
364 IN UINT32 ProcessorSignature,
365 IN UINT32 ProcessorFlags
366 )
367 {
368 UINTN Index;
369 CPU_AP_DATA *CpuData;
370
371 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
372 CpuData = &CpuMpData->CpuData[Index];
373 if ((ProcessorSignature == CpuData->ProcessorSignature) &&
374 (ProcessorFlags & (1 << CpuData->PlatformId)) != 0) {
375 return TRUE;
376 }
377 }
378
379 return FALSE;
380 }
381
382 /**
383 Actual worker function that loads the required microcode patches into memory.
384
385 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
386 @param[in] Patches The pointer to an array of information on
387 the microcode patches that will be loaded
388 into memory.
389 @param[in] PatchCount The number of microcode patches that will
390 be loaded into memory.
391 @param[in] TotalLoadSize The total size of all the microcode patches
392 to be loaded.
393 **/
394 VOID
395 LoadMicrocodePatchWorker (
396 IN OUT CPU_MP_DATA *CpuMpData,
397 IN MICROCODE_PATCH_INFO *Patches,
398 IN UINTN PatchCount,
399 IN UINTN TotalLoadSize
400 )
401 {
402 UINTN Index;
403 VOID *MicrocodePatchInRam;
404 UINT8 *Walker;
405
406 ASSERT ((Patches != NULL) && (PatchCount != 0));
407
408 MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));
409 if (MicrocodePatchInRam == NULL) {
410 return;
411 }
412
413 //
414 // Load all the required microcode patches into memory
415 //
416 for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {
417 CopyMem (
418 Walker,
419 (VOID *) Patches[Index].Address,
420 Patches[Index].Size
421 );
422
423 //
424 // Zero-fill the padding area
425 // Please note that AlignedSize will be no less than Size
426 //
427 ZeroMem (
428 Walker + Patches[Index].Size,
429 Patches[Index].AlignedSize - Patches[Index].Size
430 );
431
432 Walker += Patches[Index].AlignedSize;
433 }
434
435 //
436 // Update the microcode patch related fields in CpuMpData
437 //
438 CpuMpData->MicrocodePatchAddress = (UINTN) MicrocodePatchInRam;
439 CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;
440
441 DEBUG ((
442 DEBUG_INFO,
443 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
444 __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize
445 ));
446
447 return;
448 }
449
450 /**
451 Load the required microcode patches data into memory.
452
453 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
454 **/
455 VOID
456 LoadMicrocodePatch (
457 IN OUT CPU_MP_DATA *CpuMpData
458 )
459 {
460 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
461 UINTN MicrocodeEnd;
462 UINTN DataSize;
463 UINTN TotalSize;
464 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
465 UINT32 ExtendedTableCount;
466 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
467 MICROCODE_PATCH_INFO *PatchInfoBuffer;
468 UINTN MaxPatchNumber;
469 UINTN PatchCount;
470 UINTN TotalLoadSize;
471 UINTN Index;
472 BOOLEAN NeedLoad;
473
474 //
475 // Initialize the microcode patch related fields in CpuMpData as the values
476 // specified by the PCD pair. If the microcode patches are loaded into memory,
477 // these fields will be updated.
478 //
479 CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
480 CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
481
482 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
483 MicrocodeEnd = (UINTN) MicrocodeEntryPoint +
484 (UINTN) CpuMpData->MicrocodePatchRegionSize;
485 if ((MicrocodeEntryPoint == NULL) || ((UINTN) MicrocodeEntryPoint == MicrocodeEnd)) {
486 //
487 // There is no microcode patches
488 //
489 return;
490 }
491
492 PatchCount = 0;
493 MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM;
494 TotalLoadSize = 0;
495 PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));
496 if (PatchInfoBuffer == NULL) {
497 return;
498 }
499
500 //
501 // Process the header of each microcode patch within the region.
502 // The purpose is to decide which microcode patch(es) will be loaded into memory.
503 //
504 do {
505 if (MicrocodeEntryPoint->HeaderVersion != 0x1) {
506 //
507 // Padding data between the microcode patches, skip 1KB to check next entry.
508 //
509 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
510 continue;
511 }
512
513 DataSize = MicrocodeEntryPoint->DataSize;
514 TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;
515 if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||
516 ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
517 (DataSize & 0x3) != 0 ||
518 (TotalSize & (SIZE_1KB - 1)) != 0 ||
519 TotalSize < DataSize
520 ) {
521 //
522 // Not a valid microcode header, skip 1KB to check next entry.
523 //
524 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
525 continue;
526 }
527
528 //
529 // Check the 'ProcessorSignature' and 'ProcessorFlags' of the microcode
530 // patch header with the CPUID and PlatformID of the processors within
531 // system to decide if it will be copied into memory
532 //
533 NeedLoad = IsMicrocodePatchNeedLoad (
534 CpuMpData,
535 MicrocodeEntryPoint->ProcessorSignature.Uint32,
536 MicrocodeEntryPoint->ProcessorFlags
537 );
538
539 //
540 // If the Extended Signature Table exists, check if the processor is in the
541 // support list
542 //
543 if ((!NeedLoad) && (DataSize != 0) &&
544 (TotalSize - DataSize > sizeof (CPU_MICROCODE_HEADER) +
545 sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))) {
546 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
547 + DataSize + sizeof (CPU_MICROCODE_HEADER));
548 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
549 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
550
551 for (Index = 0; Index < ExtendedTableCount; Index ++) {
552 //
553 // Avoid access content beyond MicrocodeEnd
554 //
555 if ((UINTN) ExtendedTable > MicrocodeEnd - sizeof (CPU_MICROCODE_EXTENDED_TABLE)) {
556 break;
557 }
558
559 //
560 // Check the 'ProcessorSignature' and 'ProcessorFlag' of the Extended
561 // Signature Table entry with the CPUID and PlatformID of the processors
562 // within system to decide if it will be copied into memory
563 //
564 NeedLoad = IsMicrocodePatchNeedLoad (
565 CpuMpData,
566 ExtendedTable->ProcessorSignature.Uint32,
567 ExtendedTable->ProcessorFlag
568 );
569 if (NeedLoad) {
570 break;
571 }
572 ExtendedTable ++;
573 }
574 }
575
576 if (NeedLoad) {
577 PatchCount++;
578 if (PatchCount > MaxPatchNumber) {
579 //
580 // Current 'PatchInfoBuffer' cannot hold the information, double the size
581 // and allocate a new buffer.
582 //
583 if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {
584 //
585 // Overflow check for MaxPatchNumber
586 //
587 goto OnExit;
588 }
589
590 PatchInfoBuffer = ReallocatePool (
591 MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
592 2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
593 PatchInfoBuffer
594 );
595 if (PatchInfoBuffer == NULL) {
596 goto OnExit;
597 }
598 MaxPatchNumber = MaxPatchNumber * 2;
599 }
600
601 //
602 // Store the information of this microcode patch
603 //
604 if (TotalSize > ALIGN_VALUE (TotalSize, SIZE_1KB) ||
605 ALIGN_VALUE (TotalSize, SIZE_1KB) > MAX_UINTN - TotalLoadSize) {
606 goto OnExit;
607 }
608 PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;
609 PatchInfoBuffer[PatchCount - 1].Size = TotalSize;
610 PatchInfoBuffer[PatchCount - 1].AlignedSize = ALIGN_VALUE (TotalSize, SIZE_1KB);
611 TotalLoadSize += PatchInfoBuffer[PatchCount - 1].AlignedSize;
612 }
613
614 //
615 // Process the next microcode patch
616 //
617 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
618 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
619
620 if (PatchCount != 0) {
621 DEBUG ((
622 DEBUG_INFO,
623 "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",
624 __FUNCTION__, PatchCount, TotalLoadSize
625 ));
626
627 LoadMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);
628 }
629
630 OnExit:
631 if (PatchInfoBuffer != NULL) {
632 FreePool (PatchInfoBuffer);
633 }
634 return;
635 }