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 - 2018, Intel Corporation. All rights reserved.<BR>
12 SPDX-License-Identifier: BSD-2-Clause-Patent
16 #include "MicrocodeUpdate.h"
21 @param[out] MicrocodePatchAddress The address of Microcode
22 @param[out] MicrocodePatchRegionSize The region size of Microcode
24 @retval TRUE The Microcode region is returned.
25 @retval FALSE No Microcode region.
29 OUT VOID
**MicrocodePatchAddress
,
30 OUT UINTN
*MicrocodePatchRegionSize
33 *MicrocodePatchAddress
= (VOID
*)(UINTN
)PcdGet64(PcdCpuMicrocodePatchAddress
);
34 *MicrocodePatchRegionSize
= (UINTN
)PcdGet64(PcdCpuMicrocodePatchRegionSize
);
36 if ((*MicrocodePatchAddress
== NULL
) || (*MicrocodePatchRegionSize
== 0)) {
44 Get Microcode update signature of currently loaded Microcode update.
46 @return Microcode signature.
50 GetCurrentMicrocodeSignature (
56 AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID
, 0);
57 AsmCpuid(CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, NULL
);
58 Signature
= AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID
);
59 return (UINT32
)RShiftU64(Signature
, 32);
63 Get current processor signature.
65 @return current processor signature.
68 GetCurrentProcessorSignature (
73 AsmCpuid(CPUID_VERSION_INFO
, &RegEax
, NULL
, NULL
, NULL
);
78 Get current platform ID.
80 @return current platform ID.
83 GetCurrentPlatformId (
89 PlatformId
= (UINT8
)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID
, 50, 52);
96 @param[in] Address The address of new Microcode.
98 @return Loaded Microcode signature.
106 AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG
, Address
);
107 return GetCurrentMicrocodeSignature();
111 Load Microcode on an Application Processor.
112 The function prototype for invoking a function on an Application Processor.
114 @param[in,out] Buffer The pointer to private data buffer.
122 MICROCODE_LOAD_BUFFER
*MicrocodeLoadBuffer
;
124 MicrocodeLoadBuffer
= Buffer
;
125 MicrocodeLoadBuffer
->Revision
= LoadMicrocode (MicrocodeLoadBuffer
->Address
);
129 Load new Microcode on this processor
131 @param[in] MicrocodeFmpPrivate The Microcode driver private data
132 @param[in] CpuIndex The index of the processor.
133 @param[in] Address The address of new Microcode.
135 @return Loaded Microcode signature.
139 LoadMicrocodeOnThis (
140 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
146 EFI_MP_SERVICES_PROTOCOL
*MpService
;
147 MICROCODE_LOAD_BUFFER MicrocodeLoadBuffer
;
149 if (CpuIndex
== MicrocodeFmpPrivate
->BspIndex
) {
150 return LoadMicrocode (Address
);
152 MpService
= MicrocodeFmpPrivate
->MpService
;
153 MicrocodeLoadBuffer
.Address
= Address
;
154 MicrocodeLoadBuffer
.Revision
= 0;
155 Status
= MpService
->StartupThisAP (
161 &MicrocodeLoadBuffer
,
164 ASSERT_EFI_ERROR(Status
);
165 return MicrocodeLoadBuffer
.Revision
;
170 Collect processor information.
171 The function prototype for invoking a function on an Application Processor.
173 @param[in,out] Buffer The pointer to private data buffer.
177 CollectProcessorInfo (
181 PROCESSOR_INFO
*ProcessorInfo
;
183 ProcessorInfo
= Buffer
;
184 ProcessorInfo
->ProcessorSignature
= GetCurrentProcessorSignature();
185 ProcessorInfo
->PlatformId
= GetCurrentPlatformId();
186 ProcessorInfo
->MicrocodeRevision
= GetCurrentMicrocodeSignature();
190 Get current Microcode information.
192 The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
193 in MicrocodeFmpPrivate must be initialized.
195 The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
196 in MicrocodeFmpPrivate may not be avaiable in this function.
198 @param[in] MicrocodeFmpPrivate The Microcode driver private data
199 @param[in] DescriptorCount The count of Microcode ImageDescriptor allocated.
200 @param[out] ImageDescriptor Microcode ImageDescriptor
201 @param[out] MicrocodeInfo Microcode information
203 @return Microcode count
207 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
208 IN UINTN DescriptorCount
, OPTIONAL
209 OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR
*ImageDescriptor
, OPTIONAL
210 OUT MICROCODE_INFO
*MicrocodeInfo OPTIONAL
213 VOID
*MicrocodePatchAddress
;
214 UINTN MicrocodePatchRegionSize
;
215 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
219 UINT64 ImageAttributes
;
222 UINT32 AttemptStatus
;
223 UINTN TargetCpuIndex
;
225 MicrocodePatchAddress
= MicrocodeFmpPrivate
->MicrocodePatchAddress
;
226 MicrocodePatchRegionSize
= MicrocodeFmpPrivate
->MicrocodePatchRegionSize
;
228 DEBUG((DEBUG_INFO
, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress
, MicrocodePatchRegionSize
));
232 MicrocodeEnd
= (UINTN
)MicrocodePatchAddress
+ MicrocodePatchRegionSize
;
233 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (UINTN
) MicrocodePatchAddress
;
235 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1 && MicrocodeEntryPoint
->LoaderRevision
== 0x1) {
237 // It is the microcode header. It is not the padding data between microcode patches
238 // becasue the padding data should not include 0x00000001 and it should be the repeated
239 // byte format (like 0xXYXYXYXY....).
241 if (MicrocodeEntryPoint
->DataSize
== 0) {
244 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
247 TargetCpuIndex
= (UINTN
)-1;
248 Status
= VerifyMicrocode(MicrocodeFmpPrivate
, MicrocodeEntryPoint
, TotalSize
, FALSE
, &AttemptStatus
, NULL
, &TargetCpuIndex
);
249 if (!EFI_ERROR(Status
)) {
251 ASSERT (TargetCpuIndex
< MicrocodeFmpPrivate
->ProcessorCount
);
252 MicrocodeFmpPrivate
->ProcessorInfo
[TargetCpuIndex
].MicrocodeIndex
= Count
;
257 if (ImageDescriptor
!= NULL
&& DescriptorCount
> Count
) {
258 ImageDescriptor
[Count
].ImageIndex
= (UINT8
)(Count
+ 1);
259 CopyGuid (&ImageDescriptor
[Count
].ImageTypeId
, &gMicrocodeFmpImageTypeIdGuid
);
260 ImageDescriptor
[Count
].ImageId
= LShiftU64(MicrocodeEntryPoint
->ProcessorFlags
, 32) + MicrocodeEntryPoint
->ProcessorSignature
.Uint32
;
261 ImageDescriptor
[Count
].ImageIdName
= NULL
;
262 ImageDescriptor
[Count
].Version
= MicrocodeEntryPoint
->UpdateRevision
;
263 ImageDescriptor
[Count
].VersionName
= NULL
;
264 ImageDescriptor
[Count
].Size
= TotalSize
;
265 ImageAttributes
= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE
| IMAGE_ATTRIBUTE_RESET_REQUIRED
;
267 ImageAttributes
|= IMAGE_ATTRIBUTE_IN_USE
;
269 ImageDescriptor
[Count
].AttributesSupported
= ImageAttributes
| IMAGE_ATTRIBUTE_IN_USE
;
270 ImageDescriptor
[Count
].AttributesSetting
= ImageAttributes
;
271 ImageDescriptor
[Count
].Compatibilities
= 0;
272 ImageDescriptor
[Count
].LowestSupportedImageVersion
= MicrocodeEntryPoint
->UpdateRevision
; // do not support rollback
273 ImageDescriptor
[Count
].LastAttemptVersion
= 0;
274 ImageDescriptor
[Count
].LastAttemptStatus
= 0;
275 ImageDescriptor
[Count
].HardwareInstance
= 0;
277 if (MicrocodeInfo
!= NULL
&& DescriptorCount
> Count
) {
278 MicrocodeInfo
[Count
].MicrocodeEntryPoint
= MicrocodeEntryPoint
;
279 MicrocodeInfo
[Count
].TotalSize
= TotalSize
;
280 MicrocodeInfo
[Count
].InUse
= IsInUse
;
284 // It is the padding data between the microcode patches for microcode patches alignment.
285 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
286 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
287 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
288 // find the next possible microcode patch header.
290 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + SIZE_1KB
);
295 ASSERT(Count
< 0xFF);
298 // Get the next patch.
300 MicrocodeEntryPoint
= (CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + TotalSize
);
301 } while (((UINTN
) MicrocodeEntryPoint
< MicrocodeEnd
));
307 Return matched processor information.
309 @param[in] MicrocodeFmpPrivate The Microcode driver private data
310 @param[in] ProcessorSignature The processor signature to be matched
311 @param[in] ProcessorFlags The processor flags to be matched
312 @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
313 On output, the index of target CPU which matches the Microcode.
315 @return matched processor information.
318 GetMatchedProcessor (
319 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
320 IN UINT32 ProcessorSignature
,
321 IN UINT32 ProcessorFlags
,
322 IN OUT UINTN
*TargetCpuIndex
327 if (*TargetCpuIndex
!= (UINTN
)-1) {
328 Index
= *TargetCpuIndex
;
329 if ((ProcessorSignature
== MicrocodeFmpPrivate
->ProcessorInfo
[Index
].ProcessorSignature
) &&
330 ((ProcessorFlags
& (1 << MicrocodeFmpPrivate
->ProcessorInfo
[Index
].PlatformId
)) != 0)) {
331 return &MicrocodeFmpPrivate
->ProcessorInfo
[Index
];
337 for (Index
= 0; Index
< MicrocodeFmpPrivate
->ProcessorCount
; Index
++) {
338 if ((ProcessorSignature
== MicrocodeFmpPrivate
->ProcessorInfo
[Index
].ProcessorSignature
) &&
339 ((ProcessorFlags
& (1 << MicrocodeFmpPrivate
->ProcessorInfo
[Index
].PlatformId
)) != 0)) {
340 *TargetCpuIndex
= Index
;
341 return &MicrocodeFmpPrivate
->ProcessorInfo
[Index
];
350 Caution: This function may receive untrusted input.
352 @param[in] MicrocodeFmpPrivate The Microcode driver private data
353 @param[in] Image The Microcode image buffer.
354 @param[in] ImageSize The size of Microcode image buffer in bytes.
355 @param[in] TryLoad Try to load Microcode or not.
356 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
357 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
358 details for the aborted operation. The buffer is allocated by this function
359 with AllocatePool(), and it is the caller's responsibility to free it with a
361 @param[in, out] TargetCpuIndex On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
362 On output, the index of target CPU which matches the Microcode.
364 @retval EFI_SUCCESS The Microcode image passes verification.
365 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupted.
366 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
367 @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or ProcessorFlags is incorrect.
368 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
372 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
376 OUT UINT32
*LastAttemptStatus
,
377 OUT CHAR16
**AbortReason
, OPTIONAL
378 IN OUT UINTN
*TargetCpuIndex
382 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
385 UINT32 CurrentRevision
;
386 PROCESSOR_INFO
*ProcessorInfo
;
387 UINT32 InCompleteCheckSum32
;
389 UINTN ExtendedTableLength
;
390 UINT32 ExtendedTableCount
;
391 CPU_MICROCODE_EXTENDED_TABLE
*ExtendedTable
;
392 CPU_MICROCODE_EXTENDED_TABLE_HEADER
*ExtendedTableHeader
;
393 BOOLEAN CorrectMicrocode
;
396 // Check HeaderVersion
398 MicrocodeEntryPoint
= Image
;
399 if (MicrocodeEntryPoint
->HeaderVersion
!= 0x1) {
400 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on HeaderVersion\n"));
401 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
402 if (AbortReason
!= NULL
) {
403 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidHeaderVersion"), L
"InvalidHeaderVersion");
405 return EFI_INCOMPATIBLE_VERSION
;
408 // Check LoaderRevision
410 if (MicrocodeEntryPoint
->LoaderRevision
!= 0x1) {
411 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on LoaderRevision\n"));
412 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
413 if (AbortReason
!= NULL
) {
414 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidLoaderVersion"), L
"InvalidLoaderVersion");
416 return EFI_INCOMPATIBLE_VERSION
;
421 if (MicrocodeEntryPoint
->DataSize
== 0) {
424 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
426 if (TotalSize
<= sizeof(CPU_MICROCODE_HEADER
)) {
427 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - TotalSize too small\n"));
428 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
429 if (AbortReason
!= NULL
) {
430 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidTotalSize"), L
"InvalidTotalSize");
432 return EFI_VOLUME_CORRUPTED
;
434 if ((TotalSize
& (SIZE_1KB
- 1)) != 0) {
435 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - TotalSize is not multiples of 1024 bytes (1 KBytes)\n"));
436 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
437 if (AbortReason
!= NULL
) {
438 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidTotalSize"), L
"InvalidTotalSize");
440 return EFI_VOLUME_CORRUPTED
;
442 if (TotalSize
!= ImageSize
) {
443 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - TotalSize not equal to ImageSize\n"));
444 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
445 if (AbortReason
!= NULL
) {
446 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidTotalSize"), L
"InvalidTotalSize");
448 return EFI_VOLUME_CORRUPTED
;
453 if (MicrocodeEntryPoint
->DataSize
== 0) {
454 DataSize
= 2048 - sizeof(CPU_MICROCODE_HEADER
);
456 DataSize
= MicrocodeEntryPoint
->DataSize
;
458 if (DataSize
> TotalSize
- sizeof(CPU_MICROCODE_HEADER
)) {
459 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - DataSize too big\n"));
460 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
461 if (AbortReason
!= NULL
) {
462 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidDataSize"), L
"InvalidDataSize");
464 return EFI_VOLUME_CORRUPTED
;
466 if ((DataSize
& 0x3) != 0) {
467 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - DataSize is not multiples of DWORDs\n"));
468 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
469 if (AbortReason
!= NULL
) {
470 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidDataSize"), L
"InvalidDataSize");
472 return EFI_VOLUME_CORRUPTED
;
477 CheckSum32
= CalculateSum32((UINT32
*)MicrocodeEntryPoint
, DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
478 if (CheckSum32
!= 0) {
479 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on CheckSum32\n"));
480 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT
;
481 if (AbortReason
!= NULL
) {
482 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidChecksum"), L
"InvalidChecksum");
484 return EFI_VOLUME_CORRUPTED
;
486 InCompleteCheckSum32
= CheckSum32
;
487 InCompleteCheckSum32
-= MicrocodeEntryPoint
->ProcessorSignature
.Uint32
;
488 InCompleteCheckSum32
-= MicrocodeEntryPoint
->ProcessorFlags
;
489 InCompleteCheckSum32
-= MicrocodeEntryPoint
->Checksum
;
492 // Check ProcessorSignature/ProcessorFlags
495 ProcessorInfo
= GetMatchedProcessor (MicrocodeFmpPrivate
, MicrocodeEntryPoint
->ProcessorSignature
.Uint32
, MicrocodeEntryPoint
->ProcessorFlags
, TargetCpuIndex
);
496 if (ProcessorInfo
== NULL
) {
497 CorrectMicrocode
= FALSE
;
498 ExtendedTableLength
= TotalSize
- (DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
499 if (ExtendedTableLength
!= 0) {
501 // Extended Table exist, check if the CPU in support list
503 ExtendedTableHeader
= (CPU_MICROCODE_EXTENDED_TABLE_HEADER
*)((UINT8
*)(MicrocodeEntryPoint
) + DataSize
+ sizeof(CPU_MICROCODE_HEADER
));
505 // Calculate Extended Checksum
507 if ((ExtendedTableLength
> sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) && ((ExtendedTableLength
& 0x3) == 0)) {
508 CheckSum32
= CalculateSum32((UINT32
*)ExtendedTableHeader
, ExtendedTableLength
);
509 if (CheckSum32
!= 0) {
511 // Checksum incorrect
513 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - The checksum for extended table is incorrect\n"));
518 ExtendedTableCount
= ExtendedTableHeader
->ExtendedSignatureCount
;
519 if (ExtendedTableCount
> (ExtendedTableLength
- sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE
)) {
520 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - ExtendedTableCount %d is too big\n", ExtendedTableCount
));
522 ExtendedTable
= (CPU_MICROCODE_EXTENDED_TABLE
*)(ExtendedTableHeader
+ 1);
523 for (Index
= 0; Index
< ExtendedTableCount
; Index
++) {
524 CheckSum32
= InCompleteCheckSum32
;
525 CheckSum32
+= ExtendedTable
->ProcessorSignature
.Uint32
;
526 CheckSum32
+= ExtendedTable
->ProcessorFlag
;
527 CheckSum32
+= ExtendedTable
->Checksum
;
528 if (CheckSum32
!= 0) {
529 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - The checksum for ExtendedTable entry with index 0x%x is incorrect\n", Index
));
534 ProcessorInfo
= GetMatchedProcessor (MicrocodeFmpPrivate
, ExtendedTable
->ProcessorSignature
.Uint32
, ExtendedTable
->ProcessorFlag
, TargetCpuIndex
);
535 if (ProcessorInfo
!= NULL
) {
539 CorrectMicrocode
= TRUE
;
549 if (!CorrectMicrocode
) {
551 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on Current ProcessorSignature/ProcessorFlags\n"));
553 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION
;
554 if (AbortReason
!= NULL
) {
555 *AbortReason
= AllocateCopyPool(sizeof(L
"UnsupportedProcessorSignature/ProcessorFlags"), L
"UnsupportedProcessorSignature/ProcessorFlags");
557 return EFI_UNSUPPORTED
;
562 // Check UpdateRevision
564 CurrentRevision
= ProcessorInfo
->MicrocodeRevision
;
565 if ((MicrocodeEntryPoint
->UpdateRevision
< CurrentRevision
) ||
566 (TryLoad
&& (MicrocodeEntryPoint
->UpdateRevision
== CurrentRevision
))) {
568 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on UpdateRevision\n"));
570 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION
;
571 if (AbortReason
!= NULL
) {
572 *AbortReason
= AllocateCopyPool(sizeof(L
"IncorrectRevision"), L
"IncorrectRevision");
574 return EFI_INCOMPATIBLE_VERSION
;
581 CurrentRevision
= LoadMicrocodeOnThis(MicrocodeFmpPrivate
, ProcessorInfo
->CpuIndex
, (UINTN
)MicrocodeEntryPoint
+ sizeof(CPU_MICROCODE_HEADER
));
582 if (MicrocodeEntryPoint
->UpdateRevision
!= CurrentRevision
) {
583 DEBUG((DEBUG_ERROR
, "VerifyMicrocode - fail on LoadMicrocode\n"));
584 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR
;
585 if (AbortReason
!= NULL
) {
586 *AbortReason
= AllocateCopyPool(sizeof(L
"InvalidData"), L
"InvalidData");
588 return EFI_SECURITY_VIOLATION
;
596 Get next Microcode entrypoint.
598 @param[in] MicrocodeFmpPrivate The Microcode driver private data
599 @param[in] MicrocodeEntryPoint Current Microcode entrypoint
601 @return next Microcode entrypoint.
603 CPU_MICROCODE_HEADER
*
605 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
606 IN CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
611 for (Index
= 0; Index
< MicrocodeFmpPrivate
->DescriptorCount
; Index
++) {
612 if (MicrocodeEntryPoint
== MicrocodeFmpPrivate
->MicrocodeInfo
[Index
].MicrocodeEntryPoint
) {
613 if (Index
== (UINTN
)MicrocodeFmpPrivate
->DescriptorCount
- 1) {
618 return MicrocodeFmpPrivate
->MicrocodeInfo
[Index
+ 1].MicrocodeEntryPoint
;
628 Get next FIT Microcode entrypoint.
630 @param[in] MicrocodeFmpPrivate The Microcode driver private data
631 @param[in] MicrocodeEntryPoint Current Microcode entrypoint
633 @return next FIT Microcode entrypoint.
635 CPU_MICROCODE_HEADER
*
636 GetNextFitMicrocode (
637 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
638 IN CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
643 for (Index
= 0; Index
< MicrocodeFmpPrivate
->FitMicrocodeEntryCount
; Index
++) {
644 if (MicrocodeEntryPoint
== MicrocodeFmpPrivate
->FitMicrocodeInfo
[Index
].MicrocodeEntryPoint
) {
645 if (Index
== (UINTN
) MicrocodeFmpPrivate
->FitMicrocodeEntryCount
- 1) {
650 return MicrocodeFmpPrivate
->FitMicrocodeInfo
[Index
+ 1].MicrocodeEntryPoint
;
660 Find empty FIT Microcode entrypoint.
662 @param[in] MicrocodeFmpPrivate The Microcode driver private data
663 @param[in] ImageSize The size of Microcode image buffer in bytes.
664 @param[out] AvailableSize Available size of the empty FIT Microcode entrypoint.
666 @return Empty FIT Microcode entrypoint.
668 CPU_MICROCODE_HEADER
*
669 FindEmptyFitMicrocode (
670 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
672 OUT UINTN
*AvailableSize
676 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
677 CPU_MICROCODE_HEADER
*NextMicrocodeEntryPoint
;
678 VOID
*MicrocodePatchAddress
;
679 UINTN MicrocodePatchRegionSize
;
681 MicrocodePatchAddress
= MicrocodeFmpPrivate
->MicrocodePatchAddress
;
682 MicrocodePatchRegionSize
= MicrocodeFmpPrivate
->MicrocodePatchRegionSize
;
684 for (Index
= 0; Index
< MicrocodeFmpPrivate
->FitMicrocodeEntryCount
; Index
++) {
685 if (MicrocodeFmpPrivate
->FitMicrocodeInfo
[Index
].Empty
) {
686 MicrocodeEntryPoint
= MicrocodeFmpPrivate
->FitMicrocodeInfo
[Index
].MicrocodeEntryPoint
;
687 NextMicrocodeEntryPoint
= GetNextFitMicrocode (MicrocodeFmpPrivate
, MicrocodeEntryPoint
);
688 if (NextMicrocodeEntryPoint
!= NULL
) {
689 *AvailableSize
= (UINTN
) NextMicrocodeEntryPoint
- (UINTN
) MicrocodeEntryPoint
;
691 *AvailableSize
= (UINTN
) MicrocodePatchAddress
+ MicrocodePatchRegionSize
- (UINTN
) MicrocodeEntryPoint
;
693 if (*AvailableSize
>= ImageSize
) {
694 return MicrocodeEntryPoint
;
703 Find unused FIT Microcode entrypoint.
705 @param[in] MicrocodeFmpPrivate The Microcode driver private data
706 @param[in] ImageSize The size of Microcode image buffer in bytes.
707 @param[out] AvailableSize Available size of the unused FIT Microcode entrypoint.
709 @return Unused FIT Microcode entrypoint.
711 CPU_MICROCODE_HEADER
*
712 FindUnusedFitMicrocode (
713 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
715 OUT UINTN
*AvailableSize
719 CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
720 CPU_MICROCODE_HEADER
*NextMicrocodeEntryPoint
;
721 VOID
*MicrocodePatchAddress
;
722 UINTN MicrocodePatchRegionSize
;
724 MicrocodePatchAddress
= MicrocodeFmpPrivate
->MicrocodePatchAddress
;
725 MicrocodePatchRegionSize
= MicrocodeFmpPrivate
->MicrocodePatchRegionSize
;
727 for (Index
= 0; Index
< MicrocodeFmpPrivate
->FitMicrocodeEntryCount
; Index
++) {
728 if (!MicrocodeFmpPrivate
->FitMicrocodeInfo
[Index
].InUse
) {
729 MicrocodeEntryPoint
= MicrocodeFmpPrivate
->FitMicrocodeInfo
[Index
].MicrocodeEntryPoint
;
730 NextMicrocodeEntryPoint
= GetNextFitMicrocode (MicrocodeFmpPrivate
, MicrocodeEntryPoint
);
731 if (NextMicrocodeEntryPoint
!= NULL
) {
732 *AvailableSize
= (UINTN
) NextMicrocodeEntryPoint
- (UINTN
) MicrocodeEntryPoint
;
734 *AvailableSize
= (UINTN
) MicrocodePatchAddress
+ MicrocodePatchRegionSize
- (UINTN
) MicrocodeEntryPoint
;
736 if (*AvailableSize
>= ImageSize
) {
737 return MicrocodeEntryPoint
;
746 Get current Microcode used region size.
748 @param[in] MicrocodeFmpPrivate The Microcode driver private data
750 @return current Microcode used region size.
753 GetCurrentMicrocodeUsedRegionSize (
754 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
757 if (MicrocodeFmpPrivate
->DescriptorCount
== 0) {
761 return (UINTN
)MicrocodeFmpPrivate
->MicrocodeInfo
[MicrocodeFmpPrivate
->DescriptorCount
- 1].MicrocodeEntryPoint
762 + (UINTN
)MicrocodeFmpPrivate
->MicrocodeInfo
[MicrocodeFmpPrivate
->DescriptorCount
- 1].TotalSize
763 - (UINTN
)MicrocodeFmpPrivate
->MicrocodePatchAddress
;
769 @param[in] Address The flash address of Microcode.
770 @param[in] Image The Microcode image buffer.
771 @param[in] ImageSize The size of Microcode image buffer in bytes.
772 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
774 @retval EFI_SUCCESS The Microcode image is updated.
775 @retval EFI_WRITE_PROTECTED The flash device is read only.
782 OUT UINT32
*LastAttemptStatus
787 DEBUG((DEBUG_INFO
, "PlatformUpdate:"));
788 DEBUG((DEBUG_INFO
, " Address - 0x%lx,", Address
));
789 DEBUG((DEBUG_INFO
, " Length - 0x%x\n", ImageSize
));
791 Status
= MicrocodeFlashWrite (
796 if (!EFI_ERROR(Status
)) {
797 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_SUCCESS
;
799 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL
;
805 Update Microcode flash region with FIT.
807 @param[in] MicrocodeFmpPrivate The Microcode driver private data
808 @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated
809 @param[in] Image The Microcode image buffer.
810 @param[in] ImageSize The size of Microcode image buffer in bytes.
811 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
813 @retval EFI_SUCCESS The Microcode image is written.
814 @retval EFI_WRITE_PROTECTED The flash device is read only.
817 UpdateMicrocodeFlashRegionWithFit (
818 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
819 IN CPU_MICROCODE_HEADER
*TargetMicrocodeEntryPoint
,
822 OUT UINT32
*LastAttemptStatus
825 VOID
*MicrocodePatchAddress
;
826 UINTN MicrocodePatchRegionSize
;
827 UINTN TargetTotalSize
;
829 VOID
*MicrocodePatchScratchBuffer
;
830 UINT8
*ScratchBufferPtr
;
831 UINTN ScratchBufferSize
;
834 VOID
*NextMicrocodeEntryPoint
;
835 VOID
*EmptyFitMicrocodeEntry
;
836 VOID
*UnusedFitMicrocodeEntry
;
838 DEBUG((DEBUG_INFO
, "UpdateMicrocodeFlashRegionWithFit: Image - 0x%x, size - 0x%x\n", Image
, ImageSize
));
840 MicrocodePatchAddress
= MicrocodeFmpPrivate
->MicrocodePatchAddress
;
841 MicrocodePatchRegionSize
= MicrocodeFmpPrivate
->MicrocodePatchRegionSize
;
843 MicrocodePatchScratchBuffer
= AllocateZeroPool (MicrocodePatchRegionSize
);
844 if (MicrocodePatchScratchBuffer
== NULL
) {
845 DEBUG((DEBUG_ERROR
, "Fail to allocate Microcode Scratch buffer\n"));
846 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
847 return EFI_OUT_OF_RESOURCES
;
849 ScratchBufferPtr
= MicrocodePatchScratchBuffer
;
850 ScratchBufferSize
= 0;
853 // Target data collection
857 if (TargetMicrocodeEntryPoint
!= NULL
) {
858 if (TargetMicrocodeEntryPoint
->DataSize
== 0) {
859 TargetTotalSize
= 2048;
861 TargetTotalSize
= TargetMicrocodeEntryPoint
->TotalSize
;
863 DEBUG((DEBUG_INFO
, " TargetTotalSize - 0x%x\n", TargetTotalSize
));
864 NextMicrocodeEntryPoint
= GetNextFitMicrocode (MicrocodeFmpPrivate
, TargetMicrocodeEntryPoint
);
865 DEBUG((DEBUG_INFO
, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint
));
866 if (NextMicrocodeEntryPoint
!= NULL
) {
867 ASSERT ((UINTN
) NextMicrocodeEntryPoint
>= ((UINTN
) TargetMicrocodeEntryPoint
+ TargetTotalSize
));
868 AvailableSize
= (UINTN
) NextMicrocodeEntryPoint
- (UINTN
) TargetMicrocodeEntryPoint
;
870 AvailableSize
= (UINTN
) MicrocodePatchAddress
+ MicrocodePatchRegionSize
- (UINTN
) TargetMicrocodeEntryPoint
;
872 DEBUG((DEBUG_INFO
, " AvailableSize - 0x%x\n", AvailableSize
));
873 ASSERT (AvailableSize
>= TargetTotalSize
);
876 // Total Size means the Microcode size.
877 // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.
880 // +------+-----------+-----+------+===================+
881 // | MCU1 | Microcode | PAD | MCU2 | Empty |
882 // +------+-----------+-----+------+===================+
884 // |<-AvailableSize->|
887 // +------+-----------+===================+
888 // | MCU | Microcode | Empty |
889 // +------+-----------+===================+
891 // |<- AvailableSize ->|
895 // Update based on policy
899 // 1. If there is enough space to update old one in situ, replace old microcode in situ.
901 if (AvailableSize
>= ImageSize
) {
902 DEBUG((DEBUG_INFO
, "Replace old microcode in situ\n"));
904 // +------+------------+------+===================+
905 // |Other | Old Image | ... | Empty |
906 // +------+------------+------+===================+
908 // +------+---------+--+------+===================+
909 // |Other |New Image|FF| ... | Empty |
910 // +------+---------+--+------+===================+
912 // 1.1. Copy new image
913 CopyMem (ScratchBufferPtr
, Image
, ImageSize
);
914 ScratchBufferSize
+= ImageSize
;
915 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
917 RestSize
= AvailableSize
- ImageSize
;
919 SetMem (ScratchBufferPtr
, RestSize
, 0xFF);
920 ScratchBufferSize
+= RestSize
;
921 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
923 Status
= UpdateMicrocode((UINTN
)TargetMicrocodeEntryPoint
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
928 // 2. If there is empty FIT microcode entry with enough space, use it.
930 EmptyFitMicrocodeEntry
= FindEmptyFitMicrocode (MicrocodeFmpPrivate
, ImageSize
, &AvailableSize
);
931 if (EmptyFitMicrocodeEntry
!= NULL
) {
932 DEBUG((DEBUG_INFO
, "Use empty FIT microcode entry\n"));
933 // 2.1. Copy new image
934 CopyMem (ScratchBufferPtr
, Image
, ImageSize
);
935 ScratchBufferSize
+= ImageSize
;
936 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
938 RestSize
= AvailableSize
- ImageSize
;
940 SetMem (ScratchBufferPtr
, RestSize
, 0xFF);
941 ScratchBufferSize
+= RestSize
;
942 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
944 Status
= UpdateMicrocode ((UINTN
) EmptyFitMicrocodeEntry
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
945 if (!EFI_ERROR (Status
) && (TargetMicrocodeEntryPoint
!= NULL
)) {
947 // Empty old microcode.
949 ScratchBufferPtr
= MicrocodePatchScratchBuffer
;
950 SetMem (ScratchBufferPtr
, TargetTotalSize
, 0xFF);
951 ScratchBufferSize
= TargetTotalSize
;
952 ScratchBufferPtr
= (UINT8
*) MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
953 UpdateMicrocode ((UINTN
) TargetMicrocodeEntryPoint
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
959 // 3. If there is unused microcode entry with enough space, use it.
961 UnusedFitMicrocodeEntry
= FindUnusedFitMicrocode (MicrocodeFmpPrivate
, ImageSize
, &AvailableSize
);
962 if (UnusedFitMicrocodeEntry
!= NULL
) {
963 DEBUG((DEBUG_INFO
, "Use unused FIT microcode entry\n"));
964 // 3.1. Copy new image
965 CopyMem (ScratchBufferPtr
, Image
, ImageSize
);
966 ScratchBufferSize
+= ImageSize
;
967 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
969 RestSize
= AvailableSize
- ImageSize
;
971 SetMem (ScratchBufferPtr
, RestSize
, 0xFF);
972 ScratchBufferSize
+= RestSize
;
973 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
975 Status
= UpdateMicrocode ((UINTN
) UnusedFitMicrocodeEntry
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
976 if (!EFI_ERROR (Status
) && (TargetMicrocodeEntryPoint
!= NULL
)) {
978 // Empty old microcode.
980 ScratchBufferPtr
= MicrocodePatchScratchBuffer
;
981 SetMem (ScratchBufferPtr
, TargetTotalSize
, 0xFF);
982 ScratchBufferSize
= TargetTotalSize
;
983 ScratchBufferPtr
= (UINT8
*) MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
984 UpdateMicrocode ((UINTN
) TargetMicrocodeEntryPoint
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
990 // 4. No usable FIT microcode entry.
992 DEBUG((DEBUG_ERROR
, "No usable FIT microcode entry\n"));
993 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
994 Status
= EFI_OUT_OF_RESOURCES
;
1000 Update Microcode flash region.
1002 @param[in] MicrocodeFmpPrivate The Microcode driver private data
1003 @param[in] TargetMicrocodeEntryPoint Target Microcode entrypoint to be updated
1004 @param[in] Image The Microcode image buffer.
1005 @param[in] ImageSize The size of Microcode image buffer in bytes.
1006 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
1008 @retval EFI_SUCCESS The Microcode image is written.
1009 @retval EFI_WRITE_PROTECTED The flash device is read only.
1012 UpdateMicrocodeFlashRegion (
1013 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
1014 IN CPU_MICROCODE_HEADER
*TargetMicrocodeEntryPoint
,
1017 OUT UINT32
*LastAttemptStatus
1020 VOID
*MicrocodePatchAddress
;
1021 UINTN MicrocodePatchRegionSize
;
1022 UINTN TargetTotalSize
;
1023 UINTN UsedRegionSize
;
1025 VOID
*MicrocodePatchScratchBuffer
;
1026 UINT8
*ScratchBufferPtr
;
1027 UINTN ScratchBufferSize
;
1029 UINTN AvailableSize
;
1030 VOID
*NextMicrocodeEntryPoint
;
1031 MICROCODE_INFO
*MicrocodeInfo
;
1032 UINTN MicrocodeCount
;
1035 DEBUG((DEBUG_INFO
, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image
, ImageSize
));
1037 MicrocodePatchAddress
= MicrocodeFmpPrivate
->MicrocodePatchAddress
;
1038 MicrocodePatchRegionSize
= MicrocodeFmpPrivate
->MicrocodePatchRegionSize
;
1040 MicrocodePatchScratchBuffer
= AllocateZeroPool (MicrocodePatchRegionSize
);
1041 if (MicrocodePatchScratchBuffer
== NULL
) {
1042 DEBUG((DEBUG_ERROR
, "Fail to allocate Microcode Scratch buffer\n"));
1043 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
1044 return EFI_OUT_OF_RESOURCES
;
1046 ScratchBufferPtr
= MicrocodePatchScratchBuffer
;
1047 ScratchBufferSize
= 0;
1050 // Target data collection
1052 TargetTotalSize
= 0;
1054 NextMicrocodeEntryPoint
= NULL
;
1055 if (TargetMicrocodeEntryPoint
!= NULL
) {
1056 if (TargetMicrocodeEntryPoint
->DataSize
== 0) {
1057 TargetTotalSize
= 2048;
1059 TargetTotalSize
= TargetMicrocodeEntryPoint
->TotalSize
;
1061 DEBUG((DEBUG_INFO
, " TargetTotalSize - 0x%x\n", TargetTotalSize
));
1062 NextMicrocodeEntryPoint
= GetNextMicrocode(MicrocodeFmpPrivate
, TargetMicrocodeEntryPoint
);
1063 DEBUG((DEBUG_INFO
, " NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint
));
1064 if (NextMicrocodeEntryPoint
!= NULL
) {
1065 ASSERT ((UINTN
)NextMicrocodeEntryPoint
>= ((UINTN
)TargetMicrocodeEntryPoint
+ TargetTotalSize
));
1066 AvailableSize
= (UINTN
)NextMicrocodeEntryPoint
- (UINTN
)TargetMicrocodeEntryPoint
;
1068 AvailableSize
= (UINTN
)MicrocodePatchAddress
+ MicrocodePatchRegionSize
- (UINTN
)TargetMicrocodeEntryPoint
;
1070 DEBUG((DEBUG_INFO
, " AvailableSize - 0x%x\n", AvailableSize
));
1071 ASSERT (AvailableSize
>= TargetTotalSize
);
1073 UsedRegionSize
= GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate
);
1074 DEBUG((DEBUG_INFO
, " UsedRegionSize - 0x%x\n", UsedRegionSize
));
1075 ASSERT (UsedRegionSize
>= TargetTotalSize
);
1076 if (TargetMicrocodeEntryPoint
!= NULL
) {
1077 ASSERT ((UINTN
)MicrocodePatchAddress
+ UsedRegionSize
>= ((UINTN
)TargetMicrocodeEntryPoint
+ TargetTotalSize
));
1080 // Total Size means the Microcode size.
1081 // Available Size means the Microcode size plus the pad till (1) next Microcode or (2) the end.
1084 // +------+-----------+-----+------+===================+
1085 // | MCU1 | Microcode | PAD | MCU2 | Empty |
1086 // +------+-----------+-----+------+===================+
1088 // |<-AvailableSize->|
1089 // |<- UsedRegionSize ->|
1092 // +------+-----------+===================+
1093 // | MCU | Microcode | Empty |
1094 // +------+-----------+===================+
1096 // |<- AvailableSize ->|
1097 // |<-UsedRegionSize->|
1101 // Update based on policy
1105 // 1. If there is enough space to update old one in situ, replace old microcode in situ.
1107 if (AvailableSize
>= ImageSize
) {
1108 DEBUG((DEBUG_INFO
, "Replace old microcode in situ\n"));
1110 // +------+------------+------+===================+
1111 // |Other | Old Image | ... | Empty |
1112 // +------+------------+------+===================+
1114 // +------+---------+--+------+===================+
1115 // |Other |New Image|FF| ... | Empty |
1116 // +------+---------+--+------+===================+
1118 // 1.1. Copy new image
1119 CopyMem (ScratchBufferPtr
, Image
, ImageSize
);
1120 ScratchBufferSize
+= ImageSize
;
1121 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
1123 RestSize
= AvailableSize
- ImageSize
;
1125 SetMem (ScratchBufferPtr
, RestSize
, 0xFF);
1126 ScratchBufferSize
+= RestSize
;
1127 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
1129 Status
= UpdateMicrocode((UINTN
)TargetMicrocodeEntryPoint
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
1134 // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.
1136 if (MicrocodePatchRegionSize
- (UsedRegionSize
- TargetTotalSize
) >= ImageSize
) {
1137 if (TargetMicrocodeEntryPoint
== NULL
) {
1138 DEBUG((DEBUG_INFO
, "Append new microcode\n"));
1140 // +------+------------+------+===================+
1141 // |Other1| Other |Other2| Empty |
1142 // +------+------------+------+===================+
1144 // +------+------------+------+-----------+=======+
1145 // |Other1| Other |Other2| New Image | Empty |
1146 // +------+------------+------+-----------+=======+
1148 Status
= UpdateMicrocode((UINTN
)MicrocodePatchAddress
+ UsedRegionSize
, Image
, ImageSize
, LastAttemptStatus
);
1150 DEBUG((DEBUG_INFO
, "Reorg and replace old microcode\n"));
1152 // +------+------------+------+===================+
1153 // |Other | Old Image | ... | Empty |
1154 // +------+------------+------+===================+
1156 // +------+---------------+------+================+
1157 // |Other | New Image | ... | Empty |
1158 // +------+---------------+------+================+
1160 // 2.1. Copy new image
1161 CopyMem (ScratchBufferPtr
, Image
, ImageSize
);
1162 ScratchBufferSize
+= ImageSize
;
1163 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
1164 // 2.2. Copy rest images after the old image.
1165 if (NextMicrocodeEntryPoint
!= 0) {
1166 RestSize
= (UINTN
)MicrocodePatchAddress
+ UsedRegionSize
- ((UINTN
)NextMicrocodeEntryPoint
);
1167 CopyMem (ScratchBufferPtr
, NextMicrocodeEntryPoint
, RestSize
);
1168 ScratchBufferSize
+= RestSize
;
1169 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
1171 Status
= UpdateMicrocode((UINTN
)TargetMicrocodeEntryPoint
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
1177 // 3. The new image can be put in MCU region, but not all others can be put.
1178 // So all the unused MCU is removed.
1180 if (MicrocodePatchRegionSize
>= ImageSize
) {
1182 // +------+------------+------+===================+
1183 // |Other1| Old Image |Other2| Empty |
1184 // +------+------------+------+===================+
1186 // +-------------------------------------+--------+
1187 // | New Image | Other |
1188 // +-------------------------------------+--------+
1190 DEBUG((DEBUG_INFO
, "Add new microcode from beginning\n"));
1192 MicrocodeCount
= MicrocodeFmpPrivate
->DescriptorCount
;
1193 MicrocodeInfo
= MicrocodeFmpPrivate
->MicrocodeInfo
;
1195 // 3.1. Copy new image
1196 CopyMem (ScratchBufferPtr
, Image
, ImageSize
);
1197 ScratchBufferSize
+= ImageSize
;
1198 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
1199 // 3.2. Copy some others to rest buffer
1200 for (Index
= 0; Index
< MicrocodeCount
; Index
++) {
1201 if (!MicrocodeInfo
[Index
].InUse
) {
1204 if (MicrocodeInfo
[Index
].MicrocodeEntryPoint
== TargetMicrocodeEntryPoint
) {
1207 if (MicrocodeInfo
[Index
].TotalSize
<= MicrocodePatchRegionSize
- ScratchBufferSize
) {
1208 CopyMem (ScratchBufferPtr
, MicrocodeInfo
[Index
].MicrocodeEntryPoint
, MicrocodeInfo
[Index
].TotalSize
);
1209 ScratchBufferSize
+= MicrocodeInfo
[Index
].TotalSize
;
1210 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
1214 RestSize
= MicrocodePatchRegionSize
- ScratchBufferSize
;
1216 SetMem (ScratchBufferPtr
, RestSize
, 0xFF);
1217 ScratchBufferSize
+= RestSize
;
1218 ScratchBufferPtr
= (UINT8
*)MicrocodePatchScratchBuffer
+ ScratchBufferSize
;
1220 Status
= UpdateMicrocode((UINTN
)MicrocodePatchAddress
, MicrocodePatchScratchBuffer
, ScratchBufferSize
, LastAttemptStatus
);
1225 // 4. The new image size is bigger than the whole MCU region.
1227 DEBUG((DEBUG_ERROR
, "Microcode too big\n"));
1228 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
1229 Status
= EFI_OUT_OF_RESOURCES
;
1237 Caution: This function may receive untrusted input.
1239 @param[in] MicrocodeFmpPrivate The Microcode driver private data
1240 @param[in] Image The Microcode image buffer.
1241 @param[in] ImageSize The size of Microcode image buffer in bytes.
1242 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
1243 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
1244 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
1245 details for the aborted operation. The buffer is allocated by this function
1246 with AllocatePool(), and it is the caller's responsibility to free it with a
1249 @retval EFI_SUCCESS The Microcode image is written.
1250 @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupted.
1251 @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorrect.
1252 @retval EFI_SECURITY_VIOLATION The Microcode image fails to load.
1253 @retval EFI_WRITE_PROTECTED The flash device is read only.
1257 IN MICROCODE_FMP_PRIVATE_DATA
*MicrocodeFmpPrivate
,
1260 OUT UINT32
*LastAttemptVersion
,
1261 OUT UINT32
*LastAttemptStatus
,
1262 OUT CHAR16
**AbortReason
1267 CPU_MICROCODE_HEADER
*TargetMicrocodeEntryPoint
;
1268 UINTN TargetCpuIndex
;
1269 UINTN TargetMicrcodeIndex
;
1272 // MCU must be 16 bytes aligned
1274 AlignedImage
= AllocateCopyPool(ImageSize
, Image
);
1275 if (AlignedImage
== NULL
) {
1276 DEBUG((DEBUG_ERROR
, "Fail to allocate aligned image\n"));
1277 *LastAttemptStatus
= LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES
;
1278 return EFI_OUT_OF_RESOURCES
;
1281 TargetCpuIndex
= (UINTN
)-1;
1282 Status
= VerifyMicrocode(MicrocodeFmpPrivate
, AlignedImage
, ImageSize
, TRUE
, LastAttemptStatus
, AbortReason
, &TargetCpuIndex
);
1283 if (EFI_ERROR(Status
)) {
1284 DEBUG((DEBUG_ERROR
, "Fail to verify Microcode Region\n"));
1285 FreePool(AlignedImage
);
1288 DEBUG((DEBUG_INFO
, "Pass VerifyMicrocode\n"));
1289 *LastAttemptVersion
= ((CPU_MICROCODE_HEADER
*)Image
)->UpdateRevision
;
1291 DEBUG((DEBUG_INFO
, " TargetCpuIndex - 0x%x\n", TargetCpuIndex
));
1292 ASSERT (TargetCpuIndex
< MicrocodeFmpPrivate
->ProcessorCount
);
1293 TargetMicrcodeIndex
= MicrocodeFmpPrivate
->ProcessorInfo
[TargetCpuIndex
].MicrocodeIndex
;
1294 DEBUG((DEBUG_INFO
, " TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex
));
1295 if (TargetMicrcodeIndex
!= (UINTN
)-1) {
1296 ASSERT (TargetMicrcodeIndex
< MicrocodeFmpPrivate
->DescriptorCount
);
1297 TargetMicrocodeEntryPoint
= MicrocodeFmpPrivate
->MicrocodeInfo
[TargetMicrcodeIndex
].MicrocodeEntryPoint
;
1299 TargetMicrocodeEntryPoint
= NULL
;
1301 DEBUG((DEBUG_INFO
, " TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint
));
1303 if (MicrocodeFmpPrivate
->FitMicrocodeInfo
!= NULL
) {
1304 Status
= UpdateMicrocodeFlashRegionWithFit (
1305 MicrocodeFmpPrivate
,
1306 TargetMicrocodeEntryPoint
,
1312 Status
= UpdateMicrocodeFlashRegion (
1313 MicrocodeFmpPrivate
,
1314 TargetMicrocodeEntryPoint
,
1321 FreePool(AlignedImage
);