]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
IntelSiliconPkg MicrocodeUpdateDxe: TotalSize must be multiples of 1KB
[mirror_edk2.git] / IntelSiliconPkg / Feature / Capsule / MicrocodeUpdateDxe / MicrocodeUpdate.c
CommitLineData
88266859
JY
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
1db271df 11 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
88266859
JY
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
2ed65824
JY
35 OUT VOID **MicrocodePatchAddress,\r
36 OUT UINTN *MicrocodePatchRegionSize\r
88266859
JY
37 )\r
38{\r
2ed65824
JY
39 *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);\r
40 *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);\r
88266859 41\r
2ed65824 42 if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {\r
88266859
JY
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
2ed65824 116/**\r
31d060d9
JY
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
2ed65824 136\r
31d060d9
JY
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
2ed65824 142\r
2ed65824 143**/\r
31d060d9
JY
144UINT32\r
145LoadMicrocodeOnThis (\r
146 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
147 IN UINTN CpuIndex,\r
148 IN UINT64 Address\r
2ed65824
JY
149 )\r
150{\r
31d060d9
JY
151 EFI_STATUS Status;\r
152 EFI_MP_SERVICES_PROTOCOL *MpService;\r
153 MICROCODE_LOAD_BUFFER MicrocodeLoadBuffer;\r
2ed65824 154\r
31d060d9
JY
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
2ed65824 172 }\r
31d060d9
JY
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
2ed65824
JY
193}\r
194\r
88266859
JY
195/**\r
196 Get current Microcode information.\r
197\r
31d060d9
JY
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
2ed65824
JY
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
88266859
JY
208\r
209 @return Microcode count\r
210**/\r
211UINTN\r
212GetMicrocodeInfo (\r
2ed65824
JY
213 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
214 IN UINTN DescriptorCount, OPTIONAL\r
88266859 215 OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL\r
2ed65824 216 OUT MICROCODE_INFO *MicrocodeInfo OPTIONAL\r
88266859
JY
217 )\r
218{\r
2ed65824
JY
219 VOID *MicrocodePatchAddress;\r
220 UINTN MicrocodePatchRegionSize;\r
88266859
JY
221 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
222 UINTN MicrocodeEnd;\r
223 UINTN TotalSize;\r
224 UINTN Count;\r
225 UINT64 ImageAttributes;\r
2ed65824 226 BOOLEAN IsInUse;\r
31d060d9
JY
227 EFI_STATUS Status;\r
228 UINT32 AttemptStatus;\r
229 UINTN TargetCpuIndex;\r
88266859 230\r
2ed65824
JY
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
88266859
JY
235\r
236 Count = 0;\r
88266859 237\r
2ed65824 238 MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;\r
88266859
JY
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
31d060d9
JY
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
2ed65824 262\r
88266859
JY
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
2ed65824 272 if (IsInUse) {\r
88266859
JY
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
2ed65824
JY
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
88266859
JY
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
31d060d9
JY
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
88266859
JY
353/**\r
354 Verify Microcode.\r
355\r
356 Caution: This function may receive untrusted input.\r
357\r
31d060d9
JY
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
88266859
JY
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
31d060d9
JY
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
88266859
JY
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
31d060d9 392 PROCESSOR_INFO *ProcessorInfo;\r
88266859
JY
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
1db271df 424 // Check TotalSize\r
88266859
JY
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
1db271df
SZ
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
88266859
JY
447 if (TotalSize != ImageSize) {\r
448 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on TotalSize\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
1db271df 456 // Check DataSize\r
88266859
JY
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
1db271df 472 DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize is not multiples of DWORDs\n"));\r
88266859
JY
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
1db271df
SZ
479 //\r
480 // Check CheckSum32\r
481 //\r
88266859
JY
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
31d060d9
JY
495\r
496 ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);\r
497 if (ProcessorInfo == NULL) {\r
498 CorrectMicrocode = FALSE;\r
88266859
JY
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
3bd91ae2 508 if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) == 0)) {\r
88266859
JY
509 CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);\r
510 if (CheckSum32 == 0) {\r
511 //\r
512 // Checksum correct\r
513 //\r
514 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
515 if (ExtendedTableCount <= (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {\r
516 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);\r
517 for (Index = 0; Index < ExtendedTableCount; Index++) {\r
518 CheckSum32 = CalculateSum32((UINT32 *)ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));\r
519 if (CheckSum32 == 0) {\r
520 //\r
521 // Verify Header\r
522 //\r
31d060d9
JY
523 ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);\r
524 if (ProcessorInfo != NULL) {\r
88266859
JY
525 //\r
526 // Find one\r
527 //\r
528 CorrectMicrocode = TRUE;\r
529 break;\r
530 }\r
531 }\r
532 ExtendedTable++;\r
533 }\r
534 }\r
535 }\r
536 }\r
537 }\r
538 if (!CorrectMicrocode) {\r
2ed65824
JY
539 if (TryLoad) {\r
540 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));\r
541 }\r
88266859
JY
542 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
543 if (AbortReason != NULL) {\r
31d060d9 544 *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature/ProcessorFlags"), L"UnsupportedProcessSignature/ProcessorFlags");\r
88266859
JY
545 }\r
546 return EFI_UNSUPPORTED;\r
547 }\r
548 }\r
549\r
550 //\r
551 // Check UpdateRevision\r
552 //\r
31d060d9
JY
553 CurrentRevision = ProcessorInfo->MicrocodeRevision;\r
554 if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||\r
555 (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {\r
2ed65824
JY
556 if (TryLoad) {\r
557 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));\r
558 }\r
88266859
JY
559 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
560 if (AbortReason != NULL) {\r
561 *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");\r
562 }\r
563 return EFI_INCOMPATIBLE_VERSION;\r
564 }\r
565\r
566 //\r
567 // try load MCU\r
568 //\r
569 if (TryLoad) {\r
31d060d9 570 CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));\r
88266859
JY
571 if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {\r
572 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));\r
573 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
574 if (AbortReason != NULL) {\r
575 *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");\r
576 }\r
577 return EFI_SECURITY_VIOLATION;\r
578 }\r
579 }\r
580\r
581 return EFI_SUCCESS;\r
582}\r
583\r
2ed65824
JY
584/**\r
585 Get next Microcode entrypoint.\r
88266859 586\r
2ed65824
JY
587 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
588 @param[in] MicrocodeEntryPoint Current Microcode entrypoint\r
589\r
590 @return next Microcode entrypoint.\r
591**/\r
592CPU_MICROCODE_HEADER *\r
593GetNextMicrocode (\r
594 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
595 IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint\r
596 )\r
597{\r
598 UINTN Index;\r
599\r
600 for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {\r
601 if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {\r
602 if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {\r
603 // it is last one\r
604 return NULL;\r
88266859 605 } else {\r
2ed65824
JY
606 // return next one\r
607 return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;\r
88266859 608 }\r
88266859 609 }\r
2ed65824 610 }\r
88266859 611\r
2ed65824 612 ASSERT(FALSE);\r
88266859
JY
613 return NULL;\r
614}\r
615\r
616/**\r
617 Get current Microcode used region size.\r
618\r
2ed65824
JY
619 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
620\r
88266859
JY
621 @return current Microcode used region size.\r
622**/\r
623UINTN\r
624GetCurrentMicrocodeUsedRegionSize (\r
2ed65824 625 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
88266859
JY
626 )\r
627{\r
2ed65824 628 if (MicrocodeFmpPrivate->DescriptorCount == 0) {\r
88266859
JY
629 return 0;\r
630 }\r
88266859 631\r
2ed65824
JY
632 return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint\r
633 + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize\r
634 - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;\r
88266859
JY
635}\r
636\r
637/**\r
638 Update Microcode.\r
639\r
640 @param[in] Address The flash address of Microcode.\r
641 @param[in] Image The Microcode image buffer.\r
642 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
643 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
644\r
645 @retval EFI_SUCCESS The Microcode image is updated.\r
646 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
647**/\r
648EFI_STATUS\r
649UpdateMicrocode (\r
650 IN UINT64 Address,\r
651 IN VOID *Image,\r
652 IN UINTN ImageSize,\r
653 OUT UINT32 *LastAttemptStatus\r
654 )\r
655{\r
656 EFI_STATUS Status;\r
657\r
658 DEBUG((DEBUG_INFO, "PlatformUpdate:"));\r
659 DEBUG((DEBUG_INFO, " Address - 0x%lx,", Address));\r
660 DEBUG((DEBUG_INFO, " Legnth - 0x%x\n", ImageSize));\r
661\r
662 Status = MicrocodeFlashWrite (\r
663 Address,\r
664 Image,\r
665 ImageSize\r
666 );\r
667 if (!EFI_ERROR(Status)) {\r
668 *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
669 } else {\r
670 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
671 }\r
672 return Status;\r
673}\r
674\r
675/**\r
2ed65824 676 Update Microcode flash region.\r
88266859 677\r
2ed65824 678 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
31d060d9 679 @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated\r
2ed65824
JY
680 @param[in] Image The Microcode image buffer.\r
681 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
682 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
88266859 683\r
2ed65824
JY
684 @retval EFI_SUCCESS The Microcode image is written.\r
685 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
88266859
JY
686**/\r
687EFI_STATUS\r
2ed65824
JY
688UpdateMicrocodeFlashRegion (\r
689 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
31d060d9 690 IN CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint,\r
2ed65824
JY
691 IN VOID *Image,\r
692 IN UINTN ImageSize,\r
693 OUT UINT32 *LastAttemptStatus\r
88266859
JY
694 )\r
695{\r
2ed65824
JY
696 VOID *MicrocodePatchAddress;\r
697 UINTN MicrocodePatchRegionSize;\r
31d060d9 698 UINTN TargetTotalSize;\r
88266859 699 UINTN UsedRegionSize;\r
2ed65824
JY
700 EFI_STATUS Status;\r
701 VOID *MicrocodePatchScratchBuffer;\r
702 UINT8 *ScratchBufferPtr;\r
703 UINTN ScratchBufferSize;\r
704 UINTN RestSize;\r
705 UINTN AvailableSize;\r
706 VOID *NextMicrocodeEntryPoint;\r
707 MICROCODE_INFO *MicrocodeInfo;\r
708 UINTN MicrocodeCount;\r
709 UINTN Index;\r
710\r
711 DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));\r
88266859 712\r
2ed65824
JY
713 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
714 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
715\r
716 MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);\r
717 if (MicrocodePatchScratchBuffer == NULL) {\r
718 DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));\r
719 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
720 return EFI_OUT_OF_RESOURCES;\r
88266859 721 }\r
2ed65824
JY
722 ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
723 ScratchBufferSize = 0;\r
88266859 724\r
2ed65824 725 //\r
31d060d9 726 // Target data collection\r
2ed65824 727 //\r
31d060d9 728 TargetTotalSize = 0;\r
2ed65824
JY
729 AvailableSize = 0;\r
730 NextMicrocodeEntryPoint = NULL;\r
31d060d9
JY
731 if (TargetMicrocodeEntryPoint != NULL) {\r
732 if (TargetMicrocodeEntryPoint->DataSize == 0) {\r
733 TargetTotalSize = 2048;\r
88266859 734 } else {\r
31d060d9 735 TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;\r
88266859 736 }\r
31d060d9
JY
737 DEBUG((DEBUG_INFO, " TargetTotalSize - 0x%x\n", TargetTotalSize));\r
738 NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);\r
2ed65824
JY
739 DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));\r
740 if (NextMicrocodeEntryPoint != NULL) {\r
31d060d9
JY
741 ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
742 AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;\r
2ed65824 743 } else {\r
31d060d9 744 AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;\r
2ed65824
JY
745 }\r
746 DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));\r
747 }\r
31d060d9 748 ASSERT (AvailableSize >= TargetTotalSize);\r
2ed65824
JY
749 UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);\r
750 DEBUG((DEBUG_INFO, " UsedRegionSize - 0x%x\n", UsedRegionSize));\r
31d060d9
JY
751 ASSERT (UsedRegionSize >= TargetTotalSize);\r
752 if (TargetMicrocodeEntryPoint != NULL) {\r
753 ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
2ed65824
JY
754 }\r
755 //\r
756 // Total Size means the Microcode data size.\r
31d060d9 757 // Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.\r
2ed65824
JY
758 //\r
759 // (1)\r
760 // +------+-----------+-----+------+===================+\r
761 // | MCU1 | Microcode | PAD | MCU2 | Empty |\r
762 // +------+-----------+-----+------+===================+\r
763 // | TotalSize |\r
764 // |<-AvailableSize->|\r
765 // |<- UsedRegionSize ->|\r
766 //\r
767 // (2)\r
768 // +------+-----------+===================+\r
769 // | MCU | Microcode | Empty |\r
770 // +------+-----------+===================+\r
771 // | TotalSize |\r
772 // |<- AvailableSize ->|\r
773 // |<-UsedRegionSize->|\r
774 //\r
775\r
776 //\r
777 // Update based on policy\r
778 //\r
779\r
780 //\r
781 // 1. If there is enough space to update old one in situ, replace old microcode in situ.\r
782 //\r
783 if (AvailableSize >= ImageSize) {\r
784 DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
785 //\r
786 // +------+------------+------+===================+\r
787 // |Other1| Old Image |Other2| Empty |\r
788 // +------+------------+------+===================+\r
789 //\r
790 // +------+---------+--+------+===================+\r
791 // |Other1|New Image|FF|Other2| Empty |\r
792 // +------+---------+--+------+===================+\r
793 //\r
794 // 1.1. Copy new image\r
795 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
796 ScratchBufferSize += ImageSize;\r
31d060d9 797 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
798 // 1.2. Pad 0xFF\r
799 RestSize = AvailableSize - ImageSize;\r
800 if (RestSize > 0) {\r
801 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
802 ScratchBufferSize += RestSize;\r
31d060d9 803 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824 804 }\r
31d060d9 805 Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
2ed65824 806 return Status;\r
88266859
JY
807 }\r
808\r
2ed65824
JY
809 //\r
810 // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.\r
811 //\r
31d060d9
JY
812 if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {\r
813 if (TargetMicrocodeEntryPoint == NULL) {\r
2ed65824
JY
814 DEBUG((DEBUG_INFO, "Append new microcode\n"));\r
815 //\r
816 // +------+------------+------+===================+\r
817 // |Other1| Other |Other2| Empty |\r
818 // +------+------------+------+===================+\r
819 //\r
820 // +------+------------+------+-----------+=======+\r
821 // |Other1| Other |Other2| New Image | Empty |\r
822 // +------+------------+------+-----------+=======+\r
823 //\r
824 Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);\r
825 } else {\r
826 DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));\r
827 //\r
828 // +------+------------+------+===================+\r
829 // |Other1| Old Image |Other2| Empty |\r
830 // +------+------------+------+===================+\r
831 //\r
832 // +------+---------------+------+================+\r
833 // |Other1| New Image |Other2| Empty |\r
834 // +------+---------------+------+================+\r
835 //\r
836 // 2.1. Copy new image\r
31d060d9 837 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
2ed65824 838 ScratchBufferSize += ImageSize;\r
31d060d9 839 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
840 // 2.2. Copy rest images after the old image.\r
841 if (NextMicrocodeEntryPoint != 0) {\r
842 RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);\r
31d060d9 843 CopyMem (ScratchBufferPtr, (UINT8 *)TargetMicrocodeEntryPoint + TargetTotalSize, RestSize);\r
2ed65824 844 ScratchBufferSize += RestSize;\r
31d060d9 845 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824 846 }\r
31d060d9 847 Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
2ed65824
JY
848 }\r
849 return Status;\r
850 }\r
851\r
852 //\r
853 // 3. The new image can be put in MCU region, but not all others can be put.\r
854 // So all the unused MCU is removed.\r
855 //\r
856 if (MicrocodePatchRegionSize >= ImageSize) {\r
857 //\r
858 // +------+------------+------+===================+\r
859 // |Other1| Old Image |Other2| Empty |\r
860 // +------+------------+------+===================+\r
861 //\r
862 // +-------------------------------------+--------+\r
863 // | New Image | Other |\r
864 // +-------------------------------------+--------+\r
865 //\r
866 DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));\r
867\r
868 MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;\r
869 MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;\r
870\r
871 // 3.1. Copy new image\r
31d060d9 872 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
2ed65824 873 ScratchBufferSize += ImageSize;\r
31d060d9 874 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
875 // 3.2. Copy some others to rest buffer\r
876 for (Index = 0; Index < MicrocodeCount; Index++) {\r
877 if (!MicrocodeInfo[Index].InUse) {\r
878 continue;\r
879 }\r
31d060d9 880 if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {\r
2ed65824
JY
881 continue;\r
882 }\r
883 if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {\r
884 CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);\r
885 ScratchBufferSize += MicrocodeInfo[Index].TotalSize;\r
31d060d9 886 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
887 }\r
888 }\r
889 // 3.3. Pad 0xFF\r
890 RestSize = MicrocodePatchRegionSize - ScratchBufferSize;\r
891 if (RestSize > 0) {\r
892 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
893 ScratchBufferSize += RestSize;\r
31d060d9 894 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
895 }\r
896 Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
897 return Status;\r
898 }\r
899\r
900 //\r
901 // 4. The new image size is bigger than the whole MCU region.\r
902 //\r
903 DEBUG((DEBUG_ERROR, "Microcode too big\n"));\r
904 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
905 Status = EFI_OUT_OF_RESOURCES;\r
906\r
907 return Status;\r
908}\r
909\r
910/**\r
911 Write Microcode.\r
912\r
913 Caution: This function may receive untrusted input.\r
914\r
915 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
916 @param[in] Image The Microcode image buffer.\r
917 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
918 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
919 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
920 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more\r
921 details for the aborted operation. The buffer is allocated by this function\r
922 with AllocatePool(), and it is the caller's responsibility to free it with a\r
923 call to FreePool().\r
924\r
925 @retval EFI_SUCCESS The Microcode image is written.\r
926 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.\r
927 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.\r
928 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.\r
929 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
930**/\r
931EFI_STATUS\r
932MicrocodeWrite (\r
933 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
934 IN VOID *Image,\r
935 IN UINTN ImageSize,\r
936 OUT UINT32 *LastAttemptVersion,\r
937 OUT UINT32 *LastAttemptStatus,\r
938 OUT CHAR16 **AbortReason\r
939 )\r
940{\r
941 EFI_STATUS Status;\r
942 VOID *AlignedImage;\r
31d060d9
JY
943 CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint;\r
944 UINTN TargetCpuIndex;\r
945 UINTN TargetMicrcodeIndex;\r
2ed65824 946\r
88266859
JY
947 //\r
948 // MCU must be 16 bytes aligned\r
949 //\r
950 AlignedImage = AllocateCopyPool(ImageSize, Image);\r
951 if (AlignedImage == NULL) {\r
952 DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));\r
953 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
954 return EFI_OUT_OF_RESOURCES;\r
955 }\r
956\r
957 *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;\r
31d060d9
JY
958 TargetCpuIndex = (UINTN)-1;\r
959 Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);\r
88266859
JY
960 if (EFI_ERROR(Status)) {\r
961 DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));\r
962 FreePool(AlignedImage);\r
963 return Status;\r
964 }\r
965 DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));\r
966\r
31d060d9
JY
967 DEBUG((DEBUG_INFO, " TargetCpuIndex - 0x%x\n", TargetCpuIndex));\r
968 ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
969 TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;\r
970 DEBUG((DEBUG_INFO, " TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));\r
971 if (TargetMicrcodeIndex != (UINTN)-1) {\r
972 ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);\r
973 TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;\r
974 } else {\r
975 TargetMicrocodeEntryPoint = NULL;\r
976 }\r
977 DEBUG((DEBUG_INFO, " TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));\r
978\r
2ed65824
JY
979 Status = UpdateMicrocodeFlashRegion(\r
980 MicrocodeFmpPrivate,\r
31d060d9 981 TargetMicrocodeEntryPoint,\r
2ed65824
JY
982 AlignedImage,\r
983 ImageSize,\r
984 LastAttemptStatus\r
985 );\r
88266859
JY
986\r
987 FreePool(AlignedImage);\r
988\r
989 return Status;\r
990}\r
991\r
992\r