]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
MdeModulePkg/PciHostBridge: Count the (mm)io overhead when polling
[mirror_edk2.git] / IntelSiliconPkg / Feature / Capsule / MicrocodeUpdateDxe / MicrocodeUpdate.c
... / ...
CommitLineData
1/** @file\r
2 SetImage instance to update Microcode.\r
3\r
4 Caution: This module requires additional review when modified.\r
5 This module will have external input - capsule image.\r
6 This external input must be validated carefully to avoid security issue like\r
7 buffer overflow, integer overflow.\r
8\r
9 MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.\r
10\r
11 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
12 This program and the accompanying materials\r
13 are licensed and made available under the terms and conditions of the BSD License\r
14 which accompanies this distribution. The full text of the license may be found at\r
15 http://opensource.org/licenses/bsd-license.php\r
16\r
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
19\r
20**/\r
21\r
22#include "MicrocodeUpdate.h"\r
23\r
24/**\r
25 Get Microcode Region.\r
26\r
27 @param[out] MicrocodePatchAddress The address of Microcode\r
28 @param[out] MicrocodePatchRegionSize The region size of Microcode\r
29\r
30 @retval TRUE The Microcode region is returned.\r
31 @retval FALSE No Microcode region.\r
32**/\r
33BOOLEAN\r
34GetMicrocodeRegion (\r
35 OUT VOID **MicrocodePatchAddress,\r
36 OUT UINTN *MicrocodePatchRegionSize\r
37 )\r
38{\r
39 *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);\r
40 *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);\r
41\r
42 if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {\r
43 return FALSE;\r
44 }\r
45\r
46 return TRUE;\r
47}\r
48\r
49/**\r
50 Get Microcode update signature of currently loaded Microcode update.\r
51\r
52 @return Microcode signature.\r
53\r
54**/\r
55UINT32\r
56GetCurrentMicrocodeSignature (\r
57 VOID\r
58 )\r
59{\r
60 UINT64 Signature;\r
61\r
62 AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0);\r
63 AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
64 Signature = AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID);\r
65 return (UINT32)RShiftU64(Signature, 32);\r
66}\r
67\r
68/**\r
69 Get current processor signature.\r
70\r
71 @return current processor signature.\r
72**/\r
73UINT32\r
74GetCurrentProcessorSignature (\r
75 VOID\r
76 )\r
77{\r
78 UINT32 RegEax;\r
79 AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);\r
80 return RegEax;\r
81}\r
82\r
83/**\r
84 Get current platform ID.\r
85\r
86 @return current platform ID.\r
87**/\r
88UINT8\r
89GetCurrentPlatformId (\r
90 VOID\r
91 )\r
92{\r
93 UINT8 PlatformId;\r
94\r
95 PlatformId = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52);\r
96 return PlatformId;\r
97}\r
98\r
99/**\r
100 Load new Microcode.\r
101\r
102 @param[in] Address The address of new Microcode.\r
103\r
104 @return Loaded Microcode signature.\r
105\r
106**/\r
107UINT32\r
108LoadMicrocode (\r
109 IN UINT64 Address\r
110 )\r
111{\r
112 AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address);\r
113 return GetCurrentMicrocodeSignature();\r
114}\r
115\r
116/**\r
117 Load Microcode on an Application Processor.\r
118 The function prototype for invoking a function on an Application Processor.\r
119\r
120 @param[in,out] Buffer The pointer to private data buffer.\r
121**/\r
122VOID\r
123EFIAPI\r
124MicrocodeLoadAp (\r
125 IN OUT VOID *Buffer\r
126 )\r
127{\r
128 MICROCODE_LOAD_BUFFER *MicrocodeLoadBuffer;\r
129\r
130 MicrocodeLoadBuffer = Buffer;\r
131 MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);\r
132}\r
133\r
134/**\r
135 Load new Microcode on this processor\r
136\r
137 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
138 @param[in] CpuIndex The index of the processor.\r
139 @param[in] Address The address of new Microcode.\r
140\r
141 @return Loaded Microcode signature.\r
142\r
143**/\r
144UINT32\r
145LoadMicrocodeOnThis (\r
146 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
147 IN UINTN CpuIndex,\r
148 IN UINT64 Address\r
149 )\r
150{\r
151 EFI_STATUS Status;\r
152 EFI_MP_SERVICES_PROTOCOL *MpService;\r
153 MICROCODE_LOAD_BUFFER MicrocodeLoadBuffer;\r
154\r
155 if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {\r
156 return LoadMicrocode (Address);\r
157 } else {\r
158 MpService = MicrocodeFmpPrivate->MpService;\r
159 MicrocodeLoadBuffer.Address = Address;\r
160 MicrocodeLoadBuffer.Revision = 0;\r
161 Status = MpService->StartupThisAP (\r
162 MpService,\r
163 MicrocodeLoadAp,\r
164 CpuIndex,\r
165 NULL,\r
166 0,\r
167 &MicrocodeLoadBuffer,\r
168 NULL\r
169 );\r
170 ASSERT_EFI_ERROR(Status);\r
171 return MicrocodeLoadBuffer.Revision;\r
172 }\r
173}\r
174\r
175/**\r
176 Collect processor information.\r
177 The function prototype for invoking a function on an Application Processor.\r
178\r
179 @param[in,out] Buffer The pointer to private data buffer.\r
180**/\r
181VOID\r
182EFIAPI\r
183CollectProcessorInfo (\r
184 IN OUT VOID *Buffer\r
185 )\r
186{\r
187 PROCESSOR_INFO *ProcessorInfo;\r
188\r
189 ProcessorInfo = Buffer;\r
190 ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();\r
191 ProcessorInfo->PlatformId = GetCurrentPlatformId();\r
192 ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();\r
193}\r
194\r
195/**\r
196 Get current Microcode information.\r
197\r
198 The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)\r
199 in MicrocodeFmpPrivate must be initialized.\r
200\r
201 The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)\r
202 in MicrocodeFmpPrivate may not be avaiable in this function.\r
203\r
204 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
205 @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated.\r
206 @param[out] ImageDescriptor Microcode ImageDescriptor\r
207 @param[out] MicrocodeInfo Microcode information\r
208\r
209 @return Microcode count\r
210**/\r
211UINTN\r
212GetMicrocodeInfo (\r
213 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
214 IN UINTN DescriptorCount, OPTIONAL\r
215 OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL\r
216 OUT MICROCODE_INFO *MicrocodeInfo OPTIONAL\r
217 )\r
218{\r
219 VOID *MicrocodePatchAddress;\r
220 UINTN MicrocodePatchRegionSize;\r
221 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
222 UINTN MicrocodeEnd;\r
223 UINTN TotalSize;\r
224 UINTN Count;\r
225 UINT64 ImageAttributes;\r
226 BOOLEAN IsInUse;\r
227 EFI_STATUS Status;\r
228 UINT32 AttemptStatus;\r
229 UINTN TargetCpuIndex;\r
230\r
231 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
232 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
233\r
234 DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));\r
235\r
236 Count = 0;\r
237\r
238 MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;\r
239 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;\r
240 do {\r
241 if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {\r
242 //\r
243 // It is the microcode header. It is not the padding data between microcode patches\r
244 // becasue the padding data should not include 0x00000001 and it should be the repeated\r
245 // byte format (like 0xXYXYXYXY....).\r
246 //\r
247 if (MicrocodeEntryPoint->DataSize == 0) {\r
248 TotalSize = 2048;\r
249 } else {\r
250 TotalSize = MicrocodeEntryPoint->TotalSize;\r
251 }\r
252\r
253 TargetCpuIndex = (UINTN)-1;\r
254 Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);\r
255 if (!EFI_ERROR(Status)) {\r
256 IsInUse = TRUE;\r
257 ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
258 MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;\r
259 } else {\r
260 IsInUse = FALSE;\r
261 }\r
262\r
263 if (ImageDescriptor != NULL && DescriptorCount > Count) {\r
264 ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);\r
265 CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);\r
266 ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
267 ImageDescriptor[Count].ImageIdName = NULL;\r
268 ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision;\r
269 ImageDescriptor[Count].VersionName = NULL;\r
270 ImageDescriptor[Count].Size = TotalSize;\r
271 ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;\r
272 if (IsInUse) {\r
273 ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;\r
274 }\r
275 ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;\r
276 ImageDescriptor[Count].AttributesSetting = ImageAttributes;\r
277 ImageDescriptor[Count].Compatibilities = 0;\r
278 ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback\r
279 ImageDescriptor[Count].LastAttemptVersion = 0;\r
280 ImageDescriptor[Count].LastAttemptStatus = 0;\r
281 ImageDescriptor[Count].HardwareInstance = 0;\r
282 }\r
283 if (MicrocodeInfo != NULL && DescriptorCount > Count) {\r
284 MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;\r
285 MicrocodeInfo[Count].TotalSize = TotalSize;\r
286 MicrocodeInfo[Count].InUse = IsInUse;\r
287 }\r
288 } else {\r
289 //\r
290 // It is the padding data between the microcode patches for microcode patches alignment.\r
291 // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
292 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
293 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
294 // find the next possible microcode patch header.\r
295 //\r
296 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
297 continue;\r
298 }\r
299\r
300 Count++;\r
301 ASSERT(Count < 0xFF);\r
302\r
303 //\r
304 // Get the next patch.\r
305 //\r
306 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
307 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
308\r
309 return Count;\r
310}\r
311\r
312/**\r
313 Return matched processor information.\r
314\r
315 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
316 @param[in] ProcessorSignature The processor signature to be matched\r
317 @param[in] ProcessorFlags The processor flags to be matched\r
318 @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.\r
319 On output, the index of target CPU which matches the Microcode.\r
320\r
321 @return matched processor information.\r
322**/\r
323PROCESSOR_INFO *\r
324GetMatchedProcessor (\r
325 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
326 IN UINT32 ProcessorSignature,\r
327 IN UINT32 ProcessorFlags,\r
328 IN OUT UINTN *TargetCpuIndex\r
329 )\r
330{\r
331 UINTN Index;\r
332\r
333 if (*TargetCpuIndex != (UINTN)-1) {\r
334 Index = *TargetCpuIndex;\r
335 if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&\r
336 ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {\r
337 return &MicrocodeFmpPrivate->ProcessorInfo[Index];\r
338 } else {\r
339 return NULL;\r
340 }\r
341 }\r
342\r
343 for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {\r
344 if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&\r
345 ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {\r
346 *TargetCpuIndex = Index;\r
347 return &MicrocodeFmpPrivate->ProcessorInfo[Index];\r
348 }\r
349 }\r
350 return NULL;\r
351}\r
352\r
353/**\r
354 Verify Microcode.\r
355\r
356 Caution: This function may receive untrusted input.\r
357\r
358 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
359 @param[in] Image The Microcode image buffer.\r
360 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
361 @param[in] TryLoad Try to load Microcode or not.\r
362 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
363 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more\r
364 details for the aborted operation. The buffer is allocated by this function\r
365 with AllocatePool(), and it is the caller's responsibility to free it with a\r
366 call to FreePool().\r
367 @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.\r
368 On output, the index of target CPU which matches the Microcode.\r
369\r
370 @retval EFI_SUCCESS The Microcode image passes verification.\r
371 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.\r
372 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.\r
373 @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.\r
374 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.\r
375**/\r
376EFI_STATUS\r
377VerifyMicrocode (\r
378 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
379 IN VOID *Image,\r
380 IN UINTN ImageSize,\r
381 IN BOOLEAN TryLoad,\r
382 OUT UINT32 *LastAttemptStatus,\r
383 OUT CHAR16 **AbortReason, OPTIONAL\r
384 IN OUT UINTN *TargetCpuIndex\r
385 )\r
386{\r
387 UINTN Index;\r
388 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
389 UINTN TotalSize;\r
390 UINTN DataSize;\r
391 UINT32 CurrentRevision;\r
392 PROCESSOR_INFO *ProcessorInfo;\r
393 UINT32 CheckSum32;\r
394 UINTN ExtendedTableLength;\r
395 UINT32 ExtendedTableCount;\r
396 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
397 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
398 BOOLEAN CorrectMicrocode;\r
399\r
400 //\r
401 // Check HeaderVersion\r
402 //\r
403 MicrocodeEntryPoint = Image;\r
404 if (MicrocodeEntryPoint->HeaderVersion != 0x1) {\r
405 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n"));\r
406 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
407 if (AbortReason != NULL) {\r
408 *AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion");\r
409 }\r
410 return EFI_INCOMPATIBLE_VERSION;\r
411 }\r
412 //\r
413 // Check LoaderRevision\r
414 //\r
415 if (MicrocodeEntryPoint->LoaderRevision != 0x1) {\r
416 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n"));\r
417 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
418 if (AbortReason != NULL) {\r
419 *AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion");\r
420 }\r
421 return EFI_INCOMPATIBLE_VERSION;\r
422 }\r
423 //\r
424 // Check TotalSize\r
425 //\r
426 if (MicrocodeEntryPoint->DataSize == 0) {\r
427 TotalSize = 2048;\r
428 } else {\r
429 TotalSize = MicrocodeEntryPoint->TotalSize;\r
430 }\r
431 if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) {\r
432 DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n"));\r
433 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
434 if (AbortReason != NULL) {\r
435 *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
436 }\r
437 return EFI_VOLUME_CORRUPTED;\r
438 }\r
439 if ((TotalSize & (SIZE_1KB - 1)) != 0) {\r
440 DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize is not multiples of 1024 bytes (1 KBytes)\n"));\r
441 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
442 if (AbortReason != NULL) {\r
443 *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
444 }\r
445 return EFI_VOLUME_CORRUPTED;\r
446 }\r
447 if (TotalSize != ImageSize) {\r
448 DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize not equal to ImageSize\n"));\r
449 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
450 if (AbortReason != NULL) {\r
451 *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
452 }\r
453 return EFI_VOLUME_CORRUPTED;\r
454 }\r
455 //\r
456 // Check DataSize\r
457 //\r
458 if (MicrocodeEntryPoint->DataSize == 0) {\r
459 DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);\r
460 } else {\r
461 DataSize = MicrocodeEntryPoint->DataSize;\r
462 }\r
463 if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) {\r
464 DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n"));\r
465 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
466 if (AbortReason != NULL) {\r
467 *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
468 }\r
469 return EFI_VOLUME_CORRUPTED;\r
470 }\r
471 if ((DataSize & 0x3) != 0) {\r
472 DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize is not multiples of DWORDs\n"));\r
473 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
474 if (AbortReason != NULL) {\r
475 *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
476 }\r
477 return EFI_VOLUME_CORRUPTED;\r
478 }\r
479 //\r
480 // Check CheckSum32\r
481 //\r
482 CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));\r
483 if (CheckSum32 != 0) {\r
484 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));\r
485 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
486 if (AbortReason != NULL) {\r
487 *AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum");\r
488 }\r
489 return EFI_VOLUME_CORRUPTED;\r
490 }\r
491\r
492 //\r
493 // Check ProcessorSignature/ProcessorFlags\r
494 //\r
495\r
496 ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);\r
497 if (ProcessorInfo == NULL) {\r
498 CorrectMicrocode = FALSE;\r
499 ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER));\r
500 if (ExtendedTableLength != 0) {\r
501 //\r
502 // Extended Table exist, check if the CPU in support list\r
503 //\r
504 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER));\r
505 //\r
506 // Calculate Extended Checksum\r
507 //\r
508 if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) == 0)) {\r
509 CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);\r
510 if (CheckSum32 != 0) {\r
511 //\r
512 // Checksum incorrect\r
513 //\r
514 DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for extended table is incorrect\n"));\r
515 } else {\r
516 //\r
517 // Checksum correct\r
518 //\r
519 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
520 if (ExtendedTableCount > (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {\r
521 DEBUG((DEBUG_ERROR, "VerifyMicrocode - ExtendedTableCount too big\n"));\r
522 } else {\r
523 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);\r
524 for (Index = 0; Index < ExtendedTableCount; Index++) {\r
525 CheckSum32 = CalculateSum32((UINT32 *)ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));\r
526 if (CheckSum32 != 0) {\r
527 DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for ExtendedTable entry with index 0x%x is incorrect\n", Index));\r
528 } else {\r
529 //\r
530 // Verify Header\r
531 //\r
532 ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);\r
533 if (ProcessorInfo != NULL) {\r
534 //\r
535 // Find one\r
536 //\r
537 CorrectMicrocode = TRUE;\r
538 break;\r
539 }\r
540 }\r
541 ExtendedTable++;\r
542 }\r
543 }\r
544 }\r
545 }\r
546 }\r
547 if (!CorrectMicrocode) {\r
548 if (TryLoad) {\r
549 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on Current ProcessorSignature/ProcessorFlags\n"));\r
550 }\r
551 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
552 if (AbortReason != NULL) {\r
553 *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature/ProcessorFlags"), L"UnsupportedProcessSignature/ProcessorFlags");\r
554 }\r
555 return EFI_UNSUPPORTED;\r
556 }\r
557 }\r
558\r
559 //\r
560 // Check UpdateRevision\r
561 //\r
562 CurrentRevision = ProcessorInfo->MicrocodeRevision;\r
563 if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||\r
564 (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {\r
565 if (TryLoad) {\r
566 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));\r
567 }\r
568 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
569 if (AbortReason != NULL) {\r
570 *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");\r
571 }\r
572 return EFI_INCOMPATIBLE_VERSION;\r
573 }\r
574\r
575 //\r
576 // try load MCU\r
577 //\r
578 if (TryLoad) {\r
579 CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));\r
580 if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {\r
581 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));\r
582 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
583 if (AbortReason != NULL) {\r
584 *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");\r
585 }\r
586 return EFI_SECURITY_VIOLATION;\r
587 }\r
588 }\r
589\r
590 return EFI_SUCCESS;\r
591}\r
592\r
593/**\r
594 Get next Microcode entrypoint.\r
595\r
596 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
597 @param[in] MicrocodeEntryPoint Current Microcode entrypoint\r
598\r
599 @return next Microcode entrypoint.\r
600**/\r
601CPU_MICROCODE_HEADER *\r
602GetNextMicrocode (\r
603 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
604 IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint\r
605 )\r
606{\r
607 UINTN Index;\r
608\r
609 for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {\r
610 if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {\r
611 if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {\r
612 // it is last one\r
613 return NULL;\r
614 } else {\r
615 // return next one\r
616 return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;\r
617 }\r
618 }\r
619 }\r
620\r
621 ASSERT(FALSE);\r
622 return NULL;\r
623}\r
624\r
625/**\r
626 Get current Microcode used region size.\r
627\r
628 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
629\r
630 @return current Microcode used region size.\r
631**/\r
632UINTN\r
633GetCurrentMicrocodeUsedRegionSize (\r
634 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
635 )\r
636{\r
637 if (MicrocodeFmpPrivate->DescriptorCount == 0) {\r
638 return 0;\r
639 }\r
640\r
641 return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint\r
642 + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize\r
643 - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;\r
644}\r
645\r
646/**\r
647 Update Microcode.\r
648\r
649 @param[in] Address The flash address of Microcode.\r
650 @param[in] Image The Microcode image buffer.\r
651 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
652 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
653\r
654 @retval EFI_SUCCESS The Microcode image is updated.\r
655 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
656**/\r
657EFI_STATUS\r
658UpdateMicrocode (\r
659 IN UINT64 Address,\r
660 IN VOID *Image,\r
661 IN UINTN ImageSize,\r
662 OUT UINT32 *LastAttemptStatus\r
663 )\r
664{\r
665 EFI_STATUS Status;\r
666\r
667 DEBUG((DEBUG_INFO, "PlatformUpdate:"));\r
668 DEBUG((DEBUG_INFO, " Address - 0x%lx,", Address));\r
669 DEBUG((DEBUG_INFO, " Legnth - 0x%x\n", ImageSize));\r
670\r
671 Status = MicrocodeFlashWrite (\r
672 Address,\r
673 Image,\r
674 ImageSize\r
675 );\r
676 if (!EFI_ERROR(Status)) {\r
677 *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
678 } else {\r
679 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
680 }\r
681 return Status;\r
682}\r
683\r
684/**\r
685 Update Microcode flash region.\r
686\r
687 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
688 @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated\r
689 @param[in] Image The Microcode image buffer.\r
690 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
691 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
692\r
693 @retval EFI_SUCCESS The Microcode image is written.\r
694 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
695**/\r
696EFI_STATUS\r
697UpdateMicrocodeFlashRegion (\r
698 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
699 IN CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint,\r
700 IN VOID *Image,\r
701 IN UINTN ImageSize,\r
702 OUT UINT32 *LastAttemptStatus\r
703 )\r
704{\r
705 VOID *MicrocodePatchAddress;\r
706 UINTN MicrocodePatchRegionSize;\r
707 UINTN TargetTotalSize;\r
708 UINTN UsedRegionSize;\r
709 EFI_STATUS Status;\r
710 VOID *MicrocodePatchScratchBuffer;\r
711 UINT8 *ScratchBufferPtr;\r
712 UINTN ScratchBufferSize;\r
713 UINTN RestSize;\r
714 UINTN AvailableSize;\r
715 VOID *NextMicrocodeEntryPoint;\r
716 MICROCODE_INFO *MicrocodeInfo;\r
717 UINTN MicrocodeCount;\r
718 UINTN Index;\r
719\r
720 DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));\r
721\r
722 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
723 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
724\r
725 MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);\r
726 if (MicrocodePatchScratchBuffer == NULL) {\r
727 DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));\r
728 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
729 return EFI_OUT_OF_RESOURCES;\r
730 }\r
731 ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
732 ScratchBufferSize = 0;\r
733\r
734 //\r
735 // Target data collection\r
736 //\r
737 TargetTotalSize = 0;\r
738 AvailableSize = 0;\r
739 NextMicrocodeEntryPoint = NULL;\r
740 if (TargetMicrocodeEntryPoint != NULL) {\r
741 if (TargetMicrocodeEntryPoint->DataSize == 0) {\r
742 TargetTotalSize = 2048;\r
743 } else {\r
744 TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;\r
745 }\r
746 DEBUG((DEBUG_INFO, " TargetTotalSize - 0x%x\n", TargetTotalSize));\r
747 NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);\r
748 DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));\r
749 if (NextMicrocodeEntryPoint != NULL) {\r
750 ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
751 AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;\r
752 } else {\r
753 AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;\r
754 }\r
755 DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));\r
756 }\r
757 ASSERT (AvailableSize >= TargetTotalSize);\r
758 UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);\r
759 DEBUG((DEBUG_INFO, " UsedRegionSize - 0x%x\n", UsedRegionSize));\r
760 ASSERT (UsedRegionSize >= TargetTotalSize);\r
761 if (TargetMicrocodeEntryPoint != NULL) {\r
762 ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
763 }\r
764 //\r
765 // Total Size means the Microcode data size.\r
766 // Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.\r
767 //\r
768 // (1)\r
769 // +------+-----------+-----+------+===================+\r
770 // | MCU1 | Microcode | PAD | MCU2 | Empty |\r
771 // +------+-----------+-----+------+===================+\r
772 // | TotalSize |\r
773 // |<-AvailableSize->|\r
774 // |<- UsedRegionSize ->|\r
775 //\r
776 // (2)\r
777 // +------+-----------+===================+\r
778 // | MCU | Microcode | Empty |\r
779 // +------+-----------+===================+\r
780 // | TotalSize |\r
781 // |<- AvailableSize ->|\r
782 // |<-UsedRegionSize->|\r
783 //\r
784\r
785 //\r
786 // Update based on policy\r
787 //\r
788\r
789 //\r
790 // 1. If there is enough space to update old one in situ, replace old microcode in situ.\r
791 //\r
792 if (AvailableSize >= ImageSize) {\r
793 DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
794 //\r
795 // +------+------------+------+===================+\r
796 // |Other1| Old Image |Other2| Empty |\r
797 // +------+------------+------+===================+\r
798 //\r
799 // +------+---------+--+------+===================+\r
800 // |Other1|New Image|FF|Other2| Empty |\r
801 // +------+---------+--+------+===================+\r
802 //\r
803 // 1.1. Copy new image\r
804 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
805 ScratchBufferSize += ImageSize;\r
806 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
807 // 1.2. Pad 0xFF\r
808 RestSize = AvailableSize - ImageSize;\r
809 if (RestSize > 0) {\r
810 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
811 ScratchBufferSize += RestSize;\r
812 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
813 }\r
814 Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
815 return Status;\r
816 }\r
817\r
818 //\r
819 // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.\r
820 //\r
821 if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {\r
822 if (TargetMicrocodeEntryPoint == NULL) {\r
823 DEBUG((DEBUG_INFO, "Append new microcode\n"));\r
824 //\r
825 // +------+------------+------+===================+\r
826 // |Other1| Other |Other2| Empty |\r
827 // +------+------------+------+===================+\r
828 //\r
829 // +------+------------+------+-----------+=======+\r
830 // |Other1| Other |Other2| New Image | Empty |\r
831 // +------+------------+------+-----------+=======+\r
832 //\r
833 Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);\r
834 } else {\r
835 DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));\r
836 //\r
837 // +------+------------+------+===================+\r
838 // |Other1| Old Image |Other2| Empty |\r
839 // +------+------------+------+===================+\r
840 //\r
841 // +------+---------------+------+================+\r
842 // |Other1| New Image |Other2| Empty |\r
843 // +------+---------------+------+================+\r
844 //\r
845 // 2.1. Copy new image\r
846 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
847 ScratchBufferSize += ImageSize;\r
848 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
849 // 2.2. Copy rest images after the old image.\r
850 if (NextMicrocodeEntryPoint != 0) {\r
851 RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);\r
852 CopyMem (ScratchBufferPtr, (UINT8 *)TargetMicrocodeEntryPoint + TargetTotalSize, RestSize);\r
853 ScratchBufferSize += RestSize;\r
854 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
855 }\r
856 Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
857 }\r
858 return Status;\r
859 }\r
860\r
861 //\r
862 // 3. The new image can be put in MCU region, but not all others can be put.\r
863 // So all the unused MCU is removed.\r
864 //\r
865 if (MicrocodePatchRegionSize >= ImageSize) {\r
866 //\r
867 // +------+------------+------+===================+\r
868 // |Other1| Old Image |Other2| Empty |\r
869 // +------+------------+------+===================+\r
870 //\r
871 // +-------------------------------------+--------+\r
872 // | New Image | Other |\r
873 // +-------------------------------------+--------+\r
874 //\r
875 DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));\r
876\r
877 MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;\r
878 MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;\r
879\r
880 // 3.1. Copy new image\r
881 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
882 ScratchBufferSize += ImageSize;\r
883 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
884 // 3.2. Copy some others to rest buffer\r
885 for (Index = 0; Index < MicrocodeCount; Index++) {\r
886 if (!MicrocodeInfo[Index].InUse) {\r
887 continue;\r
888 }\r
889 if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {\r
890 continue;\r
891 }\r
892 if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {\r
893 CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);\r
894 ScratchBufferSize += MicrocodeInfo[Index].TotalSize;\r
895 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
896 }\r
897 }\r
898 // 3.3. Pad 0xFF\r
899 RestSize = MicrocodePatchRegionSize - ScratchBufferSize;\r
900 if (RestSize > 0) {\r
901 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
902 ScratchBufferSize += RestSize;\r
903 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
904 }\r
905 Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
906 return Status;\r
907 }\r
908\r
909 //\r
910 // 4. The new image size is bigger than the whole MCU region.\r
911 //\r
912 DEBUG((DEBUG_ERROR, "Microcode too big\n"));\r
913 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
914 Status = EFI_OUT_OF_RESOURCES;\r
915\r
916 return Status;\r
917}\r
918\r
919/**\r
920 Write Microcode.\r
921\r
922 Caution: This function may receive untrusted input.\r
923\r
924 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
925 @param[in] Image The Microcode image buffer.\r
926 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
927 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
928 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
929 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more\r
930 details for the aborted operation. The buffer is allocated by this function\r
931 with AllocatePool(), and it is the caller's responsibility to free it with a\r
932 call to FreePool().\r
933\r
934 @retval EFI_SUCCESS The Microcode image is written.\r
935 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.\r
936 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.\r
937 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.\r
938 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
939**/\r
940EFI_STATUS\r
941MicrocodeWrite (\r
942 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
943 IN VOID *Image,\r
944 IN UINTN ImageSize,\r
945 OUT UINT32 *LastAttemptVersion,\r
946 OUT UINT32 *LastAttemptStatus,\r
947 OUT CHAR16 **AbortReason\r
948 )\r
949{\r
950 EFI_STATUS Status;\r
951 VOID *AlignedImage;\r
952 CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint;\r
953 UINTN TargetCpuIndex;\r
954 UINTN TargetMicrcodeIndex;\r
955\r
956 //\r
957 // MCU must be 16 bytes aligned\r
958 //\r
959 AlignedImage = AllocateCopyPool(ImageSize, Image);\r
960 if (AlignedImage == NULL) {\r
961 DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));\r
962 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
963 return EFI_OUT_OF_RESOURCES;\r
964 }\r
965\r
966 *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;\r
967 TargetCpuIndex = (UINTN)-1;\r
968 Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);\r
969 if (EFI_ERROR(Status)) {\r
970 DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));\r
971 FreePool(AlignedImage);\r
972 return Status;\r
973 }\r
974 DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));\r
975\r
976 DEBUG((DEBUG_INFO, " TargetCpuIndex - 0x%x\n", TargetCpuIndex));\r
977 ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
978 TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;\r
979 DEBUG((DEBUG_INFO, " TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));\r
980 if (TargetMicrcodeIndex != (UINTN)-1) {\r
981 ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);\r
982 TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;\r
983 } else {\r
984 TargetMicrocodeEntryPoint = NULL;\r
985 }\r
986 DEBUG((DEBUG_INFO, " TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));\r
987\r
988 Status = UpdateMicrocodeFlashRegion(\r
989 MicrocodeFmpPrivate,\r
990 TargetMicrocodeEntryPoint,\r
991 AlignedImage,\r
992 ImageSize,\r
993 LastAttemptStatus\r
994 );\r
995\r
996 FreePool(AlignedImage);\r
997\r
998 return Status;\r
999}\r
1000\r
1001\r