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 ProcessRecoveryCapsule(), ProcessFmpCapsuleImage(), ProcessRecoveryImage(),
10 ValidateFmpCapsule() will receive untrusted input and do basic validation.
12 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
13 SPDX-License-Identifier: BSD-2-Clause-Patent
18 // The package level header files this module uses
23 // The protocols, PPI and GUID definitions for this module
25 #include <Ppi/MasterBootMode.h>
26 #include <Ppi/BootInRecoveryMode.h>
27 #include <Ppi/RecoveryModule.h>
28 #include <Ppi/DeviceRecoveryModule.h>
29 #include <Ppi/FirmwareVolumeInfo.h>
30 #include <Guid/FirmwareFileSystem2.h>
31 #include <Guid/FmpCapsule.h>
32 #include <Guid/EdkiiSystemFmpCapsule.h>
35 // The Library classes this module consumes
37 #include <Library/DebugLib.h>
38 #include <Library/PeimEntryPoint.h>
39 #include <Library/PeiServicesLib.h>
40 #include <Library/HobLib.h>
41 #include <Library/BaseMemoryLib.h>
42 #include <Library/MemoryAllocationLib.h>
43 #include <Library/PcdLib.h>
45 #include "RecoveryModuleLoadPei.h"
48 Loads a DXE capsule from some media into memory and updates the HOB table
49 with the DXE firmware volume information.
51 @param[in] PeiServices General-purpose services that are available to every PEIM.
52 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
54 @retval EFI_SUCCESS The capsule was loaded correctly.
55 @retval EFI_DEVICE_ERROR A device error occurred.
56 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
62 IN EFI_PEI_SERVICES
**PeiServices
,
63 IN EFI_PEI_RECOVERY_MODULE_PPI
*This
66 EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi
= {
70 EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList
= {
71 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
72 &gEfiPeiRecoveryModulePpiGuid
,
77 Parse Config data file to get the updated data array.
79 @param[in] DataBuffer Config raw file buffer.
80 @param[in] BufferSize Size of raw buffer.
81 @param[in, out] ConfigHeader Pointer to the config header.
82 @param[in, out] RecoveryArray Pointer to the config of recovery data.
84 @retval EFI_NOT_FOUND No config data is found.
85 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
86 @retval EFI_SUCCESS Parse the config file successfully.
90 ParseRecoveryDataFile (
93 IN OUT CONFIG_HEADER
*ConfigHeader
,
94 IN OUT RECOVERY_CONFIG_DATA
**RecoveryArray
98 Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
100 @param[in] FmpImageHeader A pointer to EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
102 @return TRUE It is a system FMP.
103 @return FALSE It is a device FMP.
107 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*FmpImageHeader
114 Guid
= PcdGetPtr(PcdSystemFmpCapsuleImageTypeIdGuid
);
115 Count
= PcdGetSize(PcdSystemFmpCapsuleImageTypeIdGuid
) / sizeof(GUID
);
117 for (Index
= 0; Index
< Count
; Index
++, Guid
++) {
118 if (CompareGuid(&FmpImageHeader
->UpdateImageTypeId
, Guid
)) {
127 Return if this CapsuleGuid is a FMP capsule GUID or not.
129 @param[in] CapsuleGuid A pointer to EFI_GUID
131 @return TRUE It is a FMP capsule GUID.
132 @return FALSE It is not a FMP capsule GUID.
136 IN EFI_GUID
*CapsuleGuid
139 if (CompareGuid(&gEfiFmpCapsuleGuid
, CapsuleGuid
)) {
147 This function assumes the input Capsule image already passes basic check in
148 ValidateFmpCapsule().
150 Criteria of system FMP capsule is:
151 1) FmpCapsuleHeader->EmbeddedDriverCount is 0.
152 2) FmpCapsuleHeader->PayloadItemCount is not 0.
153 3) All ImageHeader->UpdateImageTypeId matches PcdSystemFmpCapsuleImageTypeIdGuid.
155 @param[in] CapsuleHeader Points to a capsule header.
157 @retval TRUE Input capsule is a correct system FMP capsule.
158 @retval FALSE Input capsule is not a correct system FMP capsule.
161 IsSystemFmpCapsuleImage (
162 IN EFI_CAPSULE_HEADER
*CapsuleHeader
165 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
166 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
167 UINT64
*ItemOffsetList
;
171 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*) ((UINT8
*) CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
173 if (FmpCapsuleHeader
->EmbeddedDriverCount
!= 0) {
177 if (FmpCapsuleHeader
->PayloadItemCount
== 0) {
181 ItemNum
= FmpCapsuleHeader
->EmbeddedDriverCount
+ FmpCapsuleHeader
->PayloadItemCount
;
183 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
185 for (Index
= 0; Index
< ItemNum
; Index
++) {
186 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[Index
]);
187 if (!IsSystemFmpImage(ImageHeader
)) {
196 Validate if it is valid capsule header
198 This function assumes the caller provided correct CapsuleHeader pointer
201 This function validates the fields in EFI_CAPSULE_HEADER.
203 @param[in] CapsuleHeader Points to a capsule header.
204 @param[in] CapsuleSize Size of the whole capsule image.
208 IsValidCapsuleHeader (
209 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
210 IN UINT64 CapsuleSize
213 if (CapsuleHeader
->CapsuleImageSize
!= CapsuleSize
) {
216 if (CapsuleHeader
->HeaderSize
>= CapsuleHeader
->CapsuleImageSize
) {
223 Validate Fmp capsules layout.
225 Caution: This function may receive untrusted input.
227 This function assumes the caller validated the capsule by using
228 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
229 The capsule buffer size is CapsuleHeader->CapsuleImageSize.
231 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
232 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
234 @param[in] CapsuleHeader Points to a capsule header.
235 @param[out] IsSystemFmp If it is a system FMP.
236 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
238 @retval EFI_SUCCESS Input capsule is a correct FMP capsule.
239 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
243 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
244 OUT BOOLEAN
*IsSystemFmp OPTIONAL
,
245 OUT UINT16
*EmbeddedDriverCount OPTIONAL
248 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
250 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
252 UINT64
*ItemOffsetList
;
255 UINTN FmpCapsuleSize
;
256 UINTN FmpCapsuleHeaderSize
;
258 UINTN FmpImageHeaderSize
;
260 if (CapsuleHeader
->HeaderSize
>= CapsuleHeader
->CapsuleImageSize
) {
261 DEBUG((DEBUG_ERROR
, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader
->HeaderSize
, CapsuleHeader
->CapsuleImageSize
));
262 return EFI_INVALID_PARAMETER
;
265 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*) ((UINT8
*) CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
266 EndOfCapsule
= (UINT8
*) CapsuleHeader
+ CapsuleHeader
->CapsuleImageSize
;
267 FmpCapsuleSize
= (UINTN
)EndOfCapsule
- (UINTN
)FmpCapsuleHeader
;
269 if (FmpCapsuleSize
< sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
)) {
270 DEBUG((DEBUG_ERROR
, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize
));
271 return EFI_INVALID_PARAMETER
;
274 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
275 if (FmpCapsuleHeader
->Version
!= EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION
) {
276 DEBUG((DEBUG_ERROR
, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader
->Version
));
277 return EFI_INVALID_PARAMETER
;
279 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
282 ItemNum
= FmpCapsuleHeader
->EmbeddedDriverCount
+ FmpCapsuleHeader
->PayloadItemCount
;
284 if ((FmpCapsuleSize
- sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
))/sizeof(UINT64
) < ItemNum
) {
285 DEBUG((DEBUG_ERROR
, "ItemNum(0x%x) too big\n", ItemNum
));
286 return EFI_INVALID_PARAMETER
;
288 FmpCapsuleHeaderSize
= sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
) + sizeof(UINT64
)*ItemNum
;
290 // Check ItemOffsetList
291 for (Index
= 0; Index
< ItemNum
; Index
++) {
292 if (ItemOffsetList
[Index
] >= FmpCapsuleSize
) {
293 DEBUG((DEBUG_ERROR
, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index
, ItemOffsetList
[Index
], FmpCapsuleSize
));
294 return EFI_INVALID_PARAMETER
;
296 if (ItemOffsetList
[Index
] < FmpCapsuleHeaderSize
) {
297 DEBUG((DEBUG_ERROR
, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index
, ItemOffsetList
[Index
], FmpCapsuleHeaderSize
));
298 return EFI_INVALID_PARAMETER
;
301 // All the address in ItemOffsetList must be stored in ascending order
304 if (ItemOffsetList
[Index
] <= ItemOffsetList
[Index
- 1]) {
305 DEBUG((DEBUG_ERROR
, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index
, ItemOffsetList
[Index
], Index
, ItemOffsetList
[Index
- 1]));
306 return EFI_INVALID_PARAMETER
;
311 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
312 for (Index
= FmpCapsuleHeader
->EmbeddedDriverCount
; Index
< ItemNum
; Index
++) {
313 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[Index
]);
314 if (Index
== ItemNum
- 1) {
315 EndOfPayload
= (UINT8
*)((UINTN
)EndOfCapsule
- (UINTN
)FmpCapsuleHeader
);
317 EndOfPayload
= (UINT8
*)(UINTN
)ItemOffsetList
[Index
+1];
319 FmpImageSize
= (UINTN
)EndOfPayload
- ItemOffsetList
[Index
];
321 if (FmpImageSize
< OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, UpdateHardwareInstance
)) {
322 DEBUG((DEBUG_ERROR
, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize
));
323 return EFI_INVALID_PARAMETER
;
325 FmpImageHeaderSize
= sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
);
326 if ((ImageHeader
->Version
> EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION
) ||
327 (ImageHeader
->Version
< 1)) {
328 DEBUG((DEBUG_ERROR
, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader
->Version
));
329 return EFI_INVALID_PARAMETER
;
332 /// Current Init ImageHeader version is 3. UpdateHardwareInstance field was added in version 2
333 /// and ImageCapsuleSupport field was added in version 3
335 if (ImageHeader
->Version
== 1) {
336 FmpImageHeaderSize
= OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, UpdateHardwareInstance
);
337 } else if (ImageHeader
->Version
== 2){
338 FmpImageHeaderSize
= OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, ImageCapsuleSupport
);
342 if (FmpImageSize
!= (UINT64
)FmpImageHeaderSize
+ (UINT64
)ImageHeader
->UpdateImageSize
+ (UINT64
)ImageHeader
->UpdateVendorCodeSize
) {
343 DEBUG((DEBUG_ERROR
, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize
, ImageHeader
->UpdateImageSize
, ImageHeader
->UpdateVendorCodeSize
));
344 return EFI_INVALID_PARAMETER
;
350 // No driver & payload element in FMP
352 EndOfPayload
= (UINT8
*)(FmpCapsuleHeader
+ 1);
353 if (EndOfPayload
!= EndOfCapsule
) {
354 DEBUG((DEBUG_ERROR
, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload
, EndOfCapsule
));
355 return EFI_INVALID_PARAMETER
;
357 return EFI_UNSUPPORTED
;
361 // Check in system FMP capsule
363 if (IsSystemFmp
!= NULL
) {
364 *IsSystemFmp
= IsSystemFmpCapsuleImage(CapsuleHeader
);
367 if (EmbeddedDriverCount
!= NULL
) {
368 *EmbeddedDriverCount
= FmpCapsuleHeader
->EmbeddedDriverCount
;
375 Recovery module entrypoint
377 @param[in] FileHandle Handle of the file being invoked.
378 @param[in] PeiServices Describes the list of possible PEI Services.
380 @return EFI_SUCCESS Recovery module is initialized.
384 InitializeRecoveryModule (
385 IN EFI_PEI_FILE_HANDLE FileHandle
,
386 IN CONST EFI_PEI_SERVICES
**PeiServices
392 BootMode
= GetBootModeHob();
393 ASSERT(BootMode
== BOOT_IN_RECOVERY_MODE
);
395 Status
= (**PeiServices
).InstallPpi (PeiServices
, &mRecoveryPpiList
);
396 ASSERT_EFI_ERROR (Status
);
402 Create hob and install FvInfo PPI for recovery capsule.
404 @param[in] FvImage Points to the DXE FV image.
405 @param[in] FvImageSize The length of the DXE FV image in bytes.
407 @retval EFI_SUCCESS Create hob and install FvInfo PPI successfully.
408 @retval EFI_VOLUME_CORRUPTED The input data is not an FV.
409 @retval EFI_OUT_OF_RESOURCES No enough resource to process the input data.
413 CreateHobForRecoveryCapsule (
418 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
424 // FvImage should be at its required alignment.
426 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) FvImage
;
428 // Validate FV Header, if not as expected, return
430 if (ReadUnaligned32 (&FvHeader
->Signature
) != EFI_FVH_SIGNATURE
) {
431 DEBUG((DEBUG_ERROR
, "CreateHobForRecoveryCapsule (Fv Signature Error)\n"));
432 return EFI_VOLUME_CORRUPTED
;
435 // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
436 // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
437 // its initial linked location and maintain its alignment.
439 if ((ReadUnaligned32 (&FvHeader
->Attributes
) & EFI_FVB2_WEAK_ALIGNMENT
) != EFI_FVB2_WEAK_ALIGNMENT
) {
441 // Get FvHeader alignment
443 FvAlignment
= 1 << ((ReadUnaligned32 (&FvHeader
->Attributes
) & EFI_FVB2_ALIGNMENT
) >> 16);
445 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
447 if (FvAlignment
< 8) {
451 // Allocate the aligned buffer for the FvImage.
453 if ((UINTN
) FvHeader
% FvAlignment
!= 0) {
454 DEBUG((DEBUG_INFO
, "CreateHobForRecoveryCapsule (FvHeader 0x%lx is not aligned)\n", (UINT64
)(UINTN
)FvHeader
));
455 FvLength
= ReadUnaligned64 (&FvHeader
->FvLength
);
456 NewFvBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN
) FvLength
), FvAlignment
);
457 if (NewFvBuffer
== NULL
) {
458 DEBUG((DEBUG_ERROR
, "CreateHobForRecoveryCapsule (Not enough resource to allocate 0x%lx bytes)\n", FvLength
));
459 return EFI_OUT_OF_RESOURCES
;
461 CopyMem (NewFvBuffer
, FvHeader
, (UINTN
) FvLength
);
462 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) NewFvBuffer
;
466 BuildFvHob((UINT64
)(UINTN
)FvHeader
, FvHeader
->FvLength
);
467 DEBUG((DEBUG_INFO
, "BuildFvHob (FV in recovery) - 0x%lx - 0x%lx\n", (UINT64
)(UINTN
)FvHeader
, FvHeader
->FvLength
));
469 PeiServicesInstallFvInfoPpi(
470 &FvHeader
->FileSystemGuid
,
472 (UINT32
)FvHeader
->FvLength
,
481 Create recovery context based upon System Firmware image and config file.
483 @param[in] SystemFirmwareImage Points to the System Firmware image.
484 @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes.
485 @param[in] ConfigImage Points to the config file image.
486 @param[in] ConfigImageSize The length of the config file image in bytes.
488 @retval EFI_SUCCESS Process Recovery Image successfully.
492 IN VOID
*SystemFirmwareImage
,
493 IN UINTN SystemFirmwareImageSize
,
494 IN VOID
*ConfigImage
,
495 IN UINTN ConfigImageSize
499 RECOVERY_CONFIG_DATA
*ConfigData
;
500 RECOVERY_CONFIG_DATA
*RecoveryConfigData
;
501 CONFIG_HEADER ConfigHeader
;
504 if (ConfigImage
== NULL
) {
505 DEBUG((DEBUG_INFO
, "RecoverImage (NoConfig)\n"));
506 Status
= CreateHobForRecoveryCapsule(
508 SystemFirmwareImageSize
514 ZeroMem (&ConfigHeader
, sizeof(ConfigHeader
));
515 Status
= ParseRecoveryDataFile (
521 DEBUG((DEBUG_INFO
, "ParseRecoveryDataFile - %r\n", Status
));
522 if (EFI_ERROR(Status
)) {
525 DEBUG((DEBUG_INFO
, "ConfigHeader.NumOfRecovery - 0x%x\n", ConfigHeader
.NumOfRecovery
));
526 DEBUG((DEBUG_INFO
, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid
)));
529 RecoveryConfigData
= ConfigData
;
530 while (Index
< ConfigHeader
.NumOfRecovery
) {
531 if (CompareGuid(&RecoveryConfigData
->FileGuid
, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid
))) {
532 DEBUG((DEBUG_INFO
, "FileGuid - %g (processing)\n", &RecoveryConfigData
->FileGuid
));
533 Status
= CreateHobForRecoveryCapsule (
534 (UINT8
*)SystemFirmwareImage
+ RecoveryConfigData
->ImageOffset
,
535 RecoveryConfigData
->Length
538 // Shall updates be serialized so that if a recovery FV is not successfully completed,
539 // the remaining updates won't be performed.
541 if (EFI_ERROR (Status
)) {
545 DEBUG((DEBUG_INFO
, "FileGuid - %g (ignored)\n", &RecoveryConfigData
->FileGuid
));
549 RecoveryConfigData
++;
556 Process recovery image.
558 Caution: This function may receive untrusted input.
560 @param[in] Image Points to the recovery image.
561 @param[in] Length The length of the recovery image in bytes.
563 @retval EFI_SUCCESS Process Recovery Image successfully.
564 @retval EFI_SECURITY_VIOLATION Recovery image is not processed due to security violation.
567 ProcessRecoveryImage (
572 UINT32 LastAttemptVersion
;
573 UINT32 LastAttemptStatus
;
575 VOID
*SystemFirmwareImage
;
576 UINTN SystemFirmwareImageSize
;
578 UINTN ConfigImageSize
;
579 VOID
*AuthenticatedImage
;
580 UINTN AuthenticatedImageSize
;
582 AuthenticatedImage
= NULL
;
583 AuthenticatedImageSize
= 0;
585 Status
= CapsuleAuthenticateSystemFirmware(Image
, Length
, TRUE
, &LastAttemptVersion
, &LastAttemptStatus
, &AuthenticatedImage
, &AuthenticatedImageSize
);
586 if (EFI_ERROR(Status
)) {
587 DEBUG((DEBUG_INFO
, "CapsuleAuthenticateSystemFirmware - %r\n", Status
));
591 ExtractSystemFirmwareImage(AuthenticatedImage
, AuthenticatedImageSize
, &SystemFirmwareImage
, &SystemFirmwareImageSize
);
592 ExtractConfigImage(AuthenticatedImage
, AuthenticatedImageSize
, &ConfigImage
, &ConfigImageSize
);
594 Status
= RecoverImage(SystemFirmwareImage
, SystemFirmwareImageSize
, ConfigImage
, ConfigImageSize
);
595 if (EFI_ERROR(Status
)) {
596 DEBUG((DEBUG_INFO
, "RecoverImage - %r\n", Status
));
604 Process Firmware management protocol data capsule.
606 Caution: This function may receive untrusted input.
608 This function assumes the caller validated the capsule by using
609 ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
610 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
611 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
613 @param[in] CapsuleHeader Points to a capsule header.
614 @param[in] IsSystemFmp If this capsule is a system FMP capsule.
616 @retval EFI_SUCCESS Process Capsule Image successfully.
617 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
618 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
619 @retval EFI_OUT_OF_RESOURCES Not enough memory.
622 ProcessFmpCapsuleImage (
623 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
624 IN BOOLEAN IsSystemFmp
628 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
629 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
631 UINT64
*ItemOffsetList
;
635 return EFI_UNSUPPORTED
;
638 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*)((UINT8
*)CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
639 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
641 for (ItemIndex
= 0; ItemIndex
< FmpCapsuleHeader
->PayloadItemCount
; ItemIndex
++) {
642 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[ItemIndex
]);
643 if (ImageHeader
->Version
>= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION
) {
644 Image
= (UINT8
*)(ImageHeader
+ 1);
647 // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId.
648 // Header should exclude UpdateHardwareInstance field.
649 // If version is 2 Header should exclude ImageCapsuleSupport field.
651 if (ImageHeader
->Version
== 1) {
652 Image
= (UINT8
*)ImageHeader
+ OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, UpdateHardwareInstance
);
654 Image
= (UINT8
*)ImageHeader
+ OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, ImageCapsuleSupport
);
658 Status
= ProcessRecoveryImage (Image
, ImageHeader
->UpdateImageSize
);
659 if (EFI_ERROR(Status
)) {
668 Process recovery capsule image.
670 Caution: This function may receive untrusted input.
672 @param[in] CapsuleBuffer The capsule image buffer.
673 @param[in] CapsuleSize The size of the capsule image in bytes.
675 @retval EFI_SUCCESS The recovery capsule is processed.
676 @retval EFI_SECURITY_VIOLATION The recovery capsule is not process because of security violation.
677 @retval EFI_NOT_FOUND The recovery capsule is not process because of unrecognization.
681 ProcessRecoveryCapsule (
682 IN VOID
*CapsuleBuffer
,
688 EFI_CAPSULE_HEADER
*CapsuleHeader
;
690 CapsuleHeader
= CapsuleBuffer
;
691 if (!IsValidCapsuleHeader (CapsuleHeader
, CapsuleSize
)) {
692 DEBUG((DEBUG_ERROR
, "CapsuleImageSize incorrect\n"));
693 return EFI_SECURITY_VIOLATION
;
697 // Check FMP capsule layout
699 if (IsFmpCapsuleGuid(&CapsuleHeader
->CapsuleGuid
)) {
700 DEBUG((DEBUG_INFO
, "CreateHobForRecoveryCapsule\n"));
702 DEBUG((DEBUG_INFO
, "ProcessCapsuleImage for FmpCapsule ...\n"));
703 DEBUG((DEBUG_INFO
, "ValidateFmpCapsule ...\n"));
704 Status
= ValidateFmpCapsule(CapsuleHeader
, &IsSystemFmp
, NULL
);
705 DEBUG((DEBUG_INFO
, "ValidateFmpCapsule - %r\n", Status
));
706 if (EFI_ERROR(Status
)) {
711 // Process EFI FMP Capsule
713 DEBUG((DEBUG_INFO
, "ProcessFmpCapsuleImage ...\n"));
714 Status
= ProcessFmpCapsuleImage(CapsuleHeader
, IsSystemFmp
);
715 DEBUG((DEBUG_INFO
, "ProcessFmpCapsuleImage - %r\n", Status
));
717 DEBUG((DEBUG_INFO
, "CreateHobForRecoveryCapsule Done\n"));
721 return EFI_UNSUPPORTED
;
725 Loads a DXE capsule from some media into memory and updates the HOB table
726 with the DXE firmware volume information.
728 @param[in] PeiServices General-purpose services that are available to every PEIM.
729 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
731 @retval EFI_SUCCESS The capsule was loaded correctly.
732 @retval EFI_DEVICE_ERROR A device error occurred.
733 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
738 LoadRecoveryCapsule (
739 IN EFI_PEI_SERVICES
**PeiServices
,
740 IN EFI_PEI_RECOVERY_MODULE_PPI
*This
744 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*DeviceRecoveryPpi
;
745 UINTN NumberRecoveryCapsules
;
747 UINTN CapsuleInstance
;
749 EFI_GUID CapsuleType
;
752 DEBUG((DEBUG_INFO
| DEBUG_LOAD
, "Recovery Entry\n"));
754 for (Instance
= 0; ; Instance
++) {
755 Status
= PeiServicesLocatePpi (
756 &gEfiPeiDeviceRecoveryModulePpiGuid
,
759 (VOID
**)&DeviceRecoveryPpi
761 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - LocateRecoveryPpi (%d) - %r\n", Instance
, Status
));
762 if (EFI_ERROR (Status
)) {
765 NumberRecoveryCapsules
= 0;
766 Status
= DeviceRecoveryPpi
->GetNumberRecoveryCapsules (
767 (EFI_PEI_SERVICES
**)PeiServices
,
769 &NumberRecoveryCapsules
771 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules
, Status
));
772 if (EFI_ERROR (Status
)) {
775 for (CapsuleInstance
= 1; CapsuleInstance
<= NumberRecoveryCapsules
; CapsuleInstance
++) {
777 Status
= DeviceRecoveryPpi
->GetRecoveryCapsuleInfo (
778 (EFI_PEI_SERVICES
**)PeiServices
,
784 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance
, CapsuleSize
, Status
));
785 if (EFI_ERROR (Status
)) {
789 CapsuleBuffer
= AllocatePages (EFI_SIZE_TO_PAGES(CapsuleSize
));
790 if (CapsuleBuffer
== NULL
) {
791 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - AllocatePool fail\n"));
794 Status
= DeviceRecoveryPpi
->LoadRecoveryCapsule (
795 (EFI_PEI_SERVICES
**)PeiServices
,
800 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance
, Status
));
801 if (EFI_ERROR (Status
)) {
802 FreePages (CapsuleBuffer
, EFI_SIZE_TO_PAGES(CapsuleSize
));
806 // good, load capsule buffer
808 Status
= ProcessRecoveryCapsule (CapsuleBuffer
, CapsuleSize
);
813 return EFI_NOT_FOUND
;