]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
IntelSiliconPkg: Replace BSD License with BSD+Patent License
[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
8f7a05e1 12 SPDX-License-Identifier: BSD-2-Clause-Patent\r
88266859
JY
13\r
14**/\r
15\r
16#include "MicrocodeUpdate.h"\r
17\r
18/**\r
19 Get Microcode Region.\r
20\r
21 @param[out] MicrocodePatchAddress The address of Microcode\r
22 @param[out] MicrocodePatchRegionSize The region size of Microcode\r
23\r
24 @retval TRUE The Microcode region is returned.\r
25 @retval FALSE No Microcode region.\r
26**/\r
27BOOLEAN\r
28GetMicrocodeRegion (\r
2ed65824
JY
29 OUT VOID **MicrocodePatchAddress,\r
30 OUT UINTN *MicrocodePatchRegionSize\r
88266859
JY
31 )\r
32{\r
2ed65824
JY
33 *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);\r
34 *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);\r
88266859 35\r
2ed65824 36 if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {\r
88266859
JY
37 return FALSE;\r
38 }\r
39\r
40 return TRUE;\r
41}\r
42\r
43/**\r
44 Get Microcode update signature of currently loaded Microcode update.\r
45\r
46 @return Microcode signature.\r
47\r
48**/\r
49UINT32\r
50GetCurrentMicrocodeSignature (\r
51 VOID\r
52 )\r
53{\r
54 UINT64 Signature;\r
55\r
56 AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0);\r
57 AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
58 Signature = AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID);\r
59 return (UINT32)RShiftU64(Signature, 32);\r
60}\r
61\r
62/**\r
63 Get current processor signature.\r
64\r
65 @return current processor signature.\r
66**/\r
67UINT32\r
68GetCurrentProcessorSignature (\r
69 VOID\r
70 )\r
71{\r
72 UINT32 RegEax;\r
73 AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);\r
74 return RegEax;\r
75}\r
76\r
77/**\r
78 Get current platform ID.\r
79\r
80 @return current platform ID.\r
81**/\r
82UINT8\r
83GetCurrentPlatformId (\r
84 VOID\r
85 )\r
86{\r
87 UINT8 PlatformId;\r
88\r
89 PlatformId = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52);\r
90 return PlatformId;\r
91}\r
92\r
93/**\r
94 Load new Microcode.\r
95\r
96 @param[in] Address The address of new Microcode.\r
97\r
98 @return Loaded Microcode signature.\r
99\r
100**/\r
101UINT32\r
102LoadMicrocode (\r
103 IN UINT64 Address\r
104 )\r
105{\r
106 AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address);\r
107 return GetCurrentMicrocodeSignature();\r
108}\r
109\r
2ed65824 110/**\r
31d060d9
JY
111 Load Microcode on an Application Processor.\r
112 The function prototype for invoking a function on an Application Processor.\r
113\r
114 @param[in,out] Buffer The pointer to private data buffer.\r
115**/\r
116VOID\r
117EFIAPI\r
118MicrocodeLoadAp (\r
119 IN OUT VOID *Buffer\r
120 )\r
121{\r
122 MICROCODE_LOAD_BUFFER *MicrocodeLoadBuffer;\r
123\r
124 MicrocodeLoadBuffer = Buffer;\r
125 MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);\r
126}\r
127\r
128/**\r
129 Load new Microcode on this processor\r
2ed65824 130\r
31d060d9
JY
131 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
132 @param[in] CpuIndex The index of the processor.\r
133 @param[in] Address The address of new Microcode.\r
134\r
135 @return Loaded Microcode signature.\r
2ed65824 136\r
2ed65824 137**/\r
31d060d9
JY
138UINT32\r
139LoadMicrocodeOnThis (\r
140 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
141 IN UINTN CpuIndex,\r
142 IN UINT64 Address\r
2ed65824
JY
143 )\r
144{\r
31d060d9
JY
145 EFI_STATUS Status;\r
146 EFI_MP_SERVICES_PROTOCOL *MpService;\r
147 MICROCODE_LOAD_BUFFER MicrocodeLoadBuffer;\r
2ed65824 148\r
31d060d9
JY
149 if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {\r
150 return LoadMicrocode (Address);\r
151 } else {\r
152 MpService = MicrocodeFmpPrivate->MpService;\r
153 MicrocodeLoadBuffer.Address = Address;\r
154 MicrocodeLoadBuffer.Revision = 0;\r
155 Status = MpService->StartupThisAP (\r
156 MpService,\r
157 MicrocodeLoadAp,\r
158 CpuIndex,\r
159 NULL,\r
160 0,\r
161 &MicrocodeLoadBuffer,\r
162 NULL\r
163 );\r
164 ASSERT_EFI_ERROR(Status);\r
165 return MicrocodeLoadBuffer.Revision;\r
2ed65824 166 }\r
31d060d9
JY
167}\r
168\r
169/**\r
170 Collect processor information.\r
171 The function prototype for invoking a function on an Application Processor.\r
172\r
173 @param[in,out] Buffer The pointer to private data buffer.\r
174**/\r
175VOID\r
176EFIAPI\r
177CollectProcessorInfo (\r
178 IN OUT VOID *Buffer\r
179 )\r
180{\r
181 PROCESSOR_INFO *ProcessorInfo;\r
182\r
183 ProcessorInfo = Buffer;\r
184 ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();\r
185 ProcessorInfo->PlatformId = GetCurrentPlatformId();\r
186 ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();\r
2ed65824
JY
187}\r
188\r
88266859
JY
189/**\r
190 Get current Microcode information.\r
191\r
31d060d9
JY
192 The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)\r
193 in MicrocodeFmpPrivate must be initialized.\r
194\r
195 The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)\r
196 in MicrocodeFmpPrivate may not be avaiable in this function.\r
2ed65824
JY
197\r
198 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
199 @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated.\r
200 @param[out] ImageDescriptor Microcode ImageDescriptor\r
201 @param[out] MicrocodeInfo Microcode information\r
88266859
JY
202\r
203 @return Microcode count\r
204**/\r
205UINTN\r
206GetMicrocodeInfo (\r
2ed65824
JY
207 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
208 IN UINTN DescriptorCount, OPTIONAL\r
88266859 209 OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL\r
2ed65824 210 OUT MICROCODE_INFO *MicrocodeInfo OPTIONAL\r
88266859
JY
211 )\r
212{\r
2ed65824
JY
213 VOID *MicrocodePatchAddress;\r
214 UINTN MicrocodePatchRegionSize;\r
88266859
JY
215 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
216 UINTN MicrocodeEnd;\r
217 UINTN TotalSize;\r
218 UINTN Count;\r
219 UINT64 ImageAttributes;\r
2ed65824 220 BOOLEAN IsInUse;\r
31d060d9
JY
221 EFI_STATUS Status;\r
222 UINT32 AttemptStatus;\r
223 UINTN TargetCpuIndex;\r
88266859 224\r
2ed65824
JY
225 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
226 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
227\r
228 DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));\r
88266859
JY
229\r
230 Count = 0;\r
88266859 231\r
2ed65824 232 MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;\r
88266859
JY
233 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;\r
234 do {\r
235 if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {\r
236 //\r
237 // It is the microcode header. It is not the padding data between microcode patches\r
238 // becasue the padding data should not include 0x00000001 and it should be the repeated\r
239 // byte format (like 0xXYXYXYXY....).\r
240 //\r
241 if (MicrocodeEntryPoint->DataSize == 0) {\r
242 TotalSize = 2048;\r
243 } else {\r
244 TotalSize = MicrocodeEntryPoint->TotalSize;\r
245 }\r
246\r
31d060d9
JY
247 TargetCpuIndex = (UINTN)-1;\r
248 Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);\r
249 if (!EFI_ERROR(Status)) {\r
250 IsInUse = TRUE;\r
251 ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
252 MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;\r
253 } else {\r
254 IsInUse = FALSE;\r
255 }\r
2ed65824 256\r
88266859
JY
257 if (ImageDescriptor != NULL && DescriptorCount > Count) {\r
258 ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);\r
259 CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);\r
260 ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
261 ImageDescriptor[Count].ImageIdName = NULL;\r
262 ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision;\r
263 ImageDescriptor[Count].VersionName = NULL;\r
264 ImageDescriptor[Count].Size = TotalSize;\r
265 ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;\r
2ed65824 266 if (IsInUse) {\r
88266859
JY
267 ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;\r
268 }\r
269 ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;\r
270 ImageDescriptor[Count].AttributesSetting = ImageAttributes;\r
271 ImageDescriptor[Count].Compatibilities = 0;\r
272 ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback\r
273 ImageDescriptor[Count].LastAttemptVersion = 0;\r
274 ImageDescriptor[Count].LastAttemptStatus = 0;\r
275 ImageDescriptor[Count].HardwareInstance = 0;\r
276 }\r
2ed65824
JY
277 if (MicrocodeInfo != NULL && DescriptorCount > Count) {\r
278 MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;\r
279 MicrocodeInfo[Count].TotalSize = TotalSize;\r
280 MicrocodeInfo[Count].InUse = IsInUse;\r
281 }\r
88266859
JY
282 } else {\r
283 //\r
284 // It is the padding data between the microcode patches for microcode patches alignment.\r
285 // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
286 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
287 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
288 // find the next possible microcode patch header.\r
289 //\r
290 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
291 continue;\r
292 }\r
293\r
294 Count++;\r
295 ASSERT(Count < 0xFF);\r
296\r
297 //\r
298 // Get the next patch.\r
299 //\r
300 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
301 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
302\r
303 return Count;\r
304}\r
305\r
31d060d9
JY
306/**\r
307 Return matched processor information.\r
308\r
309 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
310 @param[in] ProcessorSignature The processor signature to be matched\r
311 @param[in] ProcessorFlags The processor flags to be matched\r
312 @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.\r
313 On output, the index of target CPU which matches the Microcode.\r
314\r
315 @return matched processor information.\r
316**/\r
317PROCESSOR_INFO *\r
318GetMatchedProcessor (\r
319 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
320 IN UINT32 ProcessorSignature,\r
321 IN UINT32 ProcessorFlags,\r
322 IN OUT UINTN *TargetCpuIndex\r
323 )\r
324{\r
325 UINTN Index;\r
326\r
327 if (*TargetCpuIndex != (UINTN)-1) {\r
328 Index = *TargetCpuIndex;\r
329 if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&\r
330 ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {\r
331 return &MicrocodeFmpPrivate->ProcessorInfo[Index];\r
332 } else {\r
333 return NULL;\r
334 }\r
335 }\r
336\r
337 for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {\r
338 if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&\r
339 ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {\r
340 *TargetCpuIndex = Index;\r
341 return &MicrocodeFmpPrivate->ProcessorInfo[Index];\r
342 }\r
343 }\r
344 return NULL;\r
345}\r
346\r
88266859
JY
347/**\r
348 Verify Microcode.\r
349\r
350 Caution: This function may receive untrusted input.\r
351\r
31d060d9
JY
352 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
353 @param[in] Image The Microcode image buffer.\r
354 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
355 @param[in] TryLoad Try to load Microcode or not.\r
356 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
357 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more\r
358 details for the aborted operation. The buffer is allocated by this function\r
359 with AllocatePool(), and it is the caller's responsibility to free it with a\r
360 call to FreePool().\r
361 @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.\r
362 On output, the index of target CPU which matches the Microcode.\r
88266859
JY
363\r
364 @retval EFI_SUCCESS The Microcode image passes verification.\r
e9179788 365 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupted.\r
88266859
JY
366 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.\r
367 @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.\r
368 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.\r
369**/\r
370EFI_STATUS\r
371VerifyMicrocode (\r
31d060d9
JY
372 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
373 IN VOID *Image,\r
374 IN UINTN ImageSize,\r
375 IN BOOLEAN TryLoad,\r
376 OUT UINT32 *LastAttemptStatus,\r
377 OUT CHAR16 **AbortReason, OPTIONAL\r
378 IN OUT UINTN *TargetCpuIndex\r
88266859
JY
379 )\r
380{\r
381 UINTN Index;\r
382 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
383 UINTN TotalSize;\r
384 UINTN DataSize;\r
385 UINT32 CurrentRevision;\r
31d060d9 386 PROCESSOR_INFO *ProcessorInfo;\r
5170327b 387 UINT32 InCompleteCheckSum32;\r
88266859
JY
388 UINT32 CheckSum32;\r
389 UINTN ExtendedTableLength;\r
390 UINT32 ExtendedTableCount;\r
391 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
392 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
393 BOOLEAN CorrectMicrocode;\r
394\r
395 //\r
396 // Check HeaderVersion\r
397 //\r
398 MicrocodeEntryPoint = Image;\r
399 if (MicrocodeEntryPoint->HeaderVersion != 0x1) {\r
400 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n"));\r
401 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
402 if (AbortReason != NULL) {\r
403 *AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion");\r
404 }\r
405 return EFI_INCOMPATIBLE_VERSION;\r
406 }\r
407 //\r
408 // Check LoaderRevision\r
409 //\r
410 if (MicrocodeEntryPoint->LoaderRevision != 0x1) {\r
411 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n"));\r
412 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
413 if (AbortReason != NULL) {\r
414 *AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion");\r
415 }\r
416 return EFI_INCOMPATIBLE_VERSION;\r
417 }\r
418 //\r
1db271df 419 // Check TotalSize\r
88266859
JY
420 //\r
421 if (MicrocodeEntryPoint->DataSize == 0) {\r
422 TotalSize = 2048;\r
423 } else {\r
424 TotalSize = MicrocodeEntryPoint->TotalSize;\r
425 }\r
426 if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) {\r
427 DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n"));\r
428 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
429 if (AbortReason != NULL) {\r
430 *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
431 }\r
432 return EFI_VOLUME_CORRUPTED;\r
433 }\r
1db271df
SZ
434 if ((TotalSize & (SIZE_1KB - 1)) != 0) {\r
435 DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize is not multiples of 1024 bytes (1 KBytes)\n"));\r
436 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
437 if (AbortReason != NULL) {\r
438 *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
439 }\r
440 return EFI_VOLUME_CORRUPTED;\r
441 }\r
88266859 442 if (TotalSize != ImageSize) {\r
2ad34f65 443 DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize not equal to ImageSize\n"));\r
88266859
JY
444 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
445 if (AbortReason != NULL) {\r
446 *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
447 }\r
448 return EFI_VOLUME_CORRUPTED;\r
449 }\r
450 //\r
1db271df 451 // Check DataSize\r
88266859
JY
452 //\r
453 if (MicrocodeEntryPoint->DataSize == 0) {\r
454 DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);\r
455 } else {\r
456 DataSize = MicrocodeEntryPoint->DataSize;\r
457 }\r
458 if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) {\r
459 DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n"));\r
460 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
461 if (AbortReason != NULL) {\r
462 *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
463 }\r
464 return EFI_VOLUME_CORRUPTED;\r
465 }\r
466 if ((DataSize & 0x3) != 0) {\r
1db271df 467 DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize is not multiples of DWORDs\n"));\r
88266859
JY
468 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
469 if (AbortReason != NULL) {\r
470 *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
471 }\r
472 return EFI_VOLUME_CORRUPTED;\r
473 }\r
1db271df
SZ
474 //\r
475 // Check CheckSum32\r
476 //\r
88266859
JY
477 CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));\r
478 if (CheckSum32 != 0) {\r
479 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));\r
480 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
481 if (AbortReason != NULL) {\r
482 *AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum");\r
483 }\r
484 return EFI_VOLUME_CORRUPTED;\r
485 }\r
5170327b
CC
486 InCompleteCheckSum32 = CheckSum32;\r
487 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
488 InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;\r
489 InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;\r
88266859
JY
490\r
491 //\r
492 // Check ProcessorSignature/ProcessorFlags\r
493 //\r
31d060d9
JY
494\r
495 ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);\r
496 if (ProcessorInfo == NULL) {\r
497 CorrectMicrocode = FALSE;\r
88266859
JY
498 ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER));\r
499 if (ExtendedTableLength != 0) {\r
500 //\r
501 // Extended Table exist, check if the CPU in support list\r
502 //\r
503 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER));\r
504 //\r
505 // Calculate Extended Checksum\r
506 //\r
3bd91ae2 507 if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) == 0)) {\r
88266859 508 CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);\r
2ad34f65
HW
509 if (CheckSum32 != 0) {\r
510 //\r
511 // Checksum incorrect\r
512 //\r
513 DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for extended table is incorrect\n"));\r
514 } else {\r
88266859
JY
515 //\r
516 // Checksum correct\r
517 //\r
518 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
2ad34f65 519 if (ExtendedTableCount > (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {\r
f635b138 520 DEBUG((DEBUG_ERROR, "VerifyMicrocode - ExtendedTableCount %d is too big\n", ExtendedTableCount));\r
2ad34f65 521 } else {\r
88266859
JY
522 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);\r
523 for (Index = 0; Index < ExtendedTableCount; Index++) {\r
5170327b
CC
524 CheckSum32 = InCompleteCheckSum32;\r
525 CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;\r
526 CheckSum32 += ExtendedTable->ProcessorFlag;\r
527 CheckSum32 += ExtendedTable->Checksum;\r
2ad34f65
HW
528 if (CheckSum32 != 0) {\r
529 DEBUG((DEBUG_ERROR, "VerifyMicrocode - The checksum for ExtendedTable entry with index 0x%x is incorrect\n", Index));\r
530 } else {\r
88266859
JY
531 //\r
532 // Verify Header\r
533 //\r
31d060d9
JY
534 ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);\r
535 if (ProcessorInfo != NULL) {\r
88266859
JY
536 //\r
537 // Find one\r
538 //\r
539 CorrectMicrocode = TRUE;\r
540 break;\r
541 }\r
542 }\r
543 ExtendedTable++;\r
544 }\r
545 }\r
546 }\r
547 }\r
548 }\r
549 if (!CorrectMicrocode) {\r
2ed65824 550 if (TryLoad) {\r
2ad34f65 551 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on Current ProcessorSignature/ProcessorFlags\n"));\r
2ed65824 552 }\r
88266859
JY
553 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
554 if (AbortReason != NULL) {\r
e9179788 555 *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessorSignature/ProcessorFlags"), L"UnsupportedProcessorSignature/ProcessorFlags");\r
88266859
JY
556 }\r
557 return EFI_UNSUPPORTED;\r
558 }\r
559 }\r
560\r
561 //\r
562 // Check UpdateRevision\r
563 //\r
31d060d9
JY
564 CurrentRevision = ProcessorInfo->MicrocodeRevision;\r
565 if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||\r
566 (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {\r
2ed65824
JY
567 if (TryLoad) {\r
568 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));\r
569 }\r
88266859
JY
570 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
571 if (AbortReason != NULL) {\r
572 *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");\r
573 }\r
574 return EFI_INCOMPATIBLE_VERSION;\r
575 }\r
576\r
577 //\r
578 // try load MCU\r
579 //\r
580 if (TryLoad) {\r
31d060d9 581 CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));\r
88266859
JY
582 if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {\r
583 DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));\r
584 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
585 if (AbortReason != NULL) {\r
586 *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");\r
587 }\r
588 return EFI_SECURITY_VIOLATION;\r
589 }\r
590 }\r
591\r
592 return EFI_SUCCESS;\r
593}\r
594\r
2ed65824
JY
595/**\r
596 Get next Microcode entrypoint.\r
88266859 597\r
2ed65824
JY
598 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
599 @param[in] MicrocodeEntryPoint Current Microcode entrypoint\r
600\r
601 @return next Microcode entrypoint.\r
602**/\r
603CPU_MICROCODE_HEADER *\r
604GetNextMicrocode (\r
605 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
606 IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint\r
607 )\r
608{\r
609 UINTN Index;\r
610\r
611 for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {\r
612 if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {\r
613 if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {\r
614 // it is last one\r
615 return NULL;\r
88266859 616 } else {\r
2ed65824
JY
617 // return next one\r
618 return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;\r
88266859 619 }\r
88266859 620 }\r
2ed65824 621 }\r
88266859 622\r
2ed65824 623 ASSERT(FALSE);\r
88266859
JY
624 return NULL;\r
625}\r
626\r
e9179788
SZ
627/**\r
628 Get next FIT Microcode entrypoint.\r
629\r
630 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
631 @param[in] MicrocodeEntryPoint Current Microcode entrypoint\r
632\r
633 @return next FIT Microcode entrypoint.\r
634**/\r
635CPU_MICROCODE_HEADER *\r
636GetNextFitMicrocode (\r
637 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
638 IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint\r
639 )\r
640{\r
641 UINTN Index;\r
642\r
643 for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
644 if (MicrocodeEntryPoint == MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint) {\r
645 if (Index == (UINTN) MicrocodeFmpPrivate->FitMicrocodeEntryCount - 1) {\r
646 // it is last one\r
647 return NULL;\r
648 } else {\r
649 // return next one\r
650 return MicrocodeFmpPrivate->FitMicrocodeInfo[Index + 1].MicrocodeEntryPoint;\r
651 }\r
652 }\r
653 }\r
654\r
655 ASSERT(FALSE);\r
656 return NULL;\r
657}\r
658\r
659/**\r
660 Find empty FIT Microcode entrypoint.\r
661\r
662 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
663 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
664 @param[out] AvailableSize Available size of the empty FIT Microcode entrypoint.\r
665\r
666 @return Empty FIT Microcode entrypoint.\r
667**/\r
668CPU_MICROCODE_HEADER *\r
669FindEmptyFitMicrocode (\r
670 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
671 IN UINTN ImageSize,\r
672 OUT UINTN *AvailableSize\r
673 )\r
674{\r
675 UINTN Index;\r
676 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
677 CPU_MICROCODE_HEADER *NextMicrocodeEntryPoint;\r
678 VOID *MicrocodePatchAddress;\r
679 UINTN MicrocodePatchRegionSize;\r
680\r
681 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
682 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
683\r
684 for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
685 if (MicrocodeFmpPrivate->FitMicrocodeInfo[Index].Empty) {\r
686 MicrocodeEntryPoint = MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint;\r
687 NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, MicrocodeEntryPoint);\r
688 if (NextMicrocodeEntryPoint != NULL) {\r
689 *AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) MicrocodeEntryPoint;\r
690 } else {\r
691 *AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) MicrocodeEntryPoint;\r
692 }\r
693 if (*AvailableSize >= ImageSize) {\r
694 return MicrocodeEntryPoint;\r
695 }\r
696 }\r
697 }\r
698\r
699 return NULL;\r
700}\r
701\r
702/**\r
703 Find unused FIT Microcode entrypoint.\r
704\r
705 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
706 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
707 @param[out] AvailableSize Available size of the unused FIT Microcode entrypoint.\r
708\r
709 @return Unused FIT Microcode entrypoint.\r
710**/\r
711CPU_MICROCODE_HEADER *\r
712FindUnusedFitMicrocode (\r
713 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
714 IN UINTN ImageSize,\r
715 OUT UINTN *AvailableSize\r
716 )\r
717{\r
718 UINTN Index;\r
719 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
720 CPU_MICROCODE_HEADER *NextMicrocodeEntryPoint;\r
721 VOID *MicrocodePatchAddress;\r
722 UINTN MicrocodePatchRegionSize;\r
723\r
724 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
725 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
726\r
727 for (Index = 0; Index < MicrocodeFmpPrivate->FitMicrocodeEntryCount; Index++) {\r
728 if (!MicrocodeFmpPrivate->FitMicrocodeInfo[Index].InUse) {\r
729 MicrocodeEntryPoint = MicrocodeFmpPrivate->FitMicrocodeInfo[Index].MicrocodeEntryPoint;\r
730 NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, MicrocodeEntryPoint);\r
731 if (NextMicrocodeEntryPoint != NULL) {\r
732 *AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) MicrocodeEntryPoint;\r
733 } else {\r
734 *AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) MicrocodeEntryPoint;\r
735 }\r
736 if (*AvailableSize >= ImageSize) {\r
737 return MicrocodeEntryPoint;\r
738 }\r
739 }\r
740 }\r
741\r
742 return NULL;\r
743}\r
744\r
88266859
JY
745/**\r
746 Get current Microcode used region size.\r
747\r
2ed65824
JY
748 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
749\r
88266859
JY
750 @return current Microcode used region size.\r
751**/\r
752UINTN\r
753GetCurrentMicrocodeUsedRegionSize (\r
2ed65824 754 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate\r
88266859
JY
755 )\r
756{\r
2ed65824 757 if (MicrocodeFmpPrivate->DescriptorCount == 0) {\r
88266859
JY
758 return 0;\r
759 }\r
88266859 760\r
2ed65824
JY
761 return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint\r
762 + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize\r
763 - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;\r
88266859
JY
764}\r
765\r
766/**\r
767 Update Microcode.\r
768\r
769 @param[in] Address The flash address of Microcode.\r
770 @param[in] Image The Microcode image buffer.\r
771 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
772 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
773\r
774 @retval EFI_SUCCESS The Microcode image is updated.\r
775 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
776**/\r
777EFI_STATUS\r
778UpdateMicrocode (\r
779 IN UINT64 Address,\r
780 IN VOID *Image,\r
781 IN UINTN ImageSize,\r
782 OUT UINT32 *LastAttemptStatus\r
783 )\r
784{\r
785 EFI_STATUS Status;\r
786\r
787 DEBUG((DEBUG_INFO, "PlatformUpdate:"));\r
788 DEBUG((DEBUG_INFO, " Address - 0x%lx,", Address));\r
e9179788 789 DEBUG((DEBUG_INFO, " Length - 0x%x\n", ImageSize));\r
88266859
JY
790\r
791 Status = MicrocodeFlashWrite (\r
792 Address,\r
793 Image,\r
794 ImageSize\r
795 );\r
796 if (!EFI_ERROR(Status)) {\r
797 *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
798 } else {\r
799 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
800 }\r
801 return Status;\r
802}\r
803\r
e9179788
SZ
804/**\r
805 Update Microcode flash region with FIT.\r
806\r
807 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
808 @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated\r
809 @param[in] Image The Microcode image buffer.\r
810 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
811 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
812\r
813 @retval EFI_SUCCESS The Microcode image is written.\r
814 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
815**/\r
816EFI_STATUS\r
817UpdateMicrocodeFlashRegionWithFit (\r
818 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
819 IN CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint,\r
820 IN VOID *Image,\r
821 IN UINTN ImageSize,\r
822 OUT UINT32 *LastAttemptStatus\r
823 )\r
824{\r
825 VOID *MicrocodePatchAddress;\r
826 UINTN MicrocodePatchRegionSize;\r
827 UINTN TargetTotalSize;\r
828 EFI_STATUS Status;\r
829 VOID *MicrocodePatchScratchBuffer;\r
830 UINT8 *ScratchBufferPtr;\r
831 UINTN ScratchBufferSize;\r
832 UINTN RestSize;\r
833 UINTN AvailableSize;\r
834 VOID *NextMicrocodeEntryPoint;\r
835 VOID *EmptyFitMicrocodeEntry;\r
836 VOID *UnusedFitMicrocodeEntry;\r
837\r
838 DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegionWithFit: Image - 0x%x, size - 0x%x\n", Image, ImageSize));\r
839\r
840 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
841 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
842\r
843 MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);\r
844 if (MicrocodePatchScratchBuffer == NULL) {\r
845 DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));\r
846 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
847 return EFI_OUT_OF_RESOURCES;\r
848 }\r
849 ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
850 ScratchBufferSize = 0;\r
851\r
852 //\r
853 // Target data collection\r
854 //\r
855 TargetTotalSize = 0;\r
856 AvailableSize = 0;\r
857 if (TargetMicrocodeEntryPoint != NULL) {\r
858 if (TargetMicrocodeEntryPoint->DataSize == 0) {\r
859 TargetTotalSize = 2048;\r
860 } else {\r
861 TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;\r
862 }\r
863 DEBUG((DEBUG_INFO, " TargetTotalSize - 0x%x\n", TargetTotalSize));\r
864 NextMicrocodeEntryPoint = GetNextFitMicrocode (MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);\r
865 DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));\r
866 if (NextMicrocodeEntryPoint != NULL) {\r
867 ASSERT ((UINTN) NextMicrocodeEntryPoint >= ((UINTN) TargetMicrocodeEntryPoint + TargetTotalSize));\r
868 AvailableSize = (UINTN) NextMicrocodeEntryPoint - (UINTN) TargetMicrocodeEntryPoint;\r
869 } else {\r
870 AvailableSize = (UINTN) MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN) TargetMicrocodeEntryPoint;\r
871 }\r
872 DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));\r
873 ASSERT (AvailableSize >= TargetTotalSize);\r
874 }\r
875 //\r
876 // Total Size means the Microcode size.\r
877 // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.\r
878 //\r
879 // (1)\r
880 // +------+-----------+-----+------+===================+\r
881 // | MCU1 | Microcode | PAD | MCU2 | Empty |\r
882 // +------+-----------+-----+------+===================+\r
883 // | TotalSize |\r
884 // |<-AvailableSize->|\r
885 //\r
886 // (2)\r
887 // +------+-----------+===================+\r
888 // | MCU | Microcode | Empty |\r
889 // +------+-----------+===================+\r
890 // | TotalSize |\r
891 // |<- AvailableSize ->|\r
892 //\r
893\r
894 //\r
895 // Update based on policy\r
896 //\r
897\r
898 //\r
899 // 1. If there is enough space to update old one in situ, replace old microcode in situ.\r
900 //\r
901 if (AvailableSize >= ImageSize) {\r
902 DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
903 //\r
904 // +------+------------+------+===================+\r
905 // |Other | Old Image | ... | Empty |\r
906 // +------+------------+------+===================+\r
907 //\r
908 // +------+---------+--+------+===================+\r
909 // |Other |New Image|FF| ... | Empty |\r
910 // +------+---------+--+------+===================+\r
911 //\r
912 // 1.1. Copy new image\r
913 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
914 ScratchBufferSize += ImageSize;\r
915 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
916 // 1.2. Pad 0xFF\r
917 RestSize = AvailableSize - ImageSize;\r
918 if (RestSize > 0) {\r
919 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
920 ScratchBufferSize += RestSize;\r
921 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
922 }\r
923 Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
924 return Status;\r
925 }\r
926\r
927 //\r
928 // 2. If there is empty FIT microcode entry with enough space, use it.\r
929 //\r
930 EmptyFitMicrocodeEntry = FindEmptyFitMicrocode (MicrocodeFmpPrivate, ImageSize, &AvailableSize);\r
931 if (EmptyFitMicrocodeEntry != NULL) {\r
932 DEBUG((DEBUG_INFO, "Use empty FIT microcode entry\n"));\r
933 // 2.1. Copy new image\r
934 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
935 ScratchBufferSize += ImageSize;\r
936 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
937 // 2.2. Pad 0xFF\r
938 RestSize = AvailableSize - ImageSize;\r
939 if (RestSize > 0) {\r
940 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
941 ScratchBufferSize += RestSize;\r
942 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
943 }\r
944 Status = UpdateMicrocode ((UINTN) EmptyFitMicrocodeEntry, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
945 if (!EFI_ERROR (Status) && (TargetMicrocodeEntryPoint != NULL)) {\r
946 //\r
947 // Empty old microcode.\r
948 //\r
949 ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
950 SetMem (ScratchBufferPtr, TargetTotalSize, 0xFF);\r
951 ScratchBufferSize = TargetTotalSize;\r
952 ScratchBufferPtr = (UINT8 *) MicrocodePatchScratchBuffer + ScratchBufferSize;\r
953 UpdateMicrocode ((UINTN) TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
954 }\r
955 return Status;\r
956 }\r
957\r
958 //\r
959 // 3. If there is unused microcode entry with enough space, use it.\r
960 //\r
961 UnusedFitMicrocodeEntry = FindUnusedFitMicrocode (MicrocodeFmpPrivate, ImageSize, &AvailableSize);\r
962 if (UnusedFitMicrocodeEntry != NULL) {\r
963 DEBUG((DEBUG_INFO, "Use unused FIT microcode entry\n"));\r
964 // 3.1. Copy new image\r
965 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
966 ScratchBufferSize += ImageSize;\r
967 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
968 // 3.2. Pad 0xFF\r
969 RestSize = AvailableSize - ImageSize;\r
970 if (RestSize > 0) {\r
971 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
972 ScratchBufferSize += RestSize;\r
973 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
974 }\r
975 Status = UpdateMicrocode ((UINTN) UnusedFitMicrocodeEntry, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
976 if (!EFI_ERROR (Status) && (TargetMicrocodeEntryPoint != NULL)) {\r
977 //\r
978 // Empty old microcode.\r
979 //\r
980 ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
981 SetMem (ScratchBufferPtr, TargetTotalSize, 0xFF);\r
982 ScratchBufferSize = TargetTotalSize;\r
983 ScratchBufferPtr = (UINT8 *) MicrocodePatchScratchBuffer + ScratchBufferSize;\r
984 UpdateMicrocode ((UINTN) TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
985 }\r
986 return Status;\r
987 }\r
988\r
989 //\r
990 // 4. No usable FIT microcode entry.\r
991 //\r
992 DEBUG((DEBUG_ERROR, "No usable FIT microcode entry\n"));\r
993 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
994 Status = EFI_OUT_OF_RESOURCES;\r
995\r
996 return Status;\r
997}\r
998\r
88266859 999/**\r
2ed65824 1000 Update Microcode flash region.\r
88266859 1001\r
2ed65824 1002 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
31d060d9 1003 @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated\r
2ed65824
JY
1004 @param[in] Image The Microcode image buffer.\r
1005 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
1006 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
88266859 1007\r
2ed65824
JY
1008 @retval EFI_SUCCESS The Microcode image is written.\r
1009 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
88266859
JY
1010**/\r
1011EFI_STATUS\r
2ed65824
JY
1012UpdateMicrocodeFlashRegion (\r
1013 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
31d060d9 1014 IN CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint,\r
2ed65824
JY
1015 IN VOID *Image,\r
1016 IN UINTN ImageSize,\r
1017 OUT UINT32 *LastAttemptStatus\r
88266859
JY
1018 )\r
1019{\r
2ed65824
JY
1020 VOID *MicrocodePatchAddress;\r
1021 UINTN MicrocodePatchRegionSize;\r
31d060d9 1022 UINTN TargetTotalSize;\r
88266859 1023 UINTN UsedRegionSize;\r
2ed65824
JY
1024 EFI_STATUS Status;\r
1025 VOID *MicrocodePatchScratchBuffer;\r
1026 UINT8 *ScratchBufferPtr;\r
1027 UINTN ScratchBufferSize;\r
1028 UINTN RestSize;\r
1029 UINTN AvailableSize;\r
1030 VOID *NextMicrocodeEntryPoint;\r
1031 MICROCODE_INFO *MicrocodeInfo;\r
1032 UINTN MicrocodeCount;\r
1033 UINTN Index;\r
1034\r
1035 DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));\r
88266859 1036\r
2ed65824
JY
1037 MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
1038 MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
1039\r
1040 MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);\r
1041 if (MicrocodePatchScratchBuffer == NULL) {\r
1042 DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));\r
1043 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
1044 return EFI_OUT_OF_RESOURCES;\r
88266859 1045 }\r
2ed65824
JY
1046 ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
1047 ScratchBufferSize = 0;\r
88266859 1048\r
2ed65824 1049 //\r
31d060d9 1050 // Target data collection\r
2ed65824 1051 //\r
31d060d9 1052 TargetTotalSize = 0;\r
2ed65824
JY
1053 AvailableSize = 0;\r
1054 NextMicrocodeEntryPoint = NULL;\r
31d060d9
JY
1055 if (TargetMicrocodeEntryPoint != NULL) {\r
1056 if (TargetMicrocodeEntryPoint->DataSize == 0) {\r
1057 TargetTotalSize = 2048;\r
88266859 1058 } else {\r
31d060d9 1059 TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;\r
88266859 1060 }\r
31d060d9
JY
1061 DEBUG((DEBUG_INFO, " TargetTotalSize - 0x%x\n", TargetTotalSize));\r
1062 NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);\r
2ed65824
JY
1063 DEBUG((DEBUG_INFO, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));\r
1064 if (NextMicrocodeEntryPoint != NULL) {\r
31d060d9
JY
1065 ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
1066 AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;\r
2ed65824 1067 } else {\r
31d060d9 1068 AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;\r
2ed65824
JY
1069 }\r
1070 DEBUG((DEBUG_INFO, " AvailableSize - 0x%x\n", AvailableSize));\r
e9179788 1071 ASSERT (AvailableSize >= TargetTotalSize);\r
2ed65824 1072 }\r
2ed65824
JY
1073 UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);\r
1074 DEBUG((DEBUG_INFO, " UsedRegionSize - 0x%x\n", UsedRegionSize));\r
31d060d9
JY
1075 ASSERT (UsedRegionSize >= TargetTotalSize);\r
1076 if (TargetMicrocodeEntryPoint != NULL) {\r
1077 ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
2ed65824
JY
1078 }\r
1079 //\r
e9179788
SZ
1080 // Total Size means the Microcode size.\r
1081 // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.\r
2ed65824
JY
1082 //\r
1083 // (1)\r
1084 // +------+-----------+-----+------+===================+\r
1085 // | MCU1 | Microcode | PAD | MCU2 | Empty |\r
1086 // +------+-----------+-----+------+===================+\r
1087 // | TotalSize |\r
1088 // |<-AvailableSize->|\r
1089 // |<- UsedRegionSize ->|\r
1090 //\r
1091 // (2)\r
1092 // +------+-----------+===================+\r
1093 // | MCU | Microcode | Empty |\r
1094 // +------+-----------+===================+\r
1095 // | TotalSize |\r
1096 // |<- AvailableSize ->|\r
1097 // |<-UsedRegionSize->|\r
1098 //\r
1099\r
1100 //\r
1101 // Update based on policy\r
1102 //\r
1103\r
1104 //\r
1105 // 1. If there is enough space to update old one in situ, replace old microcode in situ.\r
1106 //\r
1107 if (AvailableSize >= ImageSize) {\r
1108 DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
1109 //\r
1110 // +------+------------+------+===================+\r
e9179788 1111 // |Other | Old Image | ... | Empty |\r
2ed65824
JY
1112 // +------+------------+------+===================+\r
1113 //\r
1114 // +------+---------+--+------+===================+\r
e9179788 1115 // |Other |New Image|FF| ... | Empty |\r
2ed65824
JY
1116 // +------+---------+--+------+===================+\r
1117 //\r
1118 // 1.1. Copy new image\r
1119 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
1120 ScratchBufferSize += ImageSize;\r
31d060d9 1121 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
1122 // 1.2. Pad 0xFF\r
1123 RestSize = AvailableSize - ImageSize;\r
1124 if (RestSize > 0) {\r
1125 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
1126 ScratchBufferSize += RestSize;\r
31d060d9 1127 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824 1128 }\r
31d060d9 1129 Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
2ed65824 1130 return Status;\r
88266859
JY
1131 }\r
1132\r
2ed65824
JY
1133 //\r
1134 // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.\r
1135 //\r
31d060d9
JY
1136 if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {\r
1137 if (TargetMicrocodeEntryPoint == NULL) {\r
2ed65824
JY
1138 DEBUG((DEBUG_INFO, "Append new microcode\n"));\r
1139 //\r
1140 // +------+------------+------+===================+\r
1141 // |Other1| Other |Other2| Empty |\r
1142 // +------+------------+------+===================+\r
1143 //\r
1144 // +------+------------+------+-----------+=======+\r
1145 // |Other1| Other |Other2| New Image | Empty |\r
1146 // +------+------------+------+-----------+=======+\r
1147 //\r
1148 Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);\r
1149 } else {\r
1150 DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));\r
1151 //\r
1152 // +------+------------+------+===================+\r
e9179788 1153 // |Other | Old Image | ... | Empty |\r
2ed65824
JY
1154 // +------+------------+------+===================+\r
1155 //\r
1156 // +------+---------------+------+================+\r
e9179788 1157 // |Other | New Image | ... | Empty |\r
2ed65824
JY
1158 // +------+---------------+------+================+\r
1159 //\r
1160 // 2.1. Copy new image\r
31d060d9 1161 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
2ed65824 1162 ScratchBufferSize += ImageSize;\r
31d060d9 1163 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
1164 // 2.2. Copy rest images after the old image.\r
1165 if (NextMicrocodeEntryPoint != 0) {\r
1166 RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);\r
e9179788 1167 CopyMem (ScratchBufferPtr, NextMicrocodeEntryPoint, RestSize);\r
2ed65824 1168 ScratchBufferSize += RestSize;\r
31d060d9 1169 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824 1170 }\r
31d060d9 1171 Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
2ed65824
JY
1172 }\r
1173 return Status;\r
1174 }\r
1175\r
1176 //\r
1177 // 3. The new image can be put in MCU region, but not all others can be put.\r
1178 // So all the unused MCU is removed.\r
1179 //\r
1180 if (MicrocodePatchRegionSize >= ImageSize) {\r
1181 //\r
1182 // +------+------------+------+===================+\r
1183 // |Other1| Old Image |Other2| Empty |\r
1184 // +------+------------+------+===================+\r
1185 //\r
1186 // +-------------------------------------+--------+\r
1187 // | New Image | Other |\r
1188 // +-------------------------------------+--------+\r
1189 //\r
1190 DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));\r
1191\r
1192 MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;\r
1193 MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;\r
1194\r
1195 // 3.1. Copy new image\r
31d060d9 1196 CopyMem (ScratchBufferPtr, Image, ImageSize);\r
2ed65824 1197 ScratchBufferSize += ImageSize;\r
31d060d9 1198 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
1199 // 3.2. Copy some others to rest buffer\r
1200 for (Index = 0; Index < MicrocodeCount; Index++) {\r
1201 if (!MicrocodeInfo[Index].InUse) {\r
1202 continue;\r
1203 }\r
31d060d9 1204 if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {\r
2ed65824
JY
1205 continue;\r
1206 }\r
1207 if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {\r
1208 CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);\r
1209 ScratchBufferSize += MicrocodeInfo[Index].TotalSize;\r
31d060d9 1210 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
1211 }\r
1212 }\r
1213 // 3.3. Pad 0xFF\r
1214 RestSize = MicrocodePatchRegionSize - ScratchBufferSize;\r
1215 if (RestSize > 0) {\r
1216 SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
1217 ScratchBufferSize += RestSize;\r
31d060d9 1218 ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
2ed65824
JY
1219 }\r
1220 Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
1221 return Status;\r
1222 }\r
1223\r
1224 //\r
1225 // 4. The new image size is bigger than the whole MCU region.\r
1226 //\r
1227 DEBUG((DEBUG_ERROR, "Microcode too big\n"));\r
1228 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
1229 Status = EFI_OUT_OF_RESOURCES;\r
1230\r
1231 return Status;\r
1232}\r
1233\r
1234/**\r
1235 Write Microcode.\r
1236\r
1237 Caution: This function may receive untrusted input.\r
1238\r
1239 @param[in] MicrocodeFmpPrivate The Microcode driver private data\r
1240 @param[in] Image The Microcode image buffer.\r
1241 @param[in] ImageSize The size of Microcode image buffer in bytes.\r
1242 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
1243 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
1244 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more\r
1245 details for the aborted operation. The buffer is allocated by this function\r
1246 with AllocatePool(), and it is the caller's responsibility to free it with a\r
1247 call to FreePool().\r
1248\r
1249 @retval EFI_SUCCESS The Microcode image is written.\r
e9179788 1250 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupted.\r
2ed65824
JY
1251 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.\r
1252 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.\r
1253 @retval EFI_WRITE_PROTECTED The flash device is read only.\r
1254**/\r
1255EFI_STATUS\r
1256MicrocodeWrite (\r
1257 IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate,\r
1258 IN VOID *Image,\r
1259 IN UINTN ImageSize,\r
1260 OUT UINT32 *LastAttemptVersion,\r
1261 OUT UINT32 *LastAttemptStatus,\r
1262 OUT CHAR16 **AbortReason\r
1263 )\r
1264{\r
1265 EFI_STATUS Status;\r
1266 VOID *AlignedImage;\r
31d060d9
JY
1267 CPU_MICROCODE_HEADER *TargetMicrocodeEntryPoint;\r
1268 UINTN TargetCpuIndex;\r
1269 UINTN TargetMicrcodeIndex;\r
2ed65824 1270\r
88266859
JY
1271 //\r
1272 // MCU must be 16 bytes aligned\r
1273 //\r
1274 AlignedImage = AllocateCopyPool(ImageSize, Image);\r
1275 if (AlignedImage == NULL) {\r
1276 DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));\r
1277 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
1278 return EFI_OUT_OF_RESOURCES;\r
1279 }\r
1280\r
31d060d9
JY
1281 TargetCpuIndex = (UINTN)-1;\r
1282 Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);\r
88266859
JY
1283 if (EFI_ERROR(Status)) {\r
1284 DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));\r
1285 FreePool(AlignedImage);\r
1286 return Status;\r
1287 }\r
1288 DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));\r
e9179788 1289 *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;\r
88266859 1290\r
31d060d9
JY
1291 DEBUG((DEBUG_INFO, " TargetCpuIndex - 0x%x\n", TargetCpuIndex));\r
1292 ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
1293 TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;\r
1294 DEBUG((DEBUG_INFO, " TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));\r
1295 if (TargetMicrcodeIndex != (UINTN)-1) {\r
1296 ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);\r
1297 TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;\r
1298 } else {\r
1299 TargetMicrocodeEntryPoint = NULL;\r
1300 }\r
1301 DEBUG((DEBUG_INFO, " TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));\r
1302\r
e9179788
SZ
1303 if (MicrocodeFmpPrivate->FitMicrocodeInfo != NULL) {\r
1304 Status = UpdateMicrocodeFlashRegionWithFit (\r
1305 MicrocodeFmpPrivate,\r
1306 TargetMicrocodeEntryPoint,\r
1307 AlignedImage,\r
1308 ImageSize,\r
1309 LastAttemptStatus\r
1310 );\r
1311 } else {\r
1312 Status = UpdateMicrocodeFlashRegion (\r
1313 MicrocodeFmpPrivate,\r
1314 TargetMicrocodeEntryPoint,\r
1315 AlignedImage,\r
1316 ImageSize,\r
1317 LastAttemptStatus\r
1318 );\r
1319 }\r
88266859
JY
1320\r
1321 FreePool(AlignedImage);\r
1322\r
1323 return Status;\r
1324}\r
1325\r
1326\r