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