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, Intel Corporation. All rights reserved.<BR>
13 This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
24 // The package level header files this module uses
29 // The protocols, PPI and GUID defintions for this module
31 #include <Ppi/MasterBootMode.h>
32 #include <Ppi/BootInRecoveryMode.h>
33 #include <Ppi/RecoveryModule.h>
34 #include <Ppi/DeviceRecoveryModule.h>
35 #include <Ppi/FirmwareVolumeInfo.h>
36 #include <Guid/FirmwareFileSystem2.h>
37 #include <Guid/FmpCapsule.h>
38 #include <Guid/EdkiiSystemFmpCapsule.h>
41 // The Library classes this module consumes
43 #include <Library/DebugLib.h>
44 #include <Library/PeimEntryPoint.h>
45 #include <Library/PeiServicesLib.h>
46 #include <Library/HobLib.h>
47 #include <Library/BaseMemoryLib.h>
48 #include <Library/MemoryAllocationLib.h>
49 #include <Library/PcdLib.h>
51 #include "RecoveryModuleLoadPei.h"
54 Loads a DXE capsule from some media into memory and updates the HOB table
55 with the DXE firmware volume information.
57 @param[in] PeiServices General-purpose services that are available to every PEIM.
58 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
60 @retval EFI_SUCCESS The capsule was loaded correctly.
61 @retval EFI_DEVICE_ERROR A device error occurred.
62 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
68 IN EFI_PEI_SERVICES
**PeiServices
,
69 IN EFI_PEI_RECOVERY_MODULE_PPI
*This
72 EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi
= {
76 EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList
= {
77 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
78 &gEfiPeiRecoveryModulePpiGuid
,
83 Parse Config data file to get the updated data array.
85 @param[in] DataBuffer Config raw file buffer.
86 @param[in] BufferSize Size of raw buffer.
87 @param[in, out] ConfigHeader Pointer to the config header.
88 @param[in, out] RecoveryArray Pointer to the config of recovery data.
90 @retval EFI_NOT_FOUND No config data is found.
91 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
92 @retval EFI_SUCCESS Parse the config file successfully.
96 ParseRecoveryDataFile (
99 IN OUT CONFIG_HEADER
*ConfigHeader
,
100 IN OUT RECOVERY_CONFIG_DATA
**RecoveryArray
104 Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
106 @param[in] FmpImageHeader A pointer to EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
108 @return TRUE It is a system FMP.
109 @return FALSE It is a device FMP.
113 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*FmpImageHeader
120 Guid
= PcdGetPtr(PcdSystemFmpCapsuleImageTypeIdGuid
);
121 Count
= PcdGetSize(PcdSystemFmpCapsuleImageTypeIdGuid
) / sizeof(GUID
);
123 for (Index
= 0; Index
< Count
; Index
++, Guid
++) {
124 if (CompareGuid(&FmpImageHeader
->UpdateImageTypeId
, Guid
)) {
133 Return if this CapsuleGuid is a FMP capsule GUID or not.
135 @param[in] CapsuleGuid A pointer to EFI_GUID
137 @return TRUE It is a FMP capsule GUID.
138 @return FALSE It is not a FMP capsule GUID.
142 IN EFI_GUID
*CapsuleGuid
145 if (CompareGuid(&gEfiFmpCapsuleGuid
, CapsuleGuid
)) {
153 This function assumes the input Capusule image already passes basic check in
154 ValidateFmpCapsule().
156 Criteria of system FMP capsule is:
157 1) FmpCapsuleHeader->EmbeddedDriverCount is 0.
158 2) FmpCapsuleHeader->PayloadItemCount is not 0.
159 3) All ImageHeader->UpdateImageTypeId matches PcdSystemFmpCapsuleImageTypeIdGuid.
161 @param[in] CapsuleHeader Points to a capsule header.
163 @retval TRUE Input capsule is a correct system FMP capsule.
164 @retval FALSE Input capsule is not a correct system FMP capsule.
167 IsSystemFmpCapsuleImage (
168 IN EFI_CAPSULE_HEADER
*CapsuleHeader
171 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
172 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
173 UINT64
*ItemOffsetList
;
177 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*) ((UINT8
*) CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
179 if (FmpCapsuleHeader
->EmbeddedDriverCount
!= 0) {
183 if (FmpCapsuleHeader
->PayloadItemCount
== 0) {
187 ItemNum
= FmpCapsuleHeader
->EmbeddedDriverCount
+ FmpCapsuleHeader
->PayloadItemCount
;
189 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
191 for (Index
= 0; Index
< ItemNum
; Index
++) {
192 ImageHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*)((UINT8
*)FmpCapsuleHeader
+ ItemOffsetList
[Index
]);
193 if (!IsSystemFmpImage(ImageHeader
)) {
202 Validate if it is valid capsule header
204 This function assumes the caller provided correct CapsuleHeader pointer
207 This function validates the fields in EFI_CAPSULE_HEADER.
209 @param[in] CapsuleHeader Points to a capsule header.
210 @param[in] CapsuleSize Size of the whole capsule image.
214 IsValidCapsuleHeader (
215 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
216 IN UINT64 CapsuleSize
219 if (CapsuleHeader
->CapsuleImageSize
!= CapsuleSize
) {
222 if (CapsuleHeader
->HeaderSize
>= CapsuleHeader
->CapsuleImageSize
) {
229 Validate Fmp capsules layout.
231 Caution: This function may receive untrusted input.
233 This function assumes the caller validated the capsule by using
234 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
235 The capsule buffer size is CapsuleHeader->CapsuleImageSize.
237 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
238 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
240 @param[in] CapsuleHeader Points to a capsule header.
241 @param[out] IsSystemFmp If it is a system FMP.
242 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
244 @retval EFI_SUCESS Input capsule is a correct FMP capsule.
245 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
249 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
250 OUT BOOLEAN
*IsSystemFmp
, OPTIONAL
251 OUT UINT16
*EmbeddedDriverCount OPTIONAL
254 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*FmpCapsuleHeader
;
256 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
;
258 UINT64
*ItemOffsetList
;
261 UINTN FmpCapsuleSize
;
262 UINTN FmpCapsuleHeaderSize
;
264 UINTN FmpImageHeaderSize
;
266 if (CapsuleHeader
->HeaderSize
>= CapsuleHeader
->CapsuleImageSize
) {
267 DEBUG((DEBUG_ERROR
, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader
->HeaderSize
, CapsuleHeader
->CapsuleImageSize
));
268 return EFI_INVALID_PARAMETER
;
271 FmpCapsuleHeader
= (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
*) ((UINT8
*) CapsuleHeader
+ CapsuleHeader
->HeaderSize
);
272 EndOfCapsule
= (UINT8
*) CapsuleHeader
+ CapsuleHeader
->CapsuleImageSize
;
273 FmpCapsuleSize
= (UINTN
)EndOfCapsule
- (UINTN
)FmpCapsuleHeader
;
275 if (FmpCapsuleSize
< sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
)) {
276 DEBUG((DEBUG_ERROR
, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize
));
277 return EFI_INVALID_PARAMETER
;
280 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
281 if (FmpCapsuleHeader
->Version
!= EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION
) {
282 DEBUG((DEBUG_ERROR
, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader
->Version
));
283 return EFI_INVALID_PARAMETER
;
285 ItemOffsetList
= (UINT64
*)(FmpCapsuleHeader
+ 1);
288 ItemNum
= FmpCapsuleHeader
->EmbeddedDriverCount
+ FmpCapsuleHeader
->PayloadItemCount
;
290 if ((FmpCapsuleSize
- sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
))/sizeof(UINT64
) < ItemNum
) {
291 DEBUG((DEBUG_ERROR
, "ItemNum(0x%x) too big\n", ItemNum
));
292 return EFI_INVALID_PARAMETER
;
294 FmpCapsuleHeaderSize
= sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
) + sizeof(UINT64
)*ItemNum
;
296 // Check ItemOffsetList
297 for (Index
= 0; Index
< ItemNum
; Index
++) {
298 if (ItemOffsetList
[Index
] >= FmpCapsuleSize
) {
299 DEBUG((DEBUG_ERROR
, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index
, ItemOffsetList
[Index
], FmpCapsuleSize
));
300 return EFI_INVALID_PARAMETER
;
302 if (ItemOffsetList
[Index
] < FmpCapsuleHeaderSize
) {
303 DEBUG((DEBUG_ERROR
, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index
, ItemOffsetList
[Index
], FmpCapsuleHeaderSize
));
304 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];
325 FmpImageSize
= (UINTN
)EndOfPayload
- ItemOffsetList
[Index
];
327 if (FmpImageSize
< OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, UpdateHardwareInstance
)) {
328 DEBUG((DEBUG_ERROR
, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize
));
329 return EFI_INVALID_PARAMETER
;
331 FmpImageHeaderSize
= sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
);
332 if ((ImageHeader
->Version
> EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION
) ||
333 (ImageHeader
->Version
< 1)) {
334 DEBUG((DEBUG_ERROR
, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader
->Version
));
335 return EFI_INVALID_PARAMETER
;
337 if (ImageHeader
->Version
< EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION
) {
338 FmpImageHeaderSize
= OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, UpdateHardwareInstance
);
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_SUCESS 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(
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_SUCESS 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_SUCESS 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_SUCESS 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
650 Image
= (UINT8
*)ImageHeader
+ OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
, UpdateHardwareInstance
);
653 Status
= ProcessRecoveryImage (Image
, ImageHeader
->UpdateImageSize
);
654 if (EFI_ERROR(Status
)) {
663 Process recovery capsule image.
665 Caution: This function may receive untrusted input.
667 @param[in] CapsuleBuffer The capsule image buffer.
668 @param[in] CapsuleSize The size of the capsule image in bytes.
670 @retval EFI_SUCCESS The recovery capsule is processed.
671 @retval EFI_SECURITY_VIOLATION The recovery capsule is not process because of security violation.
672 @retval EFI_NOT_FOUND The recovery capsule is not process because of unrecognization.
676 ProcessRecoveryCapsule (
677 IN VOID
*CapsuleBuffer
,
683 EFI_CAPSULE_HEADER
*CapsuleHeader
;
685 CapsuleHeader
= CapsuleBuffer
;
686 if (!IsValidCapsuleHeader (CapsuleHeader
, CapsuleSize
)) {
687 DEBUG((DEBUG_ERROR
, "CapsuleImageSize incorrect\n"));
688 return EFI_SECURITY_VIOLATION
;
692 // Check FMP capsule layout
694 if (IsFmpCapsuleGuid(&CapsuleHeader
->CapsuleGuid
)) {
695 DEBUG((DEBUG_INFO
, "CreateHobForRecoveryCapsule\n"));
697 DEBUG((DEBUG_INFO
, "ProcessCapsuleImage for FmpCapsule ...\n"));
698 DEBUG((DEBUG_INFO
, "ValidateFmpCapsule ...\n"));
699 Status
= ValidateFmpCapsule(CapsuleHeader
, &IsSystemFmp
, NULL
);
700 DEBUG((DEBUG_INFO
, "ValidateFmpCapsule - %r\n", Status
));
701 if (EFI_ERROR(Status
)) {
706 // Press EFI FMP Capsule
708 DEBUG((DEBUG_INFO
, "ProcessFmpCapsuleImage ...\n"));
709 Status
= ProcessFmpCapsuleImage(CapsuleHeader
, IsSystemFmp
);
710 DEBUG((DEBUG_INFO
, "ProcessFmpCapsuleImage - %r\n", Status
));
712 DEBUG((DEBUG_INFO
, "CreateHobForRecoveryCapsule Done\n"));
716 return EFI_UNSUPPORTED
;
720 Loads a DXE capsule from some media into memory and updates the HOB table
721 with the DXE firmware volume information.
723 @param[in] PeiServices General-purpose services that are available to every PEIM.
724 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
726 @retval EFI_SUCCESS The capsule was loaded correctly.
727 @retval EFI_DEVICE_ERROR A device error occurred.
728 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
733 LoadRecoveryCapsule (
734 IN EFI_PEI_SERVICES
**PeiServices
,
735 IN EFI_PEI_RECOVERY_MODULE_PPI
*This
739 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
*DeviceRecoveryPpi
;
740 UINTN NumberRecoveryCapsules
;
742 UINTN CapsuleInstance
;
744 EFI_GUID CapsuleType
;
747 DEBUG((DEBUG_INFO
| DEBUG_LOAD
, "Recovery Entry\n"));
749 for (Instance
= 0; ; Instance
++) {
750 Status
= PeiServicesLocatePpi (
751 &gEfiPeiDeviceRecoveryModulePpiGuid
,
754 (VOID
**)&DeviceRecoveryPpi
756 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - LocateRecoveryPpi (%d) - %r\n", Instance
, Status
));
757 if (EFI_ERROR (Status
)) {
760 NumberRecoveryCapsules
= 0;
761 Status
= DeviceRecoveryPpi
->GetNumberRecoveryCapsules (
762 (EFI_PEI_SERVICES
**)PeiServices
,
764 &NumberRecoveryCapsules
766 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules
, Status
));
767 if (EFI_ERROR (Status
)) {
770 for (CapsuleInstance
= 1; CapsuleInstance
<= NumberRecoveryCapsules
; CapsuleInstance
++) {
772 Status
= DeviceRecoveryPpi
->GetRecoveryCapsuleInfo (
773 (EFI_PEI_SERVICES
**)PeiServices
,
775 FeaturePcdGet(PcdFrameworkCompatibilitySupport
) ? CapsuleInstance
- 1 : CapsuleInstance
,
779 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance
, CapsuleSize
, Status
));
780 if (EFI_ERROR (Status
)) {
784 CapsuleBuffer
= AllocatePages (EFI_SIZE_TO_PAGES(CapsuleSize
));
785 if (CapsuleBuffer
== NULL
) {
786 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - AllocatePool fail\n"));
789 Status
= DeviceRecoveryPpi
->LoadRecoveryCapsule (
790 (EFI_PEI_SERVICES
**)PeiServices
,
792 FeaturePcdGet(PcdFrameworkCompatibilitySupport
) ? CapsuleInstance
- 1 : CapsuleInstance
,
795 DEBUG ((DEBUG_ERROR
, "LoadRecoveryCapsule - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance
, Status
));
796 if (EFI_ERROR (Status
)) {
797 FreePages (CapsuleBuffer
, EFI_SIZE_TO_PAGES(CapsuleSize
));
801 // good, load capsule buffer
803 Status
= ProcessRecoveryCapsule (CapsuleBuffer
, CapsuleSize
);
808 return EFI_NOT_FOUND
;