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