]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/Microcode.c
67e214d463d38b030cb4d41960d403126c818a87
[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 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
97 UINT32 ThreadId;
98 BOOLEAN IsBspCallIn;
99
100 if (CpuMpData->MicrocodePatchRegionSize == 0) {
101 //
102 // There is no microcode patches
103 //
104 return;
105 }
106
107 CurrentRevision = GetCurrentMicrocodeSignature ();
108 IsBspCallIn = (ProcessorNumber == (UINTN)CpuMpData->BspNumber) ? TRUE : FALSE;
109
110 GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
111 if (ThreadId != 0) {
112 //
113 // Skip loading microcode if it is not the first thread in one core.
114 //
115 return;
116 }
117
118 ExtendedTableLength = 0;
119 //
120 // Here data of CPUID leafs have not been collected into context buffer, so
121 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
122 //
123 AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);
124
125 //
126 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
127 //
128 PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
129 PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;
130
131
132 //
133 // Check whether AP has same processor with BSP.
134 // If yes, direct use microcode info saved by BSP.
135 //
136 if (!IsBspCallIn) {
137 //
138 // Get the CPU data for BSP
139 //
140 CpuData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);
141 if ((CpuData->ProcessorSignature == Eax.Uint32) &&
142 (CpuData->PlatformId == PlatformId) &&
143 (CpuData->MicrocodeEntryAddr != 0)) {
144 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN) CpuData->MicrocodeEntryAddr;
145 MicrocodeData = (VOID *) (MicrocodeEntryPoint + 1);
146 LatestRevision = MicrocodeEntryPoint->UpdateRevision;
147 goto Done;
148 }
149 }
150
151 LatestRevision = 0;
152 MicrocodeData = NULL;
153 MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);
154 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
155
156 do {
157 //
158 // Check if the microcode is for the Cpu and the version is newer
159 // and the update can be processed on the platform
160 //
161 CorrectMicrocode = FALSE;
162
163 if (MicrocodeEntryPoint->DataSize == 0) {
164 TotalSize = sizeof (CPU_MICROCODE_HEADER) + 2000;
165 } else {
166 TotalSize = sizeof (CPU_MICROCODE_HEADER) + MicrocodeEntryPoint->DataSize;
167 }
168
169 ///
170 /// 0x0 MicrocodeBegin MicrocodeEntry MicrocodeEnd 0xffffffff
171 /// |--------------|---------------|---------------|---------------|
172 /// valid TotalSize
173 /// TotalSize is only valid between 0 and (MicrocodeEnd - MicrocodeEntry).
174 /// And it should be aligned with 4 bytes.
175 /// If the TotalSize is invalid, skip 1KB to check next entry.
176 ///
177 if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||
178 ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
179 (TotalSize & 0x3) != 0
180 ) {
181 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
182 continue;
183 }
184
185 //
186 // Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
187 //
188 InCompleteCheckSum32 = CalculateSum32 (
189 (UINT32 *) MicrocodeEntryPoint,
190 TotalSize
191 );
192 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;
193 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;
194 InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;
195
196 if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
197 //
198 // It is the microcode header. It is not the padding data between microcode patches
199 // because the padding data should not include 0x00000001 and it should be the repeated
200 // byte format (like 0xXYXYXYXY....).
201 //
202 if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&
203 MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
204 (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
205 ) {
206 //
207 // Calculate CheckSum Part1.
208 //
209 CheckSum32 = InCompleteCheckSum32;
210 CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;
211 CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;
212 CheckSum32 += MicrocodeEntryPoint->Checksum;
213 if (CheckSum32 == 0) {
214 CorrectMicrocode = TRUE;
215 }
216 } else if ((MicrocodeEntryPoint->DataSize != 0) &&
217 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
218 ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +
219 sizeof (CPU_MICROCODE_HEADER));
220 if (ExtendedTableLength != 0) {
221 //
222 // Extended Table exist, check if the CPU in support list
223 //
224 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
225 + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));
226 //
227 // Calculate Extended Checksum
228 //
229 if ((ExtendedTableLength % 4) == 0) {
230 //
231 // Calculate CheckSum Part2.
232 //
233 CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);
234 if (CheckSum32 == 0) {
235 //
236 // Checksum correct
237 //
238 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
239 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
240 for (Index = 0; Index < ExtendedTableCount; Index ++) {
241 //
242 // Calculate CheckSum Part3.
243 //
244 CheckSum32 = InCompleteCheckSum32;
245 CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;
246 CheckSum32 += ExtendedTable->ProcessorFlag;
247 CheckSum32 += ExtendedTable->Checksum;
248 if (CheckSum32 == 0) {
249 //
250 // Verify Header
251 //
252 if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&
253 (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
254 //
255 // Find one
256 //
257 CorrectMicrocode = TRUE;
258 break;
259 }
260 }
261 ExtendedTable ++;
262 }
263 }
264 }
265 }
266 }
267 } else {
268 //
269 // It is the padding data between the microcode patches for microcode patches alignment.
270 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
271 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
272 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
273 // find the next possible microcode patch header.
274 //
275 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
276 continue;
277 }
278 //
279 // Get the next patch.
280 //
281 if (MicrocodeEntryPoint->DataSize == 0) {
282 TotalSize = 2048;
283 } else {
284 TotalSize = MicrocodeEntryPoint->TotalSize;
285 }
286
287 if (CorrectMicrocode) {
288 LatestRevision = MicrocodeEntryPoint->UpdateRevision;
289 MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));
290 }
291
292 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
293 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
294
295 Done:
296 if (LatestRevision != 0) {
297 //
298 // Save the detected microcode patch entry address (including the
299 // microcode patch header) for each processor.
300 // It will be used when building the microcode patch cache HOB.
301 //
302 CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr =
303 (UINTN) MicrocodeData - sizeof (CPU_MICROCODE_HEADER);
304 }
305
306 if (LatestRevision > CurrentRevision) {
307 //
308 // BIOS only authenticate updates that contain a numerically larger revision
309 // than the currently loaded revision, where Current Signature < New Update
310 // Revision. A processor with no loaded update is considered to have a
311 // revision equal to zero.
312 //
313 ASSERT (MicrocodeData != NULL);
314 AsmWriteMsr64 (
315 MSR_IA32_BIOS_UPDT_TRIG,
316 (UINT64) (UINTN) MicrocodeData
317 );
318 //
319 // Get and check new microcode signature
320 //
321 CurrentRevision = GetCurrentMicrocodeSignature ();
322 if (CurrentRevision != LatestRevision) {
323 AcquireSpinLock(&CpuMpData->MpLock);
324 DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \
325 loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));
326 ReleaseSpinLock(&CpuMpData->MpLock);
327 }
328 }
329 }
330
331 /**
332 Determine if a microcode patch matchs the specific processor signature and flag.
333
334 @param[in] CpuMpData The pointer to CPU MP Data structure.
335 @param[in] ProcessorSignature The processor signature field value
336 supported by a microcode patch.
337 @param[in] ProcessorFlags The prcessor flags field value supported by
338 a microcode patch.
339
340 @retval TRUE The specified microcode patch will be loaded.
341 @retval FALSE The specified microcode patch will not be loaded.
342 **/
343 BOOLEAN
344 IsProcessorMatchedMicrocodePatch (
345 IN CPU_MP_DATA *CpuMpData,
346 IN UINT32 ProcessorSignature,
347 IN UINT32 ProcessorFlags
348 )
349 {
350 UINTN Index;
351 CPU_AP_DATA *CpuData;
352
353 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
354 CpuData = &CpuMpData->CpuData[Index];
355 if ((ProcessorSignature == CpuData->ProcessorSignature) &&
356 (ProcessorFlags & (1 << CpuData->PlatformId)) != 0) {
357 return TRUE;
358 }
359 }
360
361 return FALSE;
362 }
363
364 /**
365 Check the 'ProcessorSignature' and 'ProcessorFlags' of the microcode
366 patch header with the CPUID and PlatformID of the processors within
367 system to decide if it will be copied into memory.
368
369 @param[in] CpuMpData The pointer to CPU MP Data structure.
370 @param[in] MicrocodeEntryPoint The pointer to the microcode patch header.
371
372 @retval TRUE The specified microcode patch need to be loaded.
373 @retval FALSE The specified microcode patch dosen't need to be loaded.
374 **/
375 BOOLEAN
376 IsMicrocodePatchNeedLoad (
377 IN CPU_MP_DATA *CpuMpData,
378 CPU_MICROCODE_HEADER *MicrocodeEntryPoint
379 )
380 {
381 BOOLEAN NeedLoad;
382 UINTN DataSize;
383 UINTN TotalSize;
384 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
385 UINT32 ExtendedTableCount;
386 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
387 UINTN Index;
388
389 //
390 // Check the 'ProcessorSignature' and 'ProcessorFlags' in microcode patch header.
391 //
392 NeedLoad = IsProcessorMatchedMicrocodePatch (
393 CpuMpData,
394 MicrocodeEntryPoint->ProcessorSignature.Uint32,
395 MicrocodeEntryPoint->ProcessorFlags
396 );
397
398 //
399 // If the Extended Signature Table exists, check if the processor is in the
400 // support list
401 //
402 DataSize = MicrocodeEntryPoint->DataSize;
403 TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;
404 if ((!NeedLoad) && (DataSize != 0) &&
405 (TotalSize - DataSize > sizeof (CPU_MICROCODE_HEADER) +
406 sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))) {
407 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
408 + DataSize + sizeof (CPU_MICROCODE_HEADER));
409 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
410 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
411
412 for (Index = 0; Index < ExtendedTableCount; Index ++) {
413 //
414 // Check the 'ProcessorSignature' and 'ProcessorFlag' of the Extended
415 // Signature Table entry with the CPUID and PlatformID of the processors
416 // within system to decide if it will be copied into memory
417 //
418 NeedLoad = IsProcessorMatchedMicrocodePatch (
419 CpuMpData,
420 ExtendedTable->ProcessorSignature.Uint32,
421 ExtendedTable->ProcessorFlag
422 );
423 if (NeedLoad) {
424 break;
425 }
426 ExtendedTable ++;
427 }
428 }
429
430 return NeedLoad;
431 }
432
433
434 /**
435 Actual worker function that shadows the required microcode patches into memory.
436
437 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
438 @param[in] Patches The pointer to an array of information on
439 the microcode patches that will be loaded
440 into memory.
441 @param[in] PatchCount The number of microcode patches that will
442 be loaded into memory.
443 @param[in] TotalLoadSize The total size of all the microcode patches
444 to be loaded.
445 **/
446 VOID
447 ShadowMicrocodePatchWorker (
448 IN OUT CPU_MP_DATA *CpuMpData,
449 IN MICROCODE_PATCH_INFO *Patches,
450 IN UINTN PatchCount,
451 IN UINTN TotalLoadSize
452 )
453 {
454 UINTN Index;
455 VOID *MicrocodePatchInRam;
456 UINT8 *Walker;
457
458 ASSERT ((Patches != NULL) && (PatchCount != 0));
459
460 MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));
461 if (MicrocodePatchInRam == NULL) {
462 return;
463 }
464
465 //
466 // Load all the required microcode patches into memory
467 //
468 for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {
469 CopyMem (
470 Walker,
471 (VOID *) Patches[Index].Address,
472 Patches[Index].Size
473 );
474 Walker += Patches[Index].Size;
475 }
476
477 //
478 // Update the microcode patch related fields in CpuMpData
479 //
480 CpuMpData->MicrocodePatchAddress = (UINTN) MicrocodePatchInRam;
481 CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;
482
483 DEBUG ((
484 DEBUG_INFO,
485 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
486 __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize
487 ));
488
489 return;
490 }
491
492 /**
493 Shadow the required microcode patches data into memory according to PCD
494 PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize.
495
496 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
497 **/
498 VOID
499 ShadowMicrocodePatchByPcd (
500 IN OUT CPU_MP_DATA *CpuMpData
501 )
502 {
503 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
504 UINTN MicrocodeEnd;
505 UINTN DataSize;
506 UINTN TotalSize;
507 MICROCODE_PATCH_INFO *PatchInfoBuffer;
508 UINTN MaxPatchNumber;
509 UINTN PatchCount;
510 UINTN TotalLoadSize;
511
512 //
513 // Initialize the microcode patch related fields in CpuMpData as the values
514 // specified by the PCD pair. If the microcode patches are loaded into memory,
515 // these fields will be updated.
516 //
517 CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
518 CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
519
520 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
521 MicrocodeEnd = (UINTN) MicrocodeEntryPoint +
522 (UINTN) CpuMpData->MicrocodePatchRegionSize;
523 if ((MicrocodeEntryPoint == NULL) || ((UINTN) MicrocodeEntryPoint == MicrocodeEnd)) {
524 //
525 // There is no microcode patches
526 //
527 return;
528 }
529
530 PatchCount = 0;
531 MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM;
532 TotalLoadSize = 0;
533 PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));
534 if (PatchInfoBuffer == NULL) {
535 return;
536 }
537
538 //
539 // Process the header of each microcode patch within the region.
540 // The purpose is to decide which microcode patch(es) will be loaded into memory.
541 //
542 do {
543 if (MicrocodeEntryPoint->HeaderVersion != 0x1) {
544 //
545 // Padding data between the microcode patches, skip 1KB to check next entry.
546 //
547 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
548 continue;
549 }
550
551 DataSize = MicrocodeEntryPoint->DataSize;
552 TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;
553 if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||
554 ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
555 (DataSize & 0x3) != 0 ||
556 (TotalSize & (SIZE_1KB - 1)) != 0 ||
557 TotalSize < DataSize
558 ) {
559 //
560 // Not a valid microcode header, skip 1KB to check next entry.
561 //
562 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
563 continue;
564 }
565
566 if (IsMicrocodePatchNeedLoad (CpuMpData, MicrocodeEntryPoint)) {
567 PatchCount++;
568 if (PatchCount > MaxPatchNumber) {
569 //
570 // Current 'PatchInfoBuffer' cannot hold the information, double the size
571 // and allocate a new buffer.
572 //
573 if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {
574 //
575 // Overflow check for MaxPatchNumber
576 //
577 goto OnExit;
578 }
579
580 PatchInfoBuffer = ReallocatePool (
581 MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
582 2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
583 PatchInfoBuffer
584 );
585 if (PatchInfoBuffer == NULL) {
586 goto OnExit;
587 }
588 MaxPatchNumber = MaxPatchNumber * 2;
589 }
590
591 //
592 // Store the information of this microcode patch
593 //
594 PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;
595 PatchInfoBuffer[PatchCount - 1].Size = TotalSize;
596 TotalLoadSize += TotalSize;
597 }
598
599 //
600 // Process the next microcode patch
601 //
602 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
603 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
604
605 if (PatchCount != 0) {
606 DEBUG ((
607 DEBUG_INFO,
608 "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",
609 __FUNCTION__, PatchCount, TotalLoadSize
610 ));
611
612 ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);
613 }
614
615 OnExit:
616 if (PatchInfoBuffer != NULL) {
617 FreePool (PatchInfoBuffer);
618 }
619 return;
620 }
621
622 /**
623 Shadow the required microcode patches data into memory according to FIT microcode entry.
624
625 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
626
627 @return EFI_SUCCESS Microcode patch is shadowed into memory.
628 @return EFI_UNSUPPORTED FIT based microcode shadowing is not supported.
629 @return EFI_OUT_OF_RESOURCES No enough memory resource.
630 @return EFI_NOT_FOUND There is something wrong in FIT microcode entry.
631
632 **/
633 EFI_STATUS
634 ShadowMicrocodePatchByFit (
635 IN OUT CPU_MP_DATA *CpuMpData
636 )
637 {
638 UINT64 FitPointer;
639 FIRMWARE_INTERFACE_TABLE_ENTRY *FitEntry;
640 UINT32 EntryNum;
641 UINT32 Index;
642 MICROCODE_PATCH_INFO *PatchInfoBuffer;
643 UINTN MaxPatchNumber;
644 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
645 UINTN PatchCount;
646 UINTN TotalSize;
647 UINTN TotalLoadSize;
648
649 if (!FeaturePcdGet (PcdCpuShadowMicrocodeByFit)) {
650 return EFI_UNSUPPORTED;
651 }
652
653 FitPointer = *(UINT64 *) (UINTN) FIT_POINTER_ADDRESS;
654 if ((FitPointer == 0) ||
655 (FitPointer == 0xFFFFFFFFFFFFFFFF) ||
656 (FitPointer == 0xEEEEEEEEEEEEEEEE)) {
657 //
658 // No FIT table.
659 //
660 ASSERT (FALSE);
661 return EFI_NOT_FOUND;
662 }
663 FitEntry = (FIRMWARE_INTERFACE_TABLE_ENTRY *) (UINTN) FitPointer;
664 if ((FitEntry[0].Type != FIT_TYPE_00_HEADER) ||
665 (FitEntry[0].Address != FIT_TYPE_00_SIGNATURE)) {
666 //
667 // Invalid FIT table, treat it as no FIT table.
668 //
669 ASSERT (FALSE);
670 return EFI_NOT_FOUND;
671 }
672
673 EntryNum = *(UINT32 *)(&FitEntry[0].Size[0]) & 0xFFFFFF;
674
675 //
676 // Calculate microcode entry number
677 //
678 MaxPatchNumber = 0;
679 for (Index = 0; Index < EntryNum; Index++) {
680 if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {
681 MaxPatchNumber++;
682 }
683 }
684 if (MaxPatchNumber == 0) {
685 return EFI_NOT_FOUND;
686 }
687
688 PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));
689 if (PatchInfoBuffer == NULL) {
690 return EFI_OUT_OF_RESOURCES;
691 }
692
693 //
694 // Fill up microcode patch info buffer according to FIT table.
695 //
696 PatchCount = 0;
697 TotalLoadSize = 0;
698 for (Index = 0; Index < EntryNum; Index++) {
699 if (FitEntry[Index].Type == FIT_TYPE_01_MICROCODE) {
700 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) FitEntry[Index].Address;
701 TotalSize = (MicrocodeEntryPoint->DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;
702 if (IsMicrocodePatchNeedLoad (CpuMpData, MicrocodeEntryPoint)) {
703 PatchInfoBuffer[PatchCount].Address = (UINTN) MicrocodeEntryPoint;
704 PatchInfoBuffer[PatchCount].Size = TotalSize;
705 TotalLoadSize += TotalSize;
706 PatchCount++;
707 }
708 }
709 }
710
711 if (PatchCount != 0) {
712 DEBUG ((
713 DEBUG_INFO,
714 "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",
715 __FUNCTION__, PatchCount, TotalLoadSize
716 ));
717
718 ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);
719 }
720
721 FreePool (PatchInfoBuffer);
722 return EFI_SUCCESS;
723 }
724
725 /**
726 Shadow the required microcode patches data into memory.
727
728 @param[in, out] CpuMpData The pointer to CPU MP Data structure.
729 **/
730 VOID
731 ShadowMicrocodeUpdatePatch (
732 IN OUT CPU_MP_DATA *CpuMpData
733 )
734 {
735 EFI_STATUS Status;
736
737 Status = ShadowMicrocodePatchByFit (CpuMpData);
738 if (EFI_ERROR (Status)) {
739 ShadowMicrocodePatchByPcd (CpuMpData);
740 }
741 }
742
743 /**
744 Get the cached microcode patch base address and size from the microcode patch
745 information cache HOB.
746
747 @param[out] Address Base address of the microcode patches data.
748 It will be updated if the microcode patch
749 information cache HOB is found.
750 @param[out] RegionSize Size of the microcode patches data.
751 It will be updated if the microcode patch
752 information cache HOB is found.
753
754 @retval TRUE The microcode patch information cache HOB is found.
755 @retval FALSE The microcode patch information cache HOB is not found.
756
757 **/
758 BOOLEAN
759 GetMicrocodePatchInfoFromHob (
760 UINT64 *Address,
761 UINT64 *RegionSize
762 )
763 {
764 EFI_HOB_GUID_TYPE *GuidHob;
765 EDKII_MICROCODE_PATCH_HOB *MicrocodePathHob;
766
767 GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid);
768 if (GuidHob == NULL) {
769 DEBUG((DEBUG_INFO, "%a: Microcode patch cache HOB is not found.\n", __FUNCTION__));
770 return FALSE;
771 }
772
773 MicrocodePathHob = GET_GUID_HOB_DATA (GuidHob);
774
775 *Address = MicrocodePathHob->MicrocodePatchAddress;
776 *RegionSize = MicrocodePathHob->MicrocodePatchRegionSize;
777
778 DEBUG((
779 DEBUG_INFO, "%a: MicrocodeBase = 0x%lx, MicrocodeSize = 0x%lx\n",
780 __FUNCTION__, *Address, *RegionSize
781 ));
782
783 return TRUE;
784 }