]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/Microcode.c
UefiPayloadPkg/UefiPayloadPkg.dsc: Consume MicrocodeLib
[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
94f63c76 318 }\r
030ba309 319 CpuMpData->CpuData[ProcessorNumber].MicrocodeRevision = GetCurrentMicrocodeSignature ();\r
94f63c76 320}\r
d786a172
HW
321\r
322/**\r
dd017041 323 Determine if a microcode patch matchs the specific processor signature and flag.\r
d786a172
HW
324\r
325 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
326 @param[in] ProcessorSignature The processor signature field value\r
327 supported by a microcode patch.\r
328 @param[in] ProcessorFlags The prcessor flags field value supported by\r
329 a microcode patch.\r
330\r
331 @retval TRUE The specified microcode patch will be loaded.\r
332 @retval FALSE The specified microcode patch will not be loaded.\r
333**/\r
334BOOLEAN\r
dd017041 335IsProcessorMatchedMicrocodePatch (\r
d786a172
HW
336 IN CPU_MP_DATA *CpuMpData,\r
337 IN UINT32 ProcessorSignature,\r
338 IN UINT32 ProcessorFlags\r
339 )\r
340{\r
341 UINTN Index;\r
342 CPU_AP_DATA *CpuData;\r
343\r
344 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
345 CpuData = &CpuMpData->CpuData[Index];\r
346 if ((ProcessorSignature == CpuData->ProcessorSignature) &&\r
347 (ProcessorFlags & (1 << CpuData->PlatformId)) != 0) {\r
348 return TRUE;\r
349 }\r
350 }\r
351\r
352 return FALSE;\r
353}\r
354\r
355/**\r
dd017041
SF
356 Check the 'ProcessorSignature' and 'ProcessorFlags' of the microcode\r
357 patch header with the CPUID and PlatformID of the processors within\r
358 system to decide if it will be copied into memory.\r
359\r
360 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
361 @param[in] MicrocodeEntryPoint The pointer to the microcode patch header.\r
362\r
363 @retval TRUE The specified microcode patch need to be loaded.\r
364 @retval FALSE The specified microcode patch dosen't need to be loaded.\r
365**/\r
366BOOLEAN\r
367IsMicrocodePatchNeedLoad (\r
368 IN CPU_MP_DATA *CpuMpData,\r
369 CPU_MICROCODE_HEADER *MicrocodeEntryPoint\r
370 )\r
371{\r
372 BOOLEAN NeedLoad;\r
373 UINTN DataSize;\r
374 UINTN TotalSize;\r
375 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
376 UINT32 ExtendedTableCount;\r
377 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
378 UINTN Index;\r
379\r
380 //\r
381 // Check the 'ProcessorSignature' and 'ProcessorFlags' in microcode patch header.\r
382 //\r
383 NeedLoad = IsProcessorMatchedMicrocodePatch (\r
384 CpuMpData,\r
385 MicrocodeEntryPoint->ProcessorSignature.Uint32,\r
386 MicrocodeEntryPoint->ProcessorFlags\r
387 );\r
388\r
389 //\r
390 // If the Extended Signature Table exists, check if the processor is in the\r
391 // support list\r
392 //\r
393 DataSize = MicrocodeEntryPoint->DataSize;\r
394 TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;\r
395 if ((!NeedLoad) && (DataSize != 0) &&\r
396 (TotalSize - DataSize > sizeof (CPU_MICROCODE_HEADER) +\r
397 sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))) {\r
398 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)\r
399 + DataSize + sizeof (CPU_MICROCODE_HEADER));\r
400 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
401 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);\r
402\r
403 for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
404 //\r
405 // Check the 'ProcessorSignature' and 'ProcessorFlag' of the Extended\r
406 // Signature Table entry with the CPUID and PlatformID of the processors\r
407 // within system to decide if it will be copied into memory\r
408 //\r
409 NeedLoad = IsProcessorMatchedMicrocodePatch (\r
410 CpuMpData,\r
411 ExtendedTable->ProcessorSignature.Uint32,\r
412 ExtendedTable->ProcessorFlag\r
413 );\r
414 if (NeedLoad) {\r
415 break;\r
416 }\r
417 ExtendedTable ++;\r
418 }\r
419 }\r
420\r
421 return NeedLoad;\r
422}\r
423\r
424\r
425/**\r
426 Actual worker function that shadows the required microcode patches into memory.\r
d786a172
HW
427\r
428 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
429 @param[in] Patches The pointer to an array of information on\r
430 the microcode patches that will be loaded\r
431 into memory.\r
432 @param[in] PatchCount The number of microcode patches that will\r
433 be loaded into memory.\r
434 @param[in] TotalLoadSize The total size of all the microcode patches\r
435 to be loaded.\r
436**/\r
437VOID\r
dd017041 438ShadowMicrocodePatchWorker (\r
d786a172
HW
439 IN OUT CPU_MP_DATA *CpuMpData,\r
440 IN MICROCODE_PATCH_INFO *Patches,\r
441 IN UINTN PatchCount,\r
442 IN UINTN TotalLoadSize\r
443 )\r
444{\r
445 UINTN Index;\r
446 VOID *MicrocodePatchInRam;\r
447 UINT8 *Walker;\r
448\r
449 ASSERT ((Patches != NULL) && (PatchCount != 0));\r
450\r
451 MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));\r
452 if (MicrocodePatchInRam == NULL) {\r
453 return;\r
454 }\r
455\r
456 //\r
457 // Load all the required microcode patches into memory\r
458 //\r
459 for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {\r
460 CopyMem (\r
461 Walker,\r
462 (VOID *) Patches[Index].Address,\r
463 Patches[Index].Size\r
464 );\r
08a475df 465 Walker += Patches[Index].Size;\r
d786a172
HW
466 }\r
467\r
468 //\r
469 // Update the microcode patch related fields in CpuMpData\r
470 //\r
471 CpuMpData->MicrocodePatchAddress = (UINTN) MicrocodePatchInRam;\r
472 CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;\r
473\r
474 DEBUG ((\r
475 DEBUG_INFO,\r
476 "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",\r
477 __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize\r
478 ));\r
479\r
480 return;\r
481}\r
482\r
483/**\r
dd017041
SF
484 Shadow the required microcode patches data into memory according to PCD\r
485 PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize.\r
d786a172
HW
486\r
487 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
488**/\r
489VOID\r
dd017041 490ShadowMicrocodePatchByPcd (\r
d786a172
HW
491 IN OUT CPU_MP_DATA *CpuMpData\r
492 )\r
493{\r
494 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
495 UINTN MicrocodeEnd;\r
496 UINTN DataSize;\r
497 UINTN TotalSize;\r
d786a172
HW
498 MICROCODE_PATCH_INFO *PatchInfoBuffer;\r
499 UINTN MaxPatchNumber;\r
500 UINTN PatchCount;\r
501 UINTN TotalLoadSize;\r
d786a172
HW
502\r
503 //\r
504 // Initialize the microcode patch related fields in CpuMpData as the values\r
505 // specified by the PCD pair. If the microcode patches are loaded into memory,\r
506 // these fields will be updated.\r
507 //\r
508 CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
509 CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
510\r
511 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
512 MicrocodeEnd = (UINTN) MicrocodeEntryPoint +\r
513 (UINTN) CpuMpData->MicrocodePatchRegionSize;\r
514 if ((MicrocodeEntryPoint == NULL) || ((UINTN) MicrocodeEntryPoint == MicrocodeEnd)) {\r
515 //\r
516 // There is no microcode patches\r
517 //\r
518 return;\r
519 }\r
520\r
521 PatchCount = 0;\r
522 MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM;\r
523 TotalLoadSize = 0;\r
524 PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));\r
525 if (PatchInfoBuffer == NULL) {\r
526 return;\r
527 }\r
528\r
529 //\r
530 // Process the header of each microcode patch within the region.\r
531 // The purpose is to decide which microcode patch(es) will be loaded into memory.\r
532 //\r
533 do {\r
534 if (MicrocodeEntryPoint->HeaderVersion != 0x1) {\r
535 //\r
536 // Padding data between the microcode patches, skip 1KB to check next entry.\r
537 //\r
538 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
539 continue;\r
540 }\r
541\r
542 DataSize = MicrocodeEntryPoint->DataSize;\r
543 TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;\r
544 if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||\r
545 ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||\r
546 (DataSize & 0x3) != 0 ||\r
547 (TotalSize & (SIZE_1KB - 1)) != 0 ||\r
548 TotalSize < DataSize\r
549 ) {\r
550 //\r
551 // Not a valid microcode header, skip 1KB to check next entry.\r
552 //\r
553 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
554 continue;\r
555 }\r
556\r
dd017041 557 if (IsMicrocodePatchNeedLoad (CpuMpData, MicrocodeEntryPoint)) {\r
d786a172
HW
558 PatchCount++;\r
559 if (PatchCount > MaxPatchNumber) {\r
560 //\r
561 // Current 'PatchInfoBuffer' cannot hold the information, double the size\r
562 // and allocate a new buffer.\r
563 //\r
564 if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {\r
565 //\r
566 // Overflow check for MaxPatchNumber\r
567 //\r
568 goto OnExit;\r
569 }\r
570\r
571 PatchInfoBuffer = ReallocatePool (\r
572 MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),\r
573 2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),\r
574 PatchInfoBuffer\r
575 );\r
576 if (PatchInfoBuffer == NULL) {\r
577 goto OnExit;\r
578 }\r
579 MaxPatchNumber = MaxPatchNumber * 2;\r
580 }\r
581\r
582 //\r
583 // Store the information of this microcode patch\r
584 //\r
08a475df
SF
585 PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;\r
586 PatchInfoBuffer[PatchCount - 1].Size = TotalSize;\r
587 TotalLoadSize += TotalSize;\r
d786a172
HW
588 }\r
589\r
590 //\r
591 // Process the next microcode patch\r
592 //\r
593 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
594 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
595\r
596 if (PatchCount != 0) {\r
597 DEBUG ((\r
598 DEBUG_INFO,\r
599 "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",\r
600 __FUNCTION__, PatchCount, TotalLoadSize\r
601 ));\r
602\r
dd017041 603 ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);\r
d786a172
HW
604 }\r
605\r
606OnExit:\r
607 if (PatchInfoBuffer != NULL) {\r
608 FreePool (PatchInfoBuffer);\r
609 }\r
610 return;\r
611}\r
dd017041 612\r
dd017041
SF
613/**\r
614 Shadow the required microcode patches data into memory.\r
615\r
616 @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r
617**/\r
618VOID\r
619ShadowMicrocodeUpdatePatch (\r
620 IN OUT CPU_MP_DATA *CpuMpData\r
621 )\r
622{\r
623 EFI_STATUS Status;\r
624\r
c788c2b1 625 Status = PlatformShadowMicrocode (CpuMpData);\r
dd017041
SF
626 if (EFI_ERROR (Status)) {\r
627 ShadowMicrocodePatchByPcd (CpuMpData);\r
628 }\r
629}\r
348a34d9
HW
630\r
631/**\r
632 Get the cached microcode patch base address and size from the microcode patch\r
633 information cache HOB.\r
634\r
635 @param[out] Address Base address of the microcode patches data.\r
636 It will be updated if the microcode patch\r
637 information cache HOB is found.\r
638 @param[out] RegionSize Size of the microcode patches data.\r
639 It will be updated if the microcode patch\r
640 information cache HOB is found.\r
641\r
642 @retval TRUE The microcode patch information cache HOB is found.\r
643 @retval FALSE The microcode patch information cache HOB is not found.\r
644\r
645**/\r
646BOOLEAN\r
647GetMicrocodePatchInfoFromHob (\r
648 UINT64 *Address,\r
649 UINT64 *RegionSize\r
650 )\r
651{\r
652 EFI_HOB_GUID_TYPE *GuidHob;\r
653 EDKII_MICROCODE_PATCH_HOB *MicrocodePathHob;\r
654\r
655 GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid);\r
656 if (GuidHob == NULL) {\r
657 DEBUG((DEBUG_INFO, "%a: Microcode patch cache HOB is not found.\n", __FUNCTION__));\r
658 return FALSE;\r
659 }\r
660\r
661 MicrocodePathHob = GET_GUID_HOB_DATA (GuidHob);\r
662\r
663 *Address = MicrocodePathHob->MicrocodePatchAddress;\r
664 *RegionSize = MicrocodePathHob->MicrocodePatchRegionSize;\r
665\r
666 DEBUG((\r
667 DEBUG_INFO, "%a: MicrocodeBase = 0x%lx, MicrocodeSize = 0x%lx\n",\r
668 __FUNCTION__, *Address, *RegionSize\r
669 ));\r
670\r
671 return TRUE;\r
672}\r