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