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