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
) {
217 if (CapsuleHeader
->HeaderSize
>= CapsuleHeader
->CapsuleImageSize
) {
225 Validate Fmp capsules layout.
227 Caution: This function may receive untrusted input.
229 This function assumes the caller validated the capsule by using
230 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
231 The capsule buffer size is CapsuleHeader->CapsuleImageSize.
233 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
234 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
236 @param[in] CapsuleHeader Points to a capsule header.
237 @param[out] IsSystemFmp If it is a system FMP.
238 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
240 @retval EFI_SUCCESS Input capsule is a correct FMP capsule.
241 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
245 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
246 OUT BOOLEAN
*IsSystemFmp OPTIONAL
,
247 OUT UINT16
*EmbeddedDriverCount OPTIONAL
250 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
252 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
254 UINT64
*ItemOffsetList
;
257 UINTN FmpCapsuleSize
;
258 UINTN FmpCapsuleHeaderSize
;
260 UINTN FmpImageHeaderSize
;
262 if (CapsuleHeader
->HeaderSize
>= CapsuleHeader
->CapsuleImageSize
) {
263 DEBUG ((DEBUG_ERROR
, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader
->HeaderSize
, CapsuleHeader
->CapsuleImageSize
));
264 return EFI_INVALID_PARAMETER
;
267 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*)((UINT8
*)CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
268 EndOfCapsule
= (UINT8
*)CapsuleHeader
+ CapsuleHeader
->CapsuleImageSize
;
269 FmpCapsuleSize
= (UINTN
)EndOfCapsule
- (UINTN
)FmpCapsuleHeader
;
271 if (FmpCapsuleSize
< sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
)) {
272 DEBUG ((DEBUG_ERROR
, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize
));
273 return EFI_INVALID_PARAMETER
;
276 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
277 if (FmpCapsuleHeader
->Version
!= EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION
) {
278 DEBUG ((DEBUG_ERROR
, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader
->Version
));
279 return EFI_INVALID_PARAMETER
;
282 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
285 ItemNum
= FmpCapsuleHeader
->EmbeddedDriverCount
+ FmpCapsuleHeader
->PayloadItemCount
;
287 if ((FmpCapsuleSize
- sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
))/sizeof (UINT64
) < ItemNum
) {
288 DEBUG ((DEBUG_ERROR
, "ItemNum(0x%x) too big\n", ItemNum
));
289 return EFI_INVALID_PARAMETER
;
292 FmpCapsuleHeaderSize
= sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
) + sizeof (UINT64
)*ItemNum
;
294 // Check ItemOffsetList
295 for (Index
= 0; Index
< ItemNum
; Index
++) {
296 if (ItemOffsetList
[Index
] >= FmpCapsuleSize
) {
297 DEBUG ((DEBUG_ERROR
, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index
, ItemOffsetList
[Index
], FmpCapsuleSize
));
298 return EFI_INVALID_PARAMETER
;
301 if (ItemOffsetList
[Index
] < FmpCapsuleHeaderSize
) {
302 DEBUG ((DEBUG_ERROR
, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index
, ItemOffsetList
[Index
], FmpCapsuleHeaderSize
));
303 return EFI_INVALID_PARAMETER
;
307 // All the address in ItemOffsetList must be stored in ascending order
310 if (ItemOffsetList
[Index
] <= ItemOffsetList
[Index
- 1]) {
311 DEBUG ((DEBUG_ERROR
, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index
, ItemOffsetList
[Index
], Index
, ItemOffsetList
[Index
- 1]));
312 return EFI_INVALID_PARAMETER
;
317 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
318 for (Index
= FmpCapsuleHeader
->EmbeddedDriverCount
; Index
< ItemNum
; Index
++) {
319 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[Index
]);
320 if (Index
== ItemNum
- 1) {
321 EndOfPayload
= (UINT8
*)((UINTN
)EndOfCapsule
- (UINTN
)FmpCapsuleHeader
);
323 EndOfPayload
= (UINT8
*)(UINTN
)ItemOffsetList
[Index
+1];
326 FmpImageSize
= (UINTN
)EndOfPayload
- ItemOffsetList
[Index
];
328 if (FmpImageSize
< OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, UpdateHardwareInstance
)) {
329 DEBUG ((DEBUG_ERROR
, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize
));
330 return EFI_INVALID_PARAMETER
;
333 FmpImageHeaderSize
= sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
);
334 if ((ImageHeader
->Version
> EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION
) ||
335 (ImageHeader
->Version
< 1))
337 DEBUG ((DEBUG_ERROR
, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader
->Version
));
338 return EFI_INVALID_PARAMETER
;
342 /// Current Init ImageHeader version is 3. UpdateHardwareInstance field was added in version 2
343 /// and ImageCapsuleSupport field was added in version 3
345 if (ImageHeader
->Version
== 1) {
346 FmpImageHeaderSize
= OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, UpdateHardwareInstance
);
347 } else if (ImageHeader
->Version
== 2) {
348 FmpImageHeaderSize
= OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, ImageCapsuleSupport
);
352 if (FmpImageSize
!= (UINT64
)FmpImageHeaderSize
+ (UINT64
)ImageHeader
->UpdateImageSize
+ (UINT64
)ImageHeader
->UpdateVendorCodeSize
) {
353 DEBUG ((DEBUG_ERROR
, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize
, ImageHeader
->UpdateImageSize
, ImageHeader
->UpdateVendorCodeSize
));
354 return EFI_INVALID_PARAMETER
;
360 // No driver & payload element in FMP
362 EndOfPayload
= (UINT8
*)(FmpCapsuleHeader
+ 1);
363 if (EndOfPayload
!= EndOfCapsule
) {
364 DEBUG ((DEBUG_ERROR
, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload
, EndOfCapsule
));
365 return EFI_INVALID_PARAMETER
;
368 return EFI_UNSUPPORTED
;
372 // Check in system FMP capsule
374 if (IsSystemFmp
!= NULL
) {
375 *IsSystemFmp
= IsSystemFmpCapsuleImage (CapsuleHeader
);
378 if (EmbeddedDriverCount
!= NULL
) {
379 *EmbeddedDriverCount
= FmpCapsuleHeader
->EmbeddedDriverCount
;
386 Recovery module entrypoint
388 @param[in] FileHandle Handle of the file being invoked.
389 @param[in] PeiServices Describes the list of possible PEI Services.
391 @return EFI_SUCCESS Recovery module is initialized.
395 InitializeRecoveryModule (
396 IN EFI_PEI_FILE_HANDLE FileHandle
,
397 IN CONST EFI_PEI_SERVICES
**PeiServices
403 BootMode
= GetBootModeHob ();
404 ASSERT (BootMode
== BOOT_IN_RECOVERY_MODE
);
406 Status
= (**PeiServices
).InstallPpi (PeiServices
, &mRecoveryPpiList
);
407 ASSERT_EFI_ERROR (Status
);
413 Create hob and install FvInfo PPI for recovery capsule.
415 @param[in] FvImage Points to the DXE FV image.
416 @param[in] FvImageSize The length of the DXE FV image in bytes.
418 @retval EFI_SUCCESS Create hob and install FvInfo PPI successfully.
419 @retval EFI_VOLUME_CORRUPTED The input data is not an FV.
420 @retval EFI_OUT_OF_RESOURCES No enough resource to process the input data.
424 CreateHobForRecoveryCapsule (
429 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
435 // FvImage should be at its required alignment.
437 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)FvImage
;
439 // Validate FV Header, if not as expected, return
441 if (ReadUnaligned32 (&FvHeader
->Signature
) != EFI_FVH_SIGNATURE
) {
442 DEBUG ((DEBUG_ERROR
, "CreateHobForRecoveryCapsule (Fv Signature Error)\n"));
443 return EFI_VOLUME_CORRUPTED
;
447 // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
448 // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
449 // its initial linked location and maintain its alignment.
451 if ((ReadUnaligned32 (&FvHeader
->Attributes
) & EFI_FVB2_WEAK_ALIGNMENT
) != EFI_FVB2_WEAK_ALIGNMENT
) {
453 // Get FvHeader alignment
455 FvAlignment
= 1 << ((ReadUnaligned32 (&FvHeader
->Attributes
) & EFI_FVB2_ALIGNMENT
) >> 16);
457 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
459 if (FvAlignment
< 8) {
464 // Allocate the aligned buffer for the FvImage.
466 if ((UINTN
)FvHeader
% FvAlignment
!= 0) {
467 DEBUG ((DEBUG_INFO
, "CreateHobForRecoveryCapsule (FvHeader 0x%lx is not aligned)\n", (UINT64
)(UINTN
)FvHeader
));
468 FvLength
= ReadUnaligned64 (&FvHeader
->FvLength
);
469 NewFvBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN
)FvLength
), FvAlignment
);
470 if (NewFvBuffer
== NULL
) {
471 DEBUG ((DEBUG_ERROR
, "CreateHobForRecoveryCapsule (Not enough resource to allocate 0x%lx bytes)\n", FvLength
));
472 return EFI_OUT_OF_RESOURCES
;
475 CopyMem (NewFvBuffer
, FvHeader
, (UINTN
)FvLength
);
476 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)NewFvBuffer
;
480 BuildFvHob ((UINT64
)(UINTN
)FvHeader
, FvHeader
->FvLength
);
481 DEBUG ((DEBUG_INFO
, "BuildFvHob (FV in recovery) - 0x%lx - 0x%lx\n", (UINT64
)(UINTN
)FvHeader
, FvHeader
->FvLength
));
483 PeiServicesInstallFvInfoPpi (
484 &FvHeader
->FileSystemGuid
,
486 (UINT32
)FvHeader
->FvLength
,
495 Create recovery context based upon System Firmware image and config file.
497 @param[in] SystemFirmwareImage Points to the System Firmware image.
498 @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes.
499 @param[in] ConfigImage Points to the config file image.
500 @param[in] ConfigImageSize The length of the config file image in bytes.
502 @retval EFI_SUCCESS Process Recovery Image successfully.
506 IN VOID
*SystemFirmwareImage
,
507 IN UINTN SystemFirmwareImageSize
,
508 IN VOID
*ConfigImage
,
509 IN UINTN ConfigImageSize
513 RECOVERY_CONFIG_DATA
*ConfigData
;
514 RECOVERY_CONFIG_DATA
*RecoveryConfigData
;
515 CONFIG_HEADER ConfigHeader
;
518 if (ConfigImage
== NULL
) {
519 DEBUG ((DEBUG_INFO
, "RecoverImage (NoConfig)\n"));
520 Status
= CreateHobForRecoveryCapsule (
522 SystemFirmwareImageSize
528 ZeroMem (&ConfigHeader
, sizeof (ConfigHeader
));
529 Status
= ParseRecoveryDataFile (
535 DEBUG ((DEBUG_INFO
, "ParseRecoveryDataFile - %r\n", Status
));
536 if (EFI_ERROR (Status
)) {
540 DEBUG ((DEBUG_INFO
, "ConfigHeader.NumOfRecovery - 0x%x\n", ConfigHeader
.NumOfRecovery
));
541 DEBUG ((DEBUG_INFO
, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid
)));
544 RecoveryConfigData
= ConfigData
;
545 while (Index
< ConfigHeader
.NumOfRecovery
) {
546 if (CompareGuid (&RecoveryConfigData
->FileGuid
, PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid
))) {
547 DEBUG ((DEBUG_INFO
, "FileGuid - %g (processing)\n", &RecoveryConfigData
->FileGuid
));
548 Status
= CreateHobForRecoveryCapsule (
549 (UINT8
*)SystemFirmwareImage
+ RecoveryConfigData
->ImageOffset
,
550 RecoveryConfigData
->Length
553 // Shall updates be serialized so that if a recovery FV is not successfully completed,
554 // the remaining updates won't be performed.
556 if (EFI_ERROR (Status
)) {
560 DEBUG ((DEBUG_INFO
, "FileGuid - %g (ignored)\n", &RecoveryConfigData
->FileGuid
));
564 RecoveryConfigData
++;
571 Process recovery image.
573 Caution: This function may receive untrusted input.
575 @param[in] Image Points to the recovery image.
576 @param[in] Length The length of the recovery image in bytes.
578 @retval EFI_SUCCESS Process Recovery Image successfully.
579 @retval EFI_SECURITY_VIOLATION Recovery image is not processed due to security violation.
582 ProcessRecoveryImage (
587 UINT32 LastAttemptVersion
;
588 UINT32 LastAttemptStatus
;
590 VOID
*SystemFirmwareImage
;
591 UINTN SystemFirmwareImageSize
;
593 UINTN ConfigImageSize
;
594 VOID
*AuthenticatedImage
;
595 UINTN AuthenticatedImageSize
;
597 AuthenticatedImage
= NULL
;
598 AuthenticatedImageSize
= 0;
600 Status
= CapsuleAuthenticateSystemFirmware (Image
, Length
, TRUE
, &LastAttemptVersion
, &LastAttemptStatus
, &AuthenticatedImage
, &AuthenticatedImageSize
);
601 if (EFI_ERROR (Status
)) {
602 DEBUG ((DEBUG_INFO
, "CapsuleAuthenticateSystemFirmware - %r\n", Status
));
606 ExtractSystemFirmwareImage (AuthenticatedImage
, AuthenticatedImageSize
, &SystemFirmwareImage
, &SystemFirmwareImageSize
);
607 ExtractConfigImage (AuthenticatedImage
, AuthenticatedImageSize
, &ConfigImage
, &ConfigImageSize
);
609 Status
= RecoverImage (SystemFirmwareImage
, SystemFirmwareImageSize
, ConfigImage
, ConfigImageSize
);
610 if (EFI_ERROR (Status
)) {
611 DEBUG ((DEBUG_INFO
, "RecoverImage - %r\n", Status
));
619 Process Firmware management protocol data capsule.
621 Caution: This function may receive untrusted input.
623 This function assumes the caller validated the capsule by using
624 ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
625 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
626 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
628 @param[in] CapsuleHeader Points to a capsule header.
629 @param[in] IsSystemFmp If this capsule is a system FMP capsule.
631 @retval EFI_SUCCESS Process Capsule Image successfully.
632 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
633 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
634 @retval EFI_OUT_OF_RESOURCES Not enough memory.
637 ProcessFmpCapsuleImage (
638 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
639 IN BOOLEAN IsSystemFmp
643 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
644 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
646 UINT64
*ItemOffsetList
;
650 return EFI_UNSUPPORTED
;
653 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*)((UINT8
*)CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
654 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
656 for (ItemIndex
= 0; ItemIndex
< FmpCapsuleHeader
->PayloadItemCount
; ItemIndex
++) {
657 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[ItemIndex
]);
658 if (ImageHeader
->Version
>= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION
) {
659 Image
= (UINT8
*)(ImageHeader
+ 1);
662 // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId.
663 // Header should exclude UpdateHardwareInstance field.
664 // If version is 2 Header should exclude ImageCapsuleSupport field.
666 if (ImageHeader
->Version
== 1) {
667 Image
= (UINT8
*)ImageHeader
+ OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, UpdateHardwareInstance
);
669 Image
= (UINT8
*)ImageHeader
+ OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, ImageCapsuleSupport
);
673 Status
= ProcessRecoveryImage (Image
, ImageHeader
->UpdateImageSize
);
674 if (EFI_ERROR (Status
)) {
683 Process recovery capsule image.
685 Caution: This function may receive untrusted input.
687 @param[in] CapsuleBuffer The capsule image buffer.
688 @param[in] CapsuleSize The size of the capsule image in bytes.
690 @retval EFI_SUCCESS The recovery capsule is processed.
691 @retval EFI_SECURITY_VIOLATION The recovery capsule is not process because of security violation.
692 @retval EFI_NOT_FOUND The recovery capsule is not process because of unrecognization.
696 ProcessRecoveryCapsule (
697 IN VOID
*CapsuleBuffer
,
703 EFI_CAPSULE_HEADER
*CapsuleHeader
;
705 CapsuleHeader
= CapsuleBuffer
;
706 if (!IsValidCapsuleHeader (CapsuleHeader
, CapsuleSize
)) {
707 DEBUG ((DEBUG_ERROR
, "CapsuleImageSize incorrect\n"));
708 return EFI_SECURITY_VIOLATION
;
712 // Check FMP capsule layout
714 if (IsFmpCapsuleGuid (&CapsuleHeader
->CapsuleGuid
)) {
715 DEBUG ((DEBUG_INFO
, "CreateHobForRecoveryCapsule\n"));
717 DEBUG ((DEBUG_INFO
, "ProcessCapsuleImage for FmpCapsule ...\n"));
718 DEBUG ((DEBUG_INFO
, "ValidateFmpCapsule ...\n"));
719 Status
= ValidateFmpCapsule (CapsuleHeader
, &IsSystemFmp
, NULL
);
720 DEBUG ((DEBUG_INFO
, "ValidateFmpCapsule - %r\n", Status
));
721 if (EFI_ERROR (Status
)) {
726 // Process EFI FMP Capsule
728 DEBUG ((DEBUG_INFO
, "ProcessFmpCapsuleImage ...\n"));
729 Status
= ProcessFmpCapsuleImage (CapsuleHeader
, IsSystemFmp
);
730 DEBUG ((DEBUG_INFO
, "ProcessFmpCapsuleImage - %r\n", Status
));
732 DEBUG ((DEBUG_INFO
, "CreateHobForRecoveryCapsule Done\n"));
736 return EFI_UNSUPPORTED
;
740 Loads a DXE capsule from some media into memory and updates the HOB table
741 with the DXE firmware volume information.
743 @param[in] PeiServices General-purpose services that are available to every PEIM.
744 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
746 @retval EFI_SUCCESS The capsule was loaded correctly.
747 @retval EFI_DEVICE_ERROR A device error occurred.
748 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
753 LoadRecoveryCapsule (
754 IN EFI_PEI_SERVICES
**PeiServices
,
755 IN EFI_PEI_RECOVERY_MODULE_PPI
*This
759 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*DeviceRecoveryPpi
;
760 UINTN NumberRecoveryCapsules
;
762 UINTN CapsuleInstance
;
764 EFI_GUID CapsuleType
;
767 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Recovery Entry\n"));
769 for (Instance
= 0; ; Instance
++) {
770 Status
= PeiServicesLocatePpi (
771 &gEfiPeiDeviceRecoveryModulePpiGuid
,
774 (VOID
**)&DeviceRecoveryPpi
776 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - LocateRecoveryPpi (%d) - %r\n", Instance
, Status
));
777 if (EFI_ERROR (Status
)) {
781 NumberRecoveryCapsules
= 0;
782 Status
= DeviceRecoveryPpi
->GetNumberRecoveryCapsules (
783 (EFI_PEI_SERVICES
**)PeiServices
,
785 &NumberRecoveryCapsules
787 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules
, Status
));
788 if (EFI_ERROR (Status
)) {
792 for (CapsuleInstance
= 1; CapsuleInstance
<= NumberRecoveryCapsules
; CapsuleInstance
++) {
794 Status
= DeviceRecoveryPpi
->GetRecoveryCapsuleInfo (
795 (EFI_PEI_SERVICES
**)PeiServices
,
801 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance
, CapsuleSize
, Status
));
802 if (EFI_ERROR (Status
)) {
806 CapsuleBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (CapsuleSize
));
807 if (CapsuleBuffer
== NULL
) {
808 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - AllocatePool fail\n"));
812 Status
= DeviceRecoveryPpi
->LoadRecoveryCapsule (
813 (EFI_PEI_SERVICES
**)PeiServices
,
818 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance
, Status
));
819 if (EFI_ERROR (Status
)) {
820 FreePages (CapsuleBuffer
, EFI_SIZE_TO_PAGES (CapsuleSize
));
825 // good, load capsule buffer
827 Status
= ProcessRecoveryCapsule (CapsuleBuffer
, CapsuleSize
);
832 return EFI_NOT_FOUND
;