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