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 - 2017, 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 VOID
**MicrocodePatchAddress
,
36 OUT UINTN
*MicrocodePatchRegionSize
39 *MicrocodePatchAddress
= (VOID
*)(UINTN
)PcdGet64(PcdCpuMicrocodePatchAddress
);
40 *MicrocodePatchRegionSize
= (UINTN
)PcdGet64(PcdCpuMicrocodePatchRegionSize
);
42 if ((*MicrocodePatchAddress
== NULL
) || (*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 Load Microcode on an Application Processor.
118 The function prototype for invoking a function on an Application Processor.
120 @param[in,out] Buffer The pointer to private data buffer.
128 MICROCODE_LOAD_BUFFER
*MicrocodeLoadBuffer
;
130 MicrocodeLoadBuffer
= Buffer
;
131 MicrocodeLoadBuffer
->Revision
= LoadMicrocode (MicrocodeLoadBuffer
->Address
);
135 Load new Microcode on this processor
137 @param[in] MicrocodeFmpPrivate The Microcode driver private data
138 @param[in] CpuIndex The index of the processor.
139 @param[in] Address The address of new Microcode.
141 @return Loaded Microcode signature.
145 LoadMicrocodeOnThis (
146 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
152 EFI_MP_SERVICES_PROTOCOL
*MpService
;
153 MICROCODE_LOAD_BUFFER MicrocodeLoadBuffer
;
155 if (CpuIndex
== MicrocodeFmpPrivate
->BspIndex
) {
156 return LoadMicrocode (Address
);
158 MpService
= MicrocodeFmpPrivate
->MpService
;
159 MicrocodeLoadBuffer
.Address
= Address
;
160 MicrocodeLoadBuffer
.Revision
= 0;
161 Status
= MpService
->StartupThisAP (
167 &MicrocodeLoadBuffer
,
170 ASSERT_EFI_ERROR(Status
);
171 return MicrocodeLoadBuffer
.Revision
;
176 Collect processor information.
177 The function prototype for invoking a function on an Application Processor.
179 @param[in,out] Buffer The pointer to private data buffer.
183 CollectProcessorInfo (
187 PROCESSOR_INFO
*ProcessorInfo
;
189 ProcessorInfo
= Buffer
;
190 ProcessorInfo
->ProcessorSignature
= GetCurrentProcessorSignature();
191 ProcessorInfo
->PlatformId
= GetCurrentPlatformId();
192 ProcessorInfo
->MicrocodeRevision
= GetCurrentMicrocodeSignature();
196 Get current Microcode information.
198 The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
199 in MicrocodeFmpPrivate must be initialized.
201 The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
202 in MicrocodeFmpPrivate may not be avaiable in this function.
204 @param[in] MicrocodeFmpPrivate The Microcode driver private data
205 @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated.
206 @param[out] ImageDescriptor Microcode ImageDescriptor
207 @param[out] MicrocodeInfo Microcode information
209 @return Microcode count
213 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
214 IN UINTN DescriptorCount
, OPTIONAL
215 OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR
*ImageDescriptor
, OPTIONAL
216 OUT MICROCODE_INFO
*MicrocodeInfo OPTIONAL
219 VOID
*MicrocodePatchAddress
;
220 UINTN MicrocodePatchRegionSize
;
221 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
225 UINT64 ImageAttributes
;
228 UINT32 AttemptStatus
;
229 UINTN TargetCpuIndex
;
231 MicrocodePatchAddress
= MicrocodeFmpPrivate
->MicrocodePatchAddress
;
232 MicrocodePatchRegionSize
= MicrocodeFmpPrivate
->MicrocodePatchRegionSize
;
234 DEBUG((DEBUG_INFO
, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress
, MicrocodePatchRegionSize
));
238 MicrocodeEnd
= (UINTN
)MicrocodePatchAddress
+ MicrocodePatchRegionSize
;
239 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (UINTN
) MicrocodePatchAddress
;
241 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1 && MicrocodeEntryPoint
->LoaderRevision
== 0x1) {
243 // It is the microcode header. It is not the padding data between microcode patches
244 // becasue the padding data should not include 0x00000001 and it should be the repeated
245 // byte format (like 0xXYXYXYXY....).
247 if (MicrocodeEntryPoint
->DataSize
== 0) {
250 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
253 TargetCpuIndex
= (UINTN
)-1;
254 Status
= VerifyMicrocode(MicrocodeFmpPrivate
, MicrocodeEntryPoint
, TotalSize
, FALSE
, &AttemptStatus
, NULL
, &TargetCpuIndex
);
255 if (!EFI_ERROR(Status
)) {
257 ASSERT (TargetCpuIndex
< MicrocodeFmpPrivate
->ProcessorCount
);
258 MicrocodeFmpPrivate
->ProcessorInfo
[TargetCpuIndex
].MicrocodeIndex
= Count
;
263 if (ImageDescriptor
!= NULL
&& DescriptorCount
> Count
) {
264 ImageDescriptor
[Count
].ImageIndex
= (UINT8
)(Count
+ 1);
265 CopyGuid (&ImageDescriptor
[Count
].ImageTypeId
, &gMicrocodeFmpImageTypeIdGuid
);
266 ImageDescriptor
[Count
].ImageId
= LShiftU64(MicrocodeEntryPoint
->ProcessorFlags
, 32) + MicrocodeEntryPoint
->ProcessorSignature
.Uint32
;
267 ImageDescriptor
[Count
].ImageIdName
= NULL
;
268 ImageDescriptor
[Count
].Version
= MicrocodeEntryPoint
->UpdateRevision
;
269 ImageDescriptor
[Count
].VersionName
= NULL
;
270 ImageDescriptor
[Count
].Size
= TotalSize
;
271 ImageAttributes
= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE
| IMAGE_ATTRIBUTE_RESET_REQUIRED
;
273 ImageAttributes
|= IMAGE_ATTRIBUTE_IN_USE
;
275 ImageDescriptor
[Count
].AttributesSupported
= ImageAttributes
| IMAGE_ATTRIBUTE_IN_USE
;
276 ImageDescriptor
[Count
].AttributesSetting
= ImageAttributes
;
277 ImageDescriptor
[Count
].Compatibilities
= 0;
278 ImageDescriptor
[Count
].LowestSupportedImageVersion
= MicrocodeEntryPoint
->UpdateRevision
; // do not support rollback
279 ImageDescriptor
[Count
].LastAttemptVersion
= 0;
280 ImageDescriptor
[Count
].LastAttemptStatus
= 0;
281 ImageDescriptor
[Count
].HardwareInstance
= 0;
283 if (MicrocodeInfo
!= NULL
&& DescriptorCount
> Count
) {
284 MicrocodeInfo
[Count
].MicrocodeEntryPoint
= MicrocodeEntryPoint
;
285 MicrocodeInfo
[Count
].TotalSize
= TotalSize
;
286 MicrocodeInfo
[Count
].InUse
= IsInUse
;
290 // It is the padding data between the microcode patches for microcode patches alignment.
291 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
292 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
293 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
294 // find the next possible microcode patch header.
296 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + SIZE_1KB
);
301 ASSERT(Count
< 0xFF);
304 // Get the next patch.
306 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + TotalSize
);
307 } while (((UINTN
) MicrocodeEntryPoint
< MicrocodeEnd
));
313 Return matched processor information.
315 @param[in] MicrocodeFmpPrivate The Microcode driver private data
316 @param[in] ProcessorSignature The processor signature to be matched
317 @param[in] ProcessorFlags The processor flags to be matched
318 @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
319 On output, the index of target CPU which matches the Microcode.
321 @return matched processor information.
324 GetMatchedProcessor (
325 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
326 IN UINT32 ProcessorSignature
,
327 IN UINT32 ProcessorFlags
,
328 IN OUT UINTN
*TargetCpuIndex
333 if (*TargetCpuIndex
!= (UINTN
)-1) {
334 Index
= *TargetCpuIndex
;
335 if ((ProcessorSignature
== MicrocodeFmpPrivate
->ProcessorInfo
[Index
].ProcessorSignature
) &&
336 ((ProcessorFlags
& (1 << MicrocodeFmpPrivate
->ProcessorInfo
[Index
].PlatformId
)) != 0)) {
337 return &MicrocodeFmpPrivate
->ProcessorInfo
[Index
];
343 for (Index
= 0; Index
< MicrocodeFmpPrivate
->ProcessorCount
; Index
++) {
344 if ((ProcessorSignature
== MicrocodeFmpPrivate
->ProcessorInfo
[Index
].ProcessorSignature
) &&
345 ((ProcessorFlags
& (1 << MicrocodeFmpPrivate
->ProcessorInfo
[Index
].PlatformId
)) != 0)) {
346 *TargetCpuIndex
= Index
;
347 return &MicrocodeFmpPrivate
->ProcessorInfo
[Index
];
356 Caution: This function may receive untrusted input.
358 @param[in] MicrocodeFmpPrivate The Microcode driver private data
359 @param[in] Image The Microcode image buffer.
360 @param[in] ImageSize The size of Microcode image buffer in bytes.
361 @param[in] TryLoad Try to load Microcode or not.
362 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
363 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
364 details for the aborted operation. The buffer is allocated by this function
365 with AllocatePool(), and it is the caller's responsibility to free it with a
367 @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
368 On output, the index of target CPU which matches the Microcode.
370 @retval EFI_SUCCESS The Microcode image passes verification.
371 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
372 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
373 @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.
374 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
378 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
382 OUT UINT32
*LastAttemptStatus
,
383 OUT CHAR16
**AbortReason
, OPTIONAL
384 IN OUT UINTN
*TargetCpuIndex
388 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
391 UINT32 CurrentRevision
;
392 PROCESSOR_INFO
*ProcessorInfo
;
394 UINTN ExtendedTableLength
;
395 UINT32 ExtendedTableCount
;
396 CPU_MICROCODE_EXTENDED_TABLE
*ExtendedTable
;
397 CPU_MICROCODE_EXTENDED_TABLE_HEADER
*ExtendedTableHeader
;
398 BOOLEAN CorrectMicrocode
;
401 // Check HeaderVersion
403 MicrocodeEntryPoint
= Image
;
404 if (MicrocodeEntryPoint
->HeaderVersion
!= 0x1) {
405 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on HeaderVersion\n"));
406 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
407 if (AbortReason
!= NULL
) {
408 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidHeaderVersion"), L
"InvalidHeaderVersion");
410 return EFI_INCOMPATIBLE_VERSION
;
413 // Check LoaderRevision
415 if (MicrocodeEntryPoint
->LoaderRevision
!= 0x1) {
416 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on LoaderRevision\n"));
417 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
418 if (AbortReason
!= NULL
) {
419 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidLoaderVersion"), L
"InvalidLoaderVersion");
421 return EFI_INCOMPATIBLE_VERSION
;
426 if (MicrocodeEntryPoint
->DataSize
== 0) {
429 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
431 if (TotalSize
<= sizeof(CPU_MICROCODE_HEADER
)) {
432 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - TotalSize too small\n"));
433 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
434 if (AbortReason
!= NULL
) {
435 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidTotalSize"), L
"InvalidTotalSize");
437 return EFI_VOLUME_CORRUPTED
;
439 if (TotalSize
!= ImageSize
) {
440 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on TotalSize\n"));
441 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
442 if (AbortReason
!= NULL
) {
443 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidTotalSize"), L
"InvalidTotalSize");
445 return EFI_VOLUME_CORRUPTED
;
450 if (MicrocodeEntryPoint
->DataSize
== 0) {
451 DataSize
= 2048 - sizeof(CPU_MICROCODE_HEADER
);
453 DataSize
= MicrocodeEntryPoint
->DataSize
;
455 if (DataSize
> TotalSize
- sizeof(CPU_MICROCODE_HEADER
)) {
456 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - DataSize too big\n"));
457 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
458 if (AbortReason
!= NULL
) {
459 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidDataSize"), L
"InvalidDataSize");
461 return EFI_VOLUME_CORRUPTED
;
463 if ((DataSize
& 0x3) != 0) {
464 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - DataSize not aligned\n"));
465 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
466 if (AbortReason
!= NULL
) {
467 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidDataSize"), L
"InvalidDataSize");
469 return EFI_VOLUME_CORRUPTED
;
471 CheckSum32
= CalculateSum32((UINT32
*)MicrocodeEntryPoint
, DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
472 if (CheckSum32
!= 0) {
473 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on CheckSum32\n"));
474 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
475 if (AbortReason
!= NULL
) {
476 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidChecksum"), L
"InvalidChecksum");
478 return EFI_VOLUME_CORRUPTED
;
482 // Check ProcessorSignature/ProcessorFlags
485 ProcessorInfo
= GetMatchedProcessor (MicrocodeFmpPrivate
, MicrocodeEntryPoint
->ProcessorSignature
.Uint32
, MicrocodeEntryPoint
->ProcessorFlags
, TargetCpuIndex
);
486 if (ProcessorInfo
== NULL
) {
487 CorrectMicrocode
= FALSE
;
488 ExtendedTableLength
= TotalSize
- (DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
489 if (ExtendedTableLength
!= 0) {
491 // Extended Table exist, check if the CPU in support list
493 ExtendedTableHeader
= (CPU_MICROCODE_EXTENDED_TABLE_HEADER
*)((UINT8
*)(MicrocodeEntryPoint
) + DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
495 // Calculate Extended Checksum
497 if ((ExtendedTableLength
> sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) && ((ExtendedTableLength
& 0x3) == 0)) {
498 CheckSum32
= CalculateSum32((UINT32
*)ExtendedTableHeader
, ExtendedTableLength
);
499 if (CheckSum32
== 0) {
503 ExtendedTableCount
= ExtendedTableHeader
->ExtendedSignatureCount
;
504 if (ExtendedTableCount
<= (ExtendedTableLength
- sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE
)) {
505 ExtendedTable
= (CPU_MICROCODE_EXTENDED_TABLE
*)(ExtendedTableHeader
+ 1);
506 for (Index
= 0; Index
< ExtendedTableCount
; Index
++) {
507 CheckSum32
= CalculateSum32((UINT32
*)ExtendedTable
, sizeof(CPU_MICROCODE_EXTENDED_TABLE
));
508 if (CheckSum32
== 0) {
512 ProcessorInfo
= GetMatchedProcessor (MicrocodeFmpPrivate
, ExtendedTable
->ProcessorSignature
.Uint32
, ExtendedTable
->ProcessorFlag
, TargetCpuIndex
);
513 if (ProcessorInfo
!= NULL
) {
517 CorrectMicrocode
= TRUE
;
527 if (!CorrectMicrocode
) {
529 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));
531 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION
;
532 if (AbortReason
!= NULL
) {
533 *AbortReason
= AllocateCopyPool(sizeof(L
"UnsupportedProcessSignature/ProcessorFlags"), L
"UnsupportedProcessSignature/ProcessorFlags");
535 return EFI_UNSUPPORTED
;
540 // Check UpdateRevision
542 CurrentRevision
= ProcessorInfo
->MicrocodeRevision
;
543 if ((MicrocodeEntryPoint
->UpdateRevision
< CurrentRevision
) ||
544 (TryLoad
&& (MicrocodeEntryPoint
->UpdateRevision
== CurrentRevision
))) {
546 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on UpdateRevision\n"));
548 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION
;
549 if (AbortReason
!= NULL
) {
550 *AbortReason
= AllocateCopyPool(sizeof(L
"IncorrectRevision"), L
"IncorrectRevision");
552 return EFI_INCOMPATIBLE_VERSION
;
559 CurrentRevision
= LoadMicrocodeOnThis(MicrocodeFmpPrivate
, ProcessorInfo
->CpuIndex
, (UINTN
)MicrocodeEntryPoint
+ sizeof(CPU_MICROCODE_HEADER
));
560 if (MicrocodeEntryPoint
->UpdateRevision
!= CurrentRevision
) {
561 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on LoadMicrocode\n"));
562 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR
;
563 if (AbortReason
!= NULL
) {
564 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidData"), L
"InvalidData");
566 return EFI_SECURITY_VIOLATION
;
574 Get next Microcode entrypoint.
576 @param[in] MicrocodeFmpPrivate The Microcode driver private data
577 @param[in] MicrocodeEntryPoint Current Microcode entrypoint
579 @return next Microcode entrypoint.
581 CPU_MICROCODE_HEADER
*
583 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
584 IN CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
589 for (Index
= 0; Index
< MicrocodeFmpPrivate
->DescriptorCount
; Index
++) {
590 if (MicrocodeEntryPoint
== MicrocodeFmpPrivate
->MicrocodeInfo
[Index
].MicrocodeEntryPoint
) {
591 if (Index
== (UINTN
)MicrocodeFmpPrivate
->DescriptorCount
- 1) {
596 return MicrocodeFmpPrivate
->MicrocodeInfo
[Index
+ 1].MicrocodeEntryPoint
;
606 Get current Microcode used region size.
608 @param[in] MicrocodeFmpPrivate The Microcode driver private data
610 @return current Microcode used region size.
613 GetCurrentMicrocodeUsedRegionSize (
614 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
617 if (MicrocodeFmpPrivate
->DescriptorCount
== 0) {
621 return (UINTN
)MicrocodeFmpPrivate
->MicrocodeInfo
[MicrocodeFmpPrivate
->DescriptorCount
- 1].MicrocodeEntryPoint
622 + (UINTN
)MicrocodeFmpPrivate
->MicrocodeInfo
[MicrocodeFmpPrivate
->DescriptorCount
- 1].TotalSize
623 - (UINTN
)MicrocodeFmpPrivate
->MicrocodePatchAddress
;
629 @param[in] Address The flash address of Microcode.
630 @param[in] Image The Microcode image buffer.
631 @param[in] ImageSize The size of Microcode image buffer in bytes.
632 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
634 @retval EFI_SUCCESS The Microcode image is updated.
635 @retval EFI_WRITE_PROTECTED The flash device is read only.
642 OUT UINT32
*LastAttemptStatus
647 DEBUG((DEBUG_INFO
, "PlatformUpdate:"));
648 DEBUG((DEBUG_INFO
, " Address - 0x%lx,", Address
));
649 DEBUG((DEBUG_INFO
, " Legnth - 0x%x\n", ImageSize
));
651 Status
= MicrocodeFlashWrite (
656 if (!EFI_ERROR(Status
)) {
657 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_SUCCESS
;
659 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL
;
665 Update Microcode flash region.
667 @param[in] MicrocodeFmpPrivate The Microcode driver private data
668 @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated
669 @param[in] Image The Microcode image buffer.
670 @param[in] ImageSize The size of Microcode image buffer in bytes.
671 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
673 @retval EFI_SUCCESS The Microcode image is written.
674 @retval EFI_WRITE_PROTECTED The flash device is read only.
677 UpdateMicrocodeFlashRegion (
678 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
679 IN CPU_MICROCODE_HEADER
*TargetMicrocodeEntryPoint
,
682 OUT UINT32
*LastAttemptStatus
685 VOID
*MicrocodePatchAddress
;
686 UINTN MicrocodePatchRegionSize
;
687 UINTN TargetTotalSize
;
688 UINTN UsedRegionSize
;
690 VOID
*MicrocodePatchScratchBuffer
;
691 UINT8
*ScratchBufferPtr
;
692 UINTN ScratchBufferSize
;
695 VOID
*NextMicrocodeEntryPoint
;
696 MICROCODE_INFO
*MicrocodeInfo
;
697 UINTN MicrocodeCount
;
700 DEBUG((DEBUG_INFO
, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image
, ImageSize
));
702 MicrocodePatchAddress
= MicrocodeFmpPrivate
->MicrocodePatchAddress
;
703 MicrocodePatchRegionSize
= MicrocodeFmpPrivate
->MicrocodePatchRegionSize
;
705 MicrocodePatchScratchBuffer
= AllocateZeroPool (MicrocodePatchRegionSize
);
706 if (MicrocodePatchScratchBuffer
== NULL
) {
707 DEBUG((DEBUG_ERROR
, "Fail to allocate Microcode Scratch buffer\n"));
708 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
709 return EFI_OUT_OF_RESOURCES
;
711 ScratchBufferPtr
= MicrocodePatchScratchBuffer
;
712 ScratchBufferSize
= 0;
715 // Target data collection
719 NextMicrocodeEntryPoint
= NULL
;
720 if (TargetMicrocodeEntryPoint
!= NULL
) {
721 if (TargetMicrocodeEntryPoint
->DataSize
== 0) {
722 TargetTotalSize
= 2048;
724 TargetTotalSize
= TargetMicrocodeEntryPoint
->TotalSize
;
726 DEBUG((DEBUG_INFO
, " TargetTotalSize - 0x%x\n", TargetTotalSize
));
727 NextMicrocodeEntryPoint
= GetNextMicrocode(MicrocodeFmpPrivate
, TargetMicrocodeEntryPoint
);
728 DEBUG((DEBUG_INFO
, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint
));
729 if (NextMicrocodeEntryPoint
!= NULL
) {
730 ASSERT ((UINTN
)NextMicrocodeEntryPoint
>= ((UINTN
)TargetMicrocodeEntryPoint
+ TargetTotalSize
));
731 AvailableSize
= (UINTN
)NextMicrocodeEntryPoint
- (UINTN
)TargetMicrocodeEntryPoint
;
733 AvailableSize
= (UINTN
)MicrocodePatchAddress
+ MicrocodePatchRegionSize
- (UINTN
)TargetMicrocodeEntryPoint
;
735 DEBUG((DEBUG_INFO
, " AvailableSize - 0x%x\n", AvailableSize
));
737 ASSERT (AvailableSize
>= TargetTotalSize
);
738 UsedRegionSize
= GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate
);
739 DEBUG((DEBUG_INFO
, " UsedRegionSize - 0x%x\n", UsedRegionSize
));
740 ASSERT (UsedRegionSize
>= TargetTotalSize
);
741 if (TargetMicrocodeEntryPoint
!= NULL
) {
742 ASSERT ((UINTN
)MicrocodePatchAddress
+ UsedRegionSize
>= ((UINTN
)TargetMicrocodeEntryPoint
+ TargetTotalSize
));
745 // Total Size means the Microcode data size.
746 // Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.
749 // +------+-----------+-----+------+===================+
750 // | MCU1 | Microcode | PAD | MCU2 | Empty |
751 // +------+-----------+-----+------+===================+
753 // |<-AvailableSize->|
754 // |<- UsedRegionSize ->|
757 // +------+-----------+===================+
758 // | MCU | Microcode | Empty |
759 // +------+-----------+===================+
761 // |<- AvailableSize ->|
762 // |<-UsedRegionSize->|
766 // Update based on policy
770 // 1. If there is enough space to update old one in situ, replace old microcode in situ.
772 if (AvailableSize
>= ImageSize
) {
773 DEBUG((DEBUG_INFO
, "Replace old microcode in situ\n"));
775 // +------+------------+------+===================+
776 // |Other1| Old Image |Other2| Empty |
777 // +------+------------+------+===================+
779 // +------+---------+--+------+===================+
780 // |Other1|New Image|FF|Other2| Empty |
781 // +------+---------+--+------+===================+
783 // 1.1. Copy new image
784 CopyMem (ScratchBufferPtr
, Image
, ImageSize
);
785 ScratchBufferSize
+= ImageSize
;
786 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
788 RestSize
= AvailableSize
- ImageSize
;
790 SetMem (ScratchBufferPtr
, RestSize
, 0xFF);
791 ScratchBufferSize
+= RestSize
;
792 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
794 Status
= UpdateMicrocode((UINTN
)TargetMicrocodeEntryPoint
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
799 // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.
801 if (MicrocodePatchRegionSize
- (UsedRegionSize
- TargetTotalSize
) >= ImageSize
) {
802 if (TargetMicrocodeEntryPoint
== NULL
) {
803 DEBUG((DEBUG_INFO
, "Append new microcode\n"));
805 // +------+------------+------+===================+
806 // |Other1| Other |Other2| Empty |
807 // +------+------------+------+===================+
809 // +------+------------+------+-----------+=======+
810 // |Other1| Other |Other2| New Image | Empty |
811 // +------+------------+------+-----------+=======+
813 Status
= UpdateMicrocode((UINTN
)MicrocodePatchAddress
+ UsedRegionSize
, Image
, ImageSize
, LastAttemptStatus
);
815 DEBUG((DEBUG_INFO
, "Reorg and replace old microcode\n"));
817 // +------+------------+------+===================+
818 // |Other1| Old Image |Other2| Empty |
819 // +------+------------+------+===================+
821 // +------+---------------+------+================+
822 // |Other1| New Image |Other2| Empty |
823 // +------+---------------+------+================+
825 // 2.1. Copy new image
826 CopyMem (ScratchBufferPtr
, Image
, ImageSize
);
827 ScratchBufferSize
+= ImageSize
;
828 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
829 // 2.2. Copy rest images after the old image.
830 if (NextMicrocodeEntryPoint
!= 0) {
831 RestSize
= (UINTN
)MicrocodePatchAddress
+ UsedRegionSize
- ((UINTN
)NextMicrocodeEntryPoint
);
832 CopyMem (ScratchBufferPtr
, (UINT8
*)TargetMicrocodeEntryPoint
+ TargetTotalSize
, RestSize
);
833 ScratchBufferSize
+= RestSize
;
834 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
836 Status
= UpdateMicrocode((UINTN
)TargetMicrocodeEntryPoint
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
842 // 3. The new image can be put in MCU region, but not all others can be put.
843 // So all the unused MCU is removed.
845 if (MicrocodePatchRegionSize
>= ImageSize
) {
847 // +------+------------+------+===================+
848 // |Other1| Old Image |Other2| Empty |
849 // +------+------------+------+===================+
851 // +-------------------------------------+--------+
852 // | New Image | Other |
853 // +-------------------------------------+--------+
855 DEBUG((DEBUG_INFO
, "Add new microcode from beginning\n"));
857 MicrocodeCount
= MicrocodeFmpPrivate
->DescriptorCount
;
858 MicrocodeInfo
= MicrocodeFmpPrivate
->MicrocodeInfo
;
860 // 3.1. Copy new image
861 CopyMem (ScratchBufferPtr
, Image
, ImageSize
);
862 ScratchBufferSize
+= ImageSize
;
863 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
864 // 3.2. Copy some others to rest buffer
865 for (Index
= 0; Index
< MicrocodeCount
; Index
++) {
866 if (!MicrocodeInfo
[Index
].InUse
) {
869 if (MicrocodeInfo
[Index
].MicrocodeEntryPoint
== TargetMicrocodeEntryPoint
) {
872 if (MicrocodeInfo
[Index
].TotalSize
<= MicrocodePatchRegionSize
- ScratchBufferSize
) {
873 CopyMem (ScratchBufferPtr
, MicrocodeInfo
[Index
].MicrocodeEntryPoint
, MicrocodeInfo
[Index
].TotalSize
);
874 ScratchBufferSize
+= MicrocodeInfo
[Index
].TotalSize
;
875 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
879 RestSize
= MicrocodePatchRegionSize
- ScratchBufferSize
;
881 SetMem (ScratchBufferPtr
, RestSize
, 0xFF);
882 ScratchBufferSize
+= RestSize
;
883 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
885 Status
= UpdateMicrocode((UINTN
)MicrocodePatchAddress
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
890 // 4. The new image size is bigger than the whole MCU region.
892 DEBUG((DEBUG_ERROR
, "Microcode too big\n"));
893 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
894 Status
= EFI_OUT_OF_RESOURCES
;
902 Caution: This function may receive untrusted input.
904 @param[in] MicrocodeFmpPrivate The Microcode driver private data
905 @param[in] Image The Microcode image buffer.
906 @param[in] ImageSize The size of Microcode image buffer in bytes.
907 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
908 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
909 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
910 details for the aborted operation. The buffer is allocated by this function
911 with AllocatePool(), and it is the caller's responsibility to free it with a
914 @retval EFI_SUCCESS The Microcode image is written.
915 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt.
916 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
917 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
918 @retval EFI_WRITE_PROTECTED The flash device is read only.
922 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
925 OUT UINT32
*LastAttemptVersion
,
926 OUT UINT32
*LastAttemptStatus
,
927 OUT CHAR16
**AbortReason
932 CPU_MICROCODE_HEADER
*TargetMicrocodeEntryPoint
;
933 UINTN TargetCpuIndex
;
934 UINTN TargetMicrcodeIndex
;
937 // MCU must be 16 bytes aligned
939 AlignedImage
= AllocateCopyPool(ImageSize
, Image
);
940 if (AlignedImage
== NULL
) {
941 DEBUG((DEBUG_ERROR
, "Fail to allocate aligned image\n"));
942 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
943 return EFI_OUT_OF_RESOURCES
;
946 *LastAttemptVersion
= ((CPU_MICROCODE_HEADER
*)Image
)->UpdateRevision
;
947 TargetCpuIndex
= (UINTN
)-1;
948 Status
= VerifyMicrocode(MicrocodeFmpPrivate
, AlignedImage
, ImageSize
, TRUE
, LastAttemptStatus
, AbortReason
, &TargetCpuIndex
);
949 if (EFI_ERROR(Status
)) {
950 DEBUG((DEBUG_ERROR
, "Fail to verify Microcode Region\n"));
951 FreePool(AlignedImage
);
954 DEBUG((DEBUG_INFO
, "Pass VerifyMicrocode\n"));
956 DEBUG((DEBUG_INFO
, " TargetCpuIndex - 0x%x\n", TargetCpuIndex
));
957 ASSERT (TargetCpuIndex
< MicrocodeFmpPrivate
->ProcessorCount
);
958 TargetMicrcodeIndex
= MicrocodeFmpPrivate
->ProcessorInfo
[TargetCpuIndex
].MicrocodeIndex
;
959 DEBUG((DEBUG_INFO
, " TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex
));
960 if (TargetMicrcodeIndex
!= (UINTN
)-1) {
961 ASSERT (TargetMicrcodeIndex
< MicrocodeFmpPrivate
->DescriptorCount
);
962 TargetMicrocodeEntryPoint
= MicrocodeFmpPrivate
->MicrocodeInfo
[TargetMicrcodeIndex
].MicrocodeEntryPoint
;
964 TargetMicrocodeEntryPoint
= NULL
;
966 DEBUG((DEBUG_INFO
, " TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint
));
968 Status
= UpdateMicrocodeFlashRegion(
970 TargetMicrocodeEntryPoint
,
976 FreePool(AlignedImage
);