2 SetImage instance to update Microcode.
4 Caution: This module requires additional review when modified.
5 This module will have external input - capsule image.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
9 MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.
11 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
12 This program and the accompanying materials
13 are licensed and made available under the terms and conditions of the BSD License
14 which accompanies this distribution. The full text of the license may be found at
15 http://opensource.org/licenses/bsd-license.php
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
22 #include "MicrocodeUpdate.h"
27 @param[out] MicrocodePatchAddress The address of Microcode
28 @param[out] MicrocodePatchRegionSize The region size of Microcode
30 @retval TRUE The Microcode region is returned.
31 @retval FALSE No Microcode region.
35 OUT UINT64
*MicrocodePatchAddress
,
36 OUT UINT64
*MicrocodePatchRegionSize
39 *MicrocodePatchAddress
= PcdGet64(PcdCpuMicrocodePatchAddress
);
40 *MicrocodePatchRegionSize
= PcdGet64(PcdCpuMicrocodePatchRegionSize
);
42 if ((*MicrocodePatchAddress
== 0) || (*MicrocodePatchRegionSize
== 0)) {
50 Get Microcode update signature of currently loaded Microcode update.
52 @return Microcode signature.
56 GetCurrentMicrocodeSignature (
62 AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID
, 0);
63 AsmCpuid(CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, NULL
);
64 Signature
= AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID
);
65 return (UINT32
)RShiftU64(Signature
, 32);
69 Get current processor signature.
71 @return current processor signature.
74 GetCurrentProcessorSignature (
79 AsmCpuid(CPUID_VERSION_INFO
, &RegEax
, NULL
, NULL
, NULL
);
84 Get current platform ID.
86 @return current platform ID.
89 GetCurrentPlatformId (
95 PlatformId
= (UINT8
)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID
, 50, 52);
102 @param[in] Address The address of new Microcode.
104 @return Loaded Microcode signature.
112 AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG
, Address
);
113 return GetCurrentMicrocodeSignature();
117 Get current Microcode information.
119 @param[out] ImageDescriptor Microcode ImageDescriptor
120 @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated.
122 @return Microcode count
126 OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR
*ImageDescriptor
, OPTIONAL
127 IN UINTN DescriptorCount OPTIONAL
131 UINT64 MicrocodePatchAddress
;
132 UINT64 MicrocodePatchRegionSize
;
133 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
137 UINT64 ImageAttributes
;
138 UINT32 CurrentRevision
;
140 Result
= GetMicrocodeRegion(&MicrocodePatchAddress
, &MicrocodePatchRegionSize
);
142 DEBUG((DEBUG_ERROR
, "Fail to get Microcode Region\n"));
145 DEBUG((DEBUG_INFO
, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress
, MicrocodePatchRegionSize
));
148 CurrentRevision
= GetCurrentMicrocodeSignature();
150 MicrocodeEnd
= (UINTN
)(MicrocodePatchAddress
+ MicrocodePatchRegionSize
);
151 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (UINTN
) MicrocodePatchAddress
;
153 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1 && MicrocodeEntryPoint
->LoaderRevision
== 0x1) {
155 // It is the microcode header. It is not the padding data between microcode patches
156 // becasue the padding data should not include 0x00000001 and it should be the repeated
157 // byte format (like 0xXYXYXYXY....).
159 if (MicrocodeEntryPoint
->DataSize
== 0) {
162 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
165 if (ImageDescriptor
!= NULL
&& DescriptorCount
> Count
) {
166 ImageDescriptor
[Count
].ImageIndex
= (UINT8
)(Count
+ 1);
167 CopyGuid (&ImageDescriptor
[Count
].ImageTypeId
, &gMicrocodeFmpImageTypeIdGuid
);
168 ImageDescriptor
[Count
].ImageId
= LShiftU64(MicrocodeEntryPoint
->ProcessorFlags
, 32) + MicrocodeEntryPoint
->ProcessorSignature
.Uint32
;
169 ImageDescriptor
[Count
].ImageIdName
= NULL
;
170 ImageDescriptor
[Count
].Version
= MicrocodeEntryPoint
->UpdateRevision
;
171 ImageDescriptor
[Count
].VersionName
= NULL
;
172 ImageDescriptor
[Count
].Size
= TotalSize
;
173 ImageAttributes
= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE
| IMAGE_ATTRIBUTE_RESET_REQUIRED
;
174 if (CurrentRevision
== MicrocodeEntryPoint
->UpdateRevision
) {
175 ImageAttributes
|= IMAGE_ATTRIBUTE_IN_USE
;
177 ImageDescriptor
[Count
].AttributesSupported
= ImageAttributes
| IMAGE_ATTRIBUTE_IN_USE
;
178 ImageDescriptor
[Count
].AttributesSetting
= ImageAttributes
;
179 ImageDescriptor
[Count
].Compatibilities
= 0;
180 ImageDescriptor
[Count
].LowestSupportedImageVersion
= MicrocodeEntryPoint
->UpdateRevision
; // do not support rollback
181 ImageDescriptor
[Count
].LastAttemptVersion
= 0;
182 ImageDescriptor
[Count
].LastAttemptStatus
= 0;
183 ImageDescriptor
[Count
].HardwareInstance
= 0;
187 // It is the padding data between the microcode patches for microcode patches alignment.
188 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
189 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
190 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
191 // find the next possible microcode patch header.
193 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + SIZE_1KB
);
198 ASSERT(Count
< 0xFF);
201 // Get the next patch.
203 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + TotalSize
);
204 } while (((UINTN
) MicrocodeEntryPoint
< MicrocodeEnd
));
212 @param[in] ImageIndex The index of Microcode image.
213 @param[in, out] Image The Microcode image buffer.
214 @param[in, out] ImageSize The size of Microcode image buffer in bytes.
216 @retval EFI_SUCCESS The Microcode image is read.
217 @retval EFI_NOT_FOUND The Microcode image is not found.
223 IN OUT UINTN
*ImageSize
227 UINT64 MicrocodePatchAddress
;
228 UINT64 MicrocodePatchRegionSize
;
229 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
234 Result
= GetMicrocodeRegion(&MicrocodePatchAddress
, &MicrocodePatchRegionSize
);
236 DEBUG((DEBUG_ERROR
, "Fail to get Microcode Region\n"));
237 return EFI_NOT_FOUND
;
239 DEBUG((DEBUG_INFO
, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress
, MicrocodePatchRegionSize
));
243 MicrocodeEnd
= (UINTN
)(MicrocodePatchAddress
+ MicrocodePatchRegionSize
);
244 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(UINTN
)MicrocodePatchAddress
;
246 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1 && MicrocodeEntryPoint
->LoaderRevision
== 0x1) {
248 // It is the microcode header. It is not the padding data between microcode patches
249 // becasue the padding data should not include 0x00000001 and it should be the repeated
250 // byte format (like 0xXYXYXYXY....).
252 if (MicrocodeEntryPoint
->DataSize
== 0) {
255 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
258 if (ImageIndex
== Count
+ 1) {
259 if (*ImageSize
< TotalSize
) {
260 *ImageSize
= TotalSize
;
261 return EFI_BUFFER_TOO_SMALL
;
263 *ImageSize
= TotalSize
;
264 CopyMem (Image
, MicrocodeEntryPoint
, TotalSize
);
270 // It is the padding data between the microcode patches for microcode patches alignment.
271 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
272 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
273 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
274 // find the next possible microcode patch header.
276 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + SIZE_1KB
);
281 ASSERT(Count
< 0xFF);
284 // Get the next patch.
286 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + TotalSize
);
287 } while (((UINTN
)MicrocodeEntryPoint
< MicrocodeEnd
));
289 return EFI_NOT_FOUND
;
295 Caution: This function may receive untrusted input.
297 @param[in] Image The Microcode image buffer.
298 @param[in] ImageSize The size of Microcode image buffer in bytes.
299 @param[in] TryLoad Try to load Microcode or not.
300 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
301 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
302 details for the aborted operation. The buffer is allocated by this function
303 with AllocatePool(), and it is the caller's responsibility to free it with a
306 @retval EFI_SUCCESS The Microcode image passes verification.
307 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
308 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
309 @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.
310 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
317 OUT UINT32
*LastAttemptStatus
,
318 OUT CHAR16
**AbortReason
322 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
325 UINT32 CurrentRevision
;
326 UINT32 CurrentProcessorSignature
;
327 UINT8 CurrentPlatformId
;
329 UINTN ExtendedTableLength
;
330 UINT32 ExtendedTableCount
;
331 CPU_MICROCODE_EXTENDED_TABLE
*ExtendedTable
;
332 CPU_MICROCODE_EXTENDED_TABLE_HEADER
*ExtendedTableHeader
;
333 BOOLEAN CorrectMicrocode
;
336 // Check HeaderVersion
338 MicrocodeEntryPoint
= Image
;
339 if (MicrocodeEntryPoint
->HeaderVersion
!= 0x1) {
340 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on HeaderVersion\n"));
341 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
342 if (AbortReason
!= NULL
) {
343 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidHeaderVersion"), L
"InvalidHeaderVersion");
345 return EFI_INCOMPATIBLE_VERSION
;
348 // Check LoaderRevision
350 if (MicrocodeEntryPoint
->LoaderRevision
!= 0x1) {
351 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on LoaderRevision\n"));
352 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
353 if (AbortReason
!= NULL
) {
354 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidLoaderVersion"), L
"InvalidLoaderVersion");
356 return EFI_INCOMPATIBLE_VERSION
;
361 if (MicrocodeEntryPoint
->DataSize
== 0) {
364 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
366 if (TotalSize
<= sizeof(CPU_MICROCODE_HEADER
)) {
367 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - TotalSize too small\n"));
368 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
369 if (AbortReason
!= NULL
) {
370 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidTotalSize"), L
"InvalidTotalSize");
372 return EFI_VOLUME_CORRUPTED
;
374 if (TotalSize
!= ImageSize
) {
375 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on TotalSize\n"));
376 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
377 if (AbortReason
!= NULL
) {
378 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidTotalSize"), L
"InvalidTotalSize");
380 return EFI_VOLUME_CORRUPTED
;
385 if (MicrocodeEntryPoint
->DataSize
== 0) {
386 DataSize
= 2048 - sizeof(CPU_MICROCODE_HEADER
);
388 DataSize
= MicrocodeEntryPoint
->DataSize
;
390 if (DataSize
> TotalSize
- sizeof(CPU_MICROCODE_HEADER
)) {
391 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - DataSize too big\n"));
392 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
393 if (AbortReason
!= NULL
) {
394 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidDataSize"), L
"InvalidDataSize");
396 return EFI_VOLUME_CORRUPTED
;
398 if ((DataSize
& 0x3) != 0) {
399 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - DataSize not aligned\n"));
400 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
401 if (AbortReason
!= NULL
) {
402 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidDataSize"), L
"InvalidDataSize");
404 return EFI_VOLUME_CORRUPTED
;
406 CheckSum32
= CalculateSum32((UINT32
*)MicrocodeEntryPoint
, DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
407 if (CheckSum32
!= 0) {
408 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on CheckSum32\n"));
409 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
410 if (AbortReason
!= NULL
) {
411 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidChecksum"), L
"InvalidChecksum");
413 return EFI_VOLUME_CORRUPTED
;
417 // Check ProcessorSignature/ProcessorFlags
419 CorrectMicrocode
= FALSE
;
420 CurrentProcessorSignature
= GetCurrentProcessorSignature();
421 CurrentPlatformId
= GetCurrentPlatformId();
422 if ((MicrocodeEntryPoint
->ProcessorSignature
.Uint32
!= CurrentProcessorSignature
) ||
423 ((MicrocodeEntryPoint
->ProcessorFlags
& (1 << CurrentPlatformId
)) == 0)) {
424 ExtendedTableLength
= TotalSize
- (DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
425 if (ExtendedTableLength
!= 0) {
427 // Extended Table exist, check if the CPU in support list
429 ExtendedTableHeader
= (CPU_MICROCODE_EXTENDED_TABLE_HEADER
*)((UINT8
*)(MicrocodeEntryPoint
) + DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
431 // Calculate Extended Checksum
433 if ((ExtendedTableLength
> sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) && ((ExtendedTableLength
& 0x3) != 0)) {
434 CheckSum32
= CalculateSum32((UINT32
*)ExtendedTableHeader
, ExtendedTableLength
);
435 if (CheckSum32
== 0) {
439 ExtendedTableCount
= ExtendedTableHeader
->ExtendedSignatureCount
;
440 if (ExtendedTableCount
<= (ExtendedTableLength
- sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE
)) {
441 ExtendedTable
= (CPU_MICROCODE_EXTENDED_TABLE
*)(ExtendedTableHeader
+ 1);
442 for (Index
= 0; Index
< ExtendedTableCount
; Index
++) {
443 CheckSum32
= CalculateSum32((UINT32
*)ExtendedTable
, sizeof(CPU_MICROCODE_EXTENDED_TABLE
));
444 if (CheckSum32
== 0) {
448 if ((ExtendedTable
->ProcessorSignature
.Uint32
== CurrentProcessorSignature
) &&
449 (ExtendedTable
->ProcessorFlag
& (1 << CurrentPlatformId
))) {
453 CorrectMicrocode
= TRUE
;
463 if (!CorrectMicrocode
) {
464 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));
465 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION
;
466 if (AbortReason
!= NULL
) {
467 if (MicrocodeEntryPoint
->ProcessorSignature
.Uint32
!= CurrentProcessorSignature
) {
468 *AbortReason
= AllocateCopyPool(sizeof(L
"UnsupportedProcessSignature"), L
"UnsupportedProcessSignature");
470 *AbortReason
= AllocateCopyPool(sizeof(L
"UnsupportedProcessorFlags"), L
"UnsupportedProcessorFlags");
473 return EFI_UNSUPPORTED
;
478 // Check UpdateRevision
480 CurrentRevision
= GetCurrentMicrocodeSignature();
481 if (MicrocodeEntryPoint
->UpdateRevision
< CurrentRevision
) {
482 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on UpdateRevision\n"));
483 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION
;
484 if (AbortReason
!= NULL
) {
485 *AbortReason
= AllocateCopyPool(sizeof(L
"IncorrectRevision"), L
"IncorrectRevision");
487 return EFI_INCOMPATIBLE_VERSION
;
494 CurrentRevision
= LoadMicrocode((UINTN
)MicrocodeEntryPoint
+ sizeof(CPU_MICROCODE_HEADER
));
495 if (MicrocodeEntryPoint
->UpdateRevision
!= CurrentRevision
) {
496 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on LoadMicrocode\n"));
497 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR
;
498 if (AbortReason
!= NULL
) {
499 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidData"), L
"InvalidData");
501 return EFI_SECURITY_VIOLATION
;
509 Get current Microcode in used.
511 @return current Microcode in used.
514 GetCurrentMicrocodeInUse (
520 UINT64 MicrocodePatchAddress
;
521 UINT64 MicrocodePatchRegionSize
;
522 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
526 UINT32 AttemptStatus
;
528 Result
= GetMicrocodeRegion(&MicrocodePatchAddress
, &MicrocodePatchRegionSize
);
530 DEBUG((DEBUG_ERROR
, "Fail to get Microcode Region\n"));
533 DEBUG((DEBUG_INFO
, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress
, MicrocodePatchRegionSize
));
537 MicrocodeEnd
= (UINTN
)(MicrocodePatchAddress
+ MicrocodePatchRegionSize
);
538 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(UINTN
)MicrocodePatchAddress
;
540 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1 && MicrocodeEntryPoint
->LoaderRevision
== 0x1) {
542 // It is the microcode header. It is not the padding data between microcode patches
543 // becasue the padding data should not include 0x00000001 and it should be the repeated
544 // byte format (like 0xXYXYXYXY....).
546 if (MicrocodeEntryPoint
->DataSize
== 0) {
549 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
551 Status
= VerifyMicrocode(MicrocodeEntryPoint
, TotalSize
, FALSE
, &AttemptStatus
, NULL
);
552 if (!EFI_ERROR(Status
)) {
553 return MicrocodeEntryPoint
;
558 // It is the padding data between the microcode patches for microcode patches alignment.
559 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
560 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
561 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
562 // find the next possible microcode patch header.
564 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + SIZE_1KB
);
569 ASSERT(Count
< 0xFF);
572 // Get the next patch.
574 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + TotalSize
);
575 } while (((UINTN
)MicrocodeEntryPoint
< MicrocodeEnd
));
581 Get current Microcode used region size.
583 @return current Microcode used region size.
586 GetCurrentMicrocodeUsedRegionSize (
591 UINT64 MicrocodePatchAddress
;
592 UINT64 MicrocodePatchRegionSize
;
593 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
597 UINTN MicrocodeUsedEnd
;
599 Result
= GetMicrocodeRegion(&MicrocodePatchAddress
, &MicrocodePatchRegionSize
);
601 DEBUG((DEBUG_ERROR
, "Fail to get Microcode Region\n"));
604 DEBUG((DEBUG_INFO
, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress
, MicrocodePatchRegionSize
));
606 MicrocodeUsedEnd
= (UINTN
)MicrocodePatchAddress
;
609 MicrocodeEnd
= (UINTN
)(MicrocodePatchAddress
+ MicrocodePatchRegionSize
);
610 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(UINTN
)MicrocodePatchAddress
;
612 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1 && MicrocodeEntryPoint
->LoaderRevision
== 0x1) {
614 // It is the microcode header. It is not the padding data between microcode patches
615 // becasue the padding data should not include 0x00000001 and it should be the repeated
616 // byte format (like 0xXYXYXYXY....).
618 if (MicrocodeEntryPoint
->DataSize
== 0) {
621 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
626 // It is the padding data between the microcode patches for microcode patches alignment.
627 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
628 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
629 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
630 // find the next possible microcode patch header.
632 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + SIZE_1KB
);
637 ASSERT(Count
< 0xFF);
638 MicrocodeUsedEnd
= (UINTN
)MicrocodeEntryPoint
;
641 // Get the next patch.
643 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + TotalSize
);
644 } while (((UINTN
)MicrocodeEntryPoint
< MicrocodeEnd
));
646 return MicrocodeUsedEnd
- (UINTN
)MicrocodePatchAddress
;
652 @param[in] Address The flash address of Microcode.
653 @param[in] Image The Microcode image buffer.
654 @param[in] ImageSize The size of Microcode image buffer in bytes.
655 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
657 @retval EFI_SUCCESS The Microcode image is updated.
658 @retval EFI_WRITE_PROTECTED The flash device is read only.
665 OUT UINT32
*LastAttemptStatus
670 DEBUG((DEBUG_INFO
, "PlatformUpdate:"));
671 DEBUG((DEBUG_INFO
, " Address - 0x%lx,", Address
));
672 DEBUG((DEBUG_INFO
, " Legnth - 0x%x\n", ImageSize
));
674 Status
= MicrocodeFlashWrite (
679 if (!EFI_ERROR(Status
)) {
680 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_SUCCESS
;
682 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL
;
690 Caution: This function may receive untrusted input.
692 @param[in] ImageIndex The index of Microcode image.
693 @param[in] Image The Microcode image buffer.
694 @param[in] ImageSize The size of Microcode image buffer in bytes.
695 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
696 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
697 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
698 details for the aborted operation. The buffer is allocated by this function
699 with AllocatePool(), and it is the caller's responsibility to free it with a
702 @retval EFI_SUCCESS The Microcode image is written.
703 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
704 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
705 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
706 @retval EFI_WRITE_PROTECTED The flash device is read only.
713 OUT UINT32
*LastAttemptVersion
,
714 OUT UINT32
*LastAttemptStatus
,
715 OUT CHAR16
**AbortReason
720 UINT64 MicrocodePatchAddress
;
721 UINT64 MicrocodePatchRegionSize
;
722 CPU_MICROCODE_HEADER
*CurrentMicrocodeEntryPoint
;
723 UINTN CurrentTotalSize
;
724 UINTN UsedRegionSize
;
727 Result
= GetMicrocodeRegion(&MicrocodePatchAddress
, &MicrocodePatchRegionSize
);
729 DEBUG((DEBUG_ERROR
, "Fail to get Microcode Region\n"));
730 return EFI_NOT_FOUND
;
733 CurrentTotalSize
= 0;
734 CurrentMicrocodeEntryPoint
= GetCurrentMicrocodeInUse();
735 if (CurrentMicrocodeEntryPoint
!= NULL
) {
736 if (CurrentMicrocodeEntryPoint
->DataSize
== 0) {
737 CurrentTotalSize
= 2048;
739 CurrentTotalSize
= CurrentMicrocodeEntryPoint
->TotalSize
;
744 // MCU must be 16 bytes aligned
746 AlignedImage
= AllocateCopyPool(ImageSize
, Image
);
747 if (AlignedImage
== NULL
) {
748 DEBUG((DEBUG_ERROR
, "Fail to allocate aligned image\n"));
749 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
750 return EFI_OUT_OF_RESOURCES
;
753 *LastAttemptVersion
= ((CPU_MICROCODE_HEADER
*)Image
)->UpdateRevision
;
754 Status
= VerifyMicrocode(AlignedImage
, ImageSize
, TRUE
, LastAttemptStatus
, AbortReason
);
755 if (EFI_ERROR(Status
)) {
756 DEBUG((DEBUG_ERROR
, "Fail to verify Microcode Region\n"));
757 FreePool(AlignedImage
);
760 DEBUG((DEBUG_INFO
, "Pass VerifyMicrocode\n"));
762 if (CurrentTotalSize
< ImageSize
) {
763 UsedRegionSize
= GetCurrentMicrocodeUsedRegionSize();
764 if (MicrocodePatchRegionSize
- UsedRegionSize
>= ImageSize
) {
768 DEBUG((DEBUG_INFO
, "Append new microcode\n"));
769 Status
= UpdateMicrocode(MicrocodePatchAddress
+ UsedRegionSize
, AlignedImage
, ImageSize
, LastAttemptStatus
);
770 } else if (MicrocodePatchRegionSize
>= ImageSize
) {
772 // Ignor all others and just add this one from beginning.
774 DEBUG((DEBUG_INFO
, "Add new microcode from beginning\n"));
775 Status
= UpdateMicrocode(MicrocodePatchAddress
, AlignedImage
, ImageSize
, LastAttemptStatus
);
777 DEBUG((DEBUG_ERROR
, "Microcode too big\n"));
778 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
779 Status
= EFI_OUT_OF_RESOURCES
;
785 DEBUG((DEBUG_INFO
, "Replace old microcode\n"));
786 Status
= UpdateMicrocode((UINTN
)CurrentMicrocodeEntryPoint
, AlignedImage
, ImageSize
, LastAttemptStatus
);
789 FreePool(AlignedImage
);