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
;
260 // It is the padding data between the microcode patches for microcode patches alignment.
261 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
262 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
263 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
264 // find the next possible microcode patch header.
266 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + SIZE_1KB
);
271 ASSERT(Count
< 0xFF);
274 // Get the next patch.
276 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + TotalSize
);
277 } while (((UINTN
)MicrocodeEntryPoint
< MicrocodeEnd
));
279 return EFI_NOT_FOUND
;
285 Caution: This function may receive untrusted input.
287 @param[in] Image The Microcode image buffer.
288 @param[in] ImageSize The size of Microcode image buffer in bytes.
289 @param[in] TryLoad Try to load Microcode or not.
290 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
291 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
292 details for the aborted operation. The buffer is allocated by this function
293 with AllocatePool(), and it is the caller's responsibility to free it with a
296 @retval EFI_SUCCESS The Microcode image passes verification.
297 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
298 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
299 @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.
300 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
307 OUT UINT32
*LastAttemptStatus
,
308 OUT CHAR16
**AbortReason
312 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
315 UINT32 CurrentRevision
;
316 UINT32 CurrentProcessorSignature
;
317 UINT8 CurrentPlatformId
;
319 UINTN ExtendedTableLength
;
320 UINT32 ExtendedTableCount
;
321 CPU_MICROCODE_EXTENDED_TABLE
*ExtendedTable
;
322 CPU_MICROCODE_EXTENDED_TABLE_HEADER
*ExtendedTableHeader
;
323 BOOLEAN CorrectMicrocode
;
326 // Check HeaderVersion
328 MicrocodeEntryPoint
= Image
;
329 if (MicrocodeEntryPoint
->HeaderVersion
!= 0x1) {
330 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on HeaderVersion\n"));
331 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
332 if (AbortReason
!= NULL
) {
333 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidHeaderVersion"), L
"InvalidHeaderVersion");
335 return EFI_INCOMPATIBLE_VERSION
;
338 // Check LoaderRevision
340 if (MicrocodeEntryPoint
->LoaderRevision
!= 0x1) {
341 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on LoaderRevision\n"));
342 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
343 if (AbortReason
!= NULL
) {
344 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidLoaderVersion"), L
"InvalidLoaderVersion");
346 return EFI_INCOMPATIBLE_VERSION
;
351 if (MicrocodeEntryPoint
->DataSize
== 0) {
354 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
356 if (TotalSize
<= sizeof(CPU_MICROCODE_HEADER
)) {
357 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - TotalSize too small\n"));
358 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
359 if (AbortReason
!= NULL
) {
360 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidTotalSize"), L
"InvalidTotalSize");
362 return EFI_VOLUME_CORRUPTED
;
364 if (TotalSize
!= ImageSize
) {
365 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on TotalSize\n"));
366 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
367 if (AbortReason
!= NULL
) {
368 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidTotalSize"), L
"InvalidTotalSize");
370 return EFI_VOLUME_CORRUPTED
;
375 if (MicrocodeEntryPoint
->DataSize
== 0) {
376 DataSize
= 2048 - sizeof(CPU_MICROCODE_HEADER
);
378 DataSize
= MicrocodeEntryPoint
->DataSize
;
380 if (DataSize
> TotalSize
- sizeof(CPU_MICROCODE_HEADER
)) {
381 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - DataSize too big\n"));
382 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
383 if (AbortReason
!= NULL
) {
384 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidDataSize"), L
"InvalidDataSize");
386 return EFI_VOLUME_CORRUPTED
;
388 if ((DataSize
& 0x3) != 0) {
389 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - DataSize not aligned\n"));
390 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
391 if (AbortReason
!= NULL
) {
392 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidDataSize"), L
"InvalidDataSize");
394 return EFI_VOLUME_CORRUPTED
;
396 CheckSum32
= CalculateSum32((UINT32
*)MicrocodeEntryPoint
, DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
397 if (CheckSum32
!= 0) {
398 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on CheckSum32\n"));
399 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
400 if (AbortReason
!= NULL
) {
401 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidChecksum"), L
"InvalidChecksum");
403 return EFI_VOLUME_CORRUPTED
;
407 // Check ProcessorSignature/ProcessorFlags
409 CorrectMicrocode
= FALSE
;
410 CurrentProcessorSignature
= GetCurrentProcessorSignature();
411 CurrentPlatformId
= GetCurrentPlatformId();
412 if ((MicrocodeEntryPoint
->ProcessorSignature
.Uint32
!= CurrentProcessorSignature
) ||
413 ((MicrocodeEntryPoint
->ProcessorFlags
& (1 << CurrentPlatformId
)) == 0)) {
414 ExtendedTableLength
= TotalSize
- (DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
415 if (ExtendedTableLength
!= 0) {
417 // Extended Table exist, check if the CPU in support list
419 ExtendedTableHeader
= (CPU_MICROCODE_EXTENDED_TABLE_HEADER
*)((UINT8
*)(MicrocodeEntryPoint
) + DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
421 // Calculate Extended Checksum
423 if ((ExtendedTableLength
> sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) && ((ExtendedTableLength
& 0x3) != 0)) {
424 CheckSum32
= CalculateSum32((UINT32
*)ExtendedTableHeader
, ExtendedTableLength
);
425 if (CheckSum32
== 0) {
429 ExtendedTableCount
= ExtendedTableHeader
->ExtendedSignatureCount
;
430 if (ExtendedTableCount
<= (ExtendedTableLength
- sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE
)) {
431 ExtendedTable
= (CPU_MICROCODE_EXTENDED_TABLE
*)(ExtendedTableHeader
+ 1);
432 for (Index
= 0; Index
< ExtendedTableCount
; Index
++) {
433 CheckSum32
= CalculateSum32((UINT32
*)ExtendedTable
, sizeof(CPU_MICROCODE_EXTENDED_TABLE
));
434 if (CheckSum32
== 0) {
438 if ((ExtendedTable
->ProcessorSignature
.Uint32
== CurrentProcessorSignature
) &&
439 (ExtendedTable
->ProcessorFlag
& (1 << CurrentPlatformId
))) {
443 CorrectMicrocode
= TRUE
;
453 if (!CorrectMicrocode
) {
454 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));
455 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION
;
456 if (AbortReason
!= NULL
) {
457 if (MicrocodeEntryPoint
->ProcessorSignature
.Uint32
!= CurrentProcessorSignature
) {
458 *AbortReason
= AllocateCopyPool(sizeof(L
"UnsupportedProcessSignature"), L
"UnsupportedProcessSignature");
460 *AbortReason
= AllocateCopyPool(sizeof(L
"UnsupportedProcessorFlags"), L
"UnsupportedProcessorFlags");
463 return EFI_UNSUPPORTED
;
468 // Check UpdateRevision
470 CurrentRevision
= GetCurrentMicrocodeSignature();
471 if (MicrocodeEntryPoint
->UpdateRevision
< CurrentRevision
) {
472 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on UpdateRevision\n"));
473 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION
;
474 if (AbortReason
!= NULL
) {
475 *AbortReason
= AllocateCopyPool(sizeof(L
"IncorrectRevision"), L
"IncorrectRevision");
477 return EFI_INCOMPATIBLE_VERSION
;
484 CurrentRevision
= LoadMicrocode((UINTN
)MicrocodeEntryPoint
+ sizeof(CPU_MICROCODE_HEADER
));
485 if (MicrocodeEntryPoint
->UpdateRevision
!= CurrentRevision
) {
486 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on LoadMicrocode\n"));
487 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR
;
488 if (AbortReason
!= NULL
) {
489 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidData"), L
"InvalidData");
491 return EFI_SECURITY_VIOLATION
;
499 Get current Microcode in used.
501 @return current Microcode in used.
504 GetCurrentMicrocodeInUse (
510 UINT64 MicrocodePatchAddress
;
511 UINT64 MicrocodePatchRegionSize
;
512 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
516 UINT32 AttemptStatus
;
518 Result
= GetMicrocodeRegion(&MicrocodePatchAddress
, &MicrocodePatchRegionSize
);
520 DEBUG((DEBUG_ERROR
, "Fail to get Microcode Region\n"));
523 DEBUG((DEBUG_INFO
, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress
, MicrocodePatchRegionSize
));
527 MicrocodeEnd
= (UINTN
)(MicrocodePatchAddress
+ MicrocodePatchRegionSize
);
528 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(UINTN
)MicrocodePatchAddress
;
530 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1 && MicrocodeEntryPoint
->LoaderRevision
== 0x1) {
532 // It is the microcode header. It is not the padding data between microcode patches
533 // becasue the padding data should not include 0x00000001 and it should be the repeated
534 // byte format (like 0xXYXYXYXY....).
536 if (MicrocodeEntryPoint
->DataSize
== 0) {
539 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
541 Status
= VerifyMicrocode(MicrocodeEntryPoint
, TotalSize
, FALSE
, &AttemptStatus
, NULL
);
542 if (!EFI_ERROR(Status
)) {
543 return MicrocodeEntryPoint
;
548 // It is the padding data between the microcode patches for microcode patches alignment.
549 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
550 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
551 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
552 // find the next possible microcode patch header.
554 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + SIZE_1KB
);
559 ASSERT(Count
< 0xFF);
562 // Get the next patch.
564 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + TotalSize
);
565 } while (((UINTN
)MicrocodeEntryPoint
< MicrocodeEnd
));
571 Get current Microcode used region size.
573 @return current Microcode used region size.
576 GetCurrentMicrocodeUsedRegionSize (
581 UINT64 MicrocodePatchAddress
;
582 UINT64 MicrocodePatchRegionSize
;
583 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
587 UINTN MicrocodeUsedEnd
;
589 Result
= GetMicrocodeRegion(&MicrocodePatchAddress
, &MicrocodePatchRegionSize
);
591 DEBUG((DEBUG_ERROR
, "Fail to get Microcode Region\n"));
594 DEBUG((DEBUG_INFO
, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress
, MicrocodePatchRegionSize
));
596 MicrocodeUsedEnd
= (UINTN
)MicrocodePatchAddress
;
599 MicrocodeEnd
= (UINTN
)(MicrocodePatchAddress
+ MicrocodePatchRegionSize
);
600 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(UINTN
)MicrocodePatchAddress
;
602 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1 && MicrocodeEntryPoint
->LoaderRevision
== 0x1) {
604 // It is the microcode header. It is not the padding data between microcode patches
605 // becasue the padding data should not include 0x00000001 and it should be the repeated
606 // byte format (like 0xXYXYXYXY....).
608 if (MicrocodeEntryPoint
->DataSize
== 0) {
611 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
616 // It is the padding data between the microcode patches for microcode patches alignment.
617 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
618 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
619 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
620 // find the next possible microcode patch header.
622 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + SIZE_1KB
);
627 ASSERT(Count
< 0xFF);
628 MicrocodeUsedEnd
= (UINTN
)MicrocodeEntryPoint
;
631 // Get the next patch.
633 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*)(((UINTN
)MicrocodeEntryPoint
) + TotalSize
);
634 } while (((UINTN
)MicrocodeEntryPoint
< MicrocodeEnd
));
636 return MicrocodeUsedEnd
- (UINTN
)MicrocodePatchAddress
;
642 @param[in] Address The flash address of Microcode.
643 @param[in] Image The Microcode image buffer.
644 @param[in] ImageSize The size of Microcode image buffer in bytes.
645 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
647 @retval EFI_SUCCESS The Microcode image is updated.
648 @retval EFI_WRITE_PROTECTED The flash device is read only.
655 OUT UINT32
*LastAttemptStatus
660 DEBUG((DEBUG_INFO
, "PlatformUpdate:"));
661 DEBUG((DEBUG_INFO
, " Address - 0x%lx,", Address
));
662 DEBUG((DEBUG_INFO
, " Legnth - 0x%x\n", ImageSize
));
664 Status
= MicrocodeFlashWrite (
669 if (!EFI_ERROR(Status
)) {
670 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_SUCCESS
;
672 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL
;
680 Caution: This function may receive untrusted input.
682 @param[in] ImageIndex The index of Microcode image.
683 @param[in] Image The Microcode image buffer.
684 @param[in] ImageSize The size of Microcode image buffer in bytes.
685 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
686 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
687 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
688 details for the aborted operation. The buffer is allocated by this function
689 with AllocatePool(), and it is the caller's responsibility to free it with a
692 @retval EFI_SUCCESS The Microcode image is written.
693 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
694 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
695 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
696 @retval EFI_WRITE_PROTECTED The flash device is read only.
703 OUT UINT32
*LastAttemptVersion
,
704 OUT UINT32
*LastAttemptStatus
,
705 OUT CHAR16
**AbortReason
710 UINT64 MicrocodePatchAddress
;
711 UINT64 MicrocodePatchRegionSize
;
712 CPU_MICROCODE_HEADER
*CurrentMicrocodeEntryPoint
;
713 UINTN CurrentTotalSize
;
714 UINTN UsedRegionSize
;
717 Result
= GetMicrocodeRegion(&MicrocodePatchAddress
, &MicrocodePatchRegionSize
);
719 DEBUG((DEBUG_ERROR
, "Fail to get Microcode Region\n"));
720 return EFI_NOT_FOUND
;
723 CurrentTotalSize
= 0;
724 CurrentMicrocodeEntryPoint
= GetCurrentMicrocodeInUse();
725 if (CurrentMicrocodeEntryPoint
!= NULL
) {
726 if (CurrentMicrocodeEntryPoint
->DataSize
== 0) {
727 CurrentTotalSize
= 2048;
729 CurrentTotalSize
= CurrentMicrocodeEntryPoint
->TotalSize
;
734 // MCU must be 16 bytes aligned
736 AlignedImage
= AllocateCopyPool(ImageSize
, Image
);
737 if (AlignedImage
== NULL
) {
738 DEBUG((DEBUG_ERROR
, "Fail to allocate aligned image\n"));
739 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
740 return EFI_OUT_OF_RESOURCES
;
743 *LastAttemptVersion
= ((CPU_MICROCODE_HEADER
*)Image
)->UpdateRevision
;
744 Status
= VerifyMicrocode(AlignedImage
, ImageSize
, TRUE
, LastAttemptStatus
, AbortReason
);
745 if (EFI_ERROR(Status
)) {
746 DEBUG((DEBUG_ERROR
, "Fail to verify Microcode Region\n"));
747 FreePool(AlignedImage
);
750 DEBUG((DEBUG_INFO
, "Pass VerifyMicrocode\n"));
752 if (CurrentTotalSize
< ImageSize
) {
753 UsedRegionSize
= GetCurrentMicrocodeUsedRegionSize();
754 if (MicrocodePatchRegionSize
- UsedRegionSize
>= ImageSize
) {
758 DEBUG((DEBUG_INFO
, "Append new microcode\n"));
759 Status
= UpdateMicrocode(MicrocodePatchAddress
+ UsedRegionSize
, AlignedImage
, ImageSize
, LastAttemptStatus
);
760 } else if (MicrocodePatchRegionSize
>= ImageSize
) {
762 // Ignor all others and just add this one from beginning.
764 DEBUG((DEBUG_INFO
, "Add new microcode from beginning\n"));
765 Status
= UpdateMicrocode(MicrocodePatchAddress
, AlignedImage
, ImageSize
, LastAttemptStatus
);
767 DEBUG((DEBUG_ERROR
, "Microcode too big\n"));
768 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
769 Status
= EFI_OUT_OF_RESOURCES
;
775 DEBUG((DEBUG_INFO
, "Replace old microcode\n"));
776 Status
= UpdateMicrocode((UINTN
)CurrentMicrocodeEntryPoint
, AlignedImage
, ImageSize
, LastAttemptStatus
);
779 FreePool(AlignedImage
);