mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-04 05:25:45 +01:00 
			
		
		
		
	Cc: Jiewen Yao <jiewen.yao@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
		
			
				
	
	
		
			810 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			810 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Recovery module.
 | 
						|
 | 
						|
  Caution: This module requires additional review when modified.
 | 
						|
  This module will have external input - capsule image.
 | 
						|
  This external input must be validated carefully to avoid security issue like
 | 
						|
  buffer overflow, integer overflow.
 | 
						|
 | 
						|
  ProcessRecoveryCapsule(), ProcessFmpCapsuleImage(), ProcessRecoveryImage(),
 | 
						|
  ValidateFmpCapsule() will receive untrusted input and do basic validation.
 | 
						|
 | 
						|
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
//
 | 
						|
// The package level header files this module uses
 | 
						|
//
 | 
						|
#include <Uefi.h>
 | 
						|
#include <PiPei.h>
 | 
						|
//
 | 
						|
// The protocols, PPI and GUID defintions for this module
 | 
						|
//
 | 
						|
#include <Ppi/MasterBootMode.h>
 | 
						|
#include <Ppi/BootInRecoveryMode.h>
 | 
						|
#include <Ppi/RecoveryModule.h>
 | 
						|
#include <Ppi/DeviceRecoveryModule.h>
 | 
						|
#include <Ppi/FirmwareVolumeInfo.h>
 | 
						|
#include <Guid/FirmwareFileSystem2.h>
 | 
						|
#include <Guid/FmpCapsule.h>
 | 
						|
#include <Guid/EdkiiSystemFmpCapsule.h>
 | 
						|
 | 
						|
//
 | 
						|
// The Library classes this module consumes
 | 
						|
//
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/PeimEntryPoint.h>
 | 
						|
#include <Library/PeiServicesLib.h>
 | 
						|
#include <Library/HobLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/PcdLib.h>
 | 
						|
 | 
						|
#include "RecoveryModuleLoadPei.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Loads a DXE capsule from some media into memory and updates the HOB table
 | 
						|
  with the DXE firmware volume information.
 | 
						|
 | 
						|
  @param[in]  PeiServices   General-purpose services that are available to every PEIM.
 | 
						|
  @param[in]  This          Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        The capsule was loaded correctly.
 | 
						|
  @retval EFI_DEVICE_ERROR   A device error occurred.
 | 
						|
  @retval EFI_NOT_FOUND      A recovery DXE capsule cannot be found.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
LoadRecoveryCapsule (
 | 
						|
  IN EFI_PEI_SERVICES                     **PeiServices,
 | 
						|
  IN EFI_PEI_RECOVERY_MODULE_PPI          *This
 | 
						|
  );
 | 
						|
 | 
						|
EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = {
 | 
						|
  LoadRecoveryCapsule
 | 
						|
};
 | 
						|
 | 
						|
EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = {
 | 
						|
  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
 | 
						|
  &gEfiPeiRecoveryModulePpiGuid,
 | 
						|
  &mRecoveryPpi
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Parse Config data file to get the updated data array.
 | 
						|
 | 
						|
  @param[in]      DataBuffer      Config raw file buffer.
 | 
						|
  @param[in]      BufferSize      Size of raw buffer.
 | 
						|
  @param[in, out] ConfigHeader    Pointer to the config header.
 | 
						|
  @param[in, out] RecoveryArray   Pointer to the config of recovery data.
 | 
						|
 | 
						|
  @retval EFI_NOT_FOUND         No config data is found.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
 | 
						|
  @retval EFI_SUCCESS           Parse the config file successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ParseRecoveryDataFile (
 | 
						|
  IN      UINT8                         *DataBuffer,
 | 
						|
  IN      UINTN                         BufferSize,
 | 
						|
  IN OUT  CONFIG_HEADER                 *ConfigHeader,
 | 
						|
  IN OUT  RECOVERY_CONFIG_DATA          **RecoveryArray
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.
 | 
						|
 | 
						|
  @param[in] FmpImageHeader A pointer to EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
 | 
						|
 | 
						|
  @return TRUE  It is a system FMP.
 | 
						|
  @return FALSE It is a device FMP.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsSystemFmpImage (
 | 
						|
  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER   *FmpImageHeader
 | 
						|
  )
 | 
						|
{
 | 
						|
  GUID      *Guid;
 | 
						|
  UINTN     Count;
 | 
						|
  UINTN     Index;
 | 
						|
 | 
						|
  Guid = PcdGetPtr(PcdSystemFmpCapsuleImageTypeIdGuid);
 | 
						|
  Count = PcdGetSize(PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof(GUID);
 | 
						|
 | 
						|
  for (Index = 0; Index < Count; Index++, Guid++) {
 | 
						|
    if (CompareGuid(&FmpImageHeader->UpdateImageTypeId, Guid)) {
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return if this CapsuleGuid is a FMP capsule GUID or not.
 | 
						|
 | 
						|
  @param[in] CapsuleGuid A pointer to EFI_GUID
 | 
						|
 | 
						|
  @return TRUE  It is a FMP capsule GUID.
 | 
						|
  @return FALSE It is not a FMP capsule GUID.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsFmpCapsuleGuid (
 | 
						|
  IN EFI_GUID  *CapsuleGuid
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function assumes the input Capusule image already passes basic check in
 | 
						|
  ValidateFmpCapsule().
 | 
						|
 | 
						|
  Criteria of system FMP capsule is:
 | 
						|
  1) FmpCapsuleHeader->EmbeddedDriverCount is 0.
 | 
						|
  2) FmpCapsuleHeader->PayloadItemCount is not 0.
 | 
						|
  3) All ImageHeader->UpdateImageTypeId matches PcdSystemFmpCapsuleImageTypeIdGuid.
 | 
						|
 | 
						|
  @param[in]  CapsuleHeader    Points to a capsule header.
 | 
						|
 | 
						|
  @retval TRUE   Input capsule is a correct system FMP capsule.
 | 
						|
  @retval FALSE  Input capsule is not a correct system FMP capsule.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsSystemFmpCapsuleImage (
 | 
						|
  IN EFI_CAPSULE_HEADER *CapsuleHeader
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
 | 
						|
  UINT64                                       *ItemOffsetList;
 | 
						|
  UINT32                                       ItemNum;
 | 
						|
  UINTN                                        Index;
 | 
						|
 | 
						|
  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
 | 
						|
 | 
						|
  if (FmpCapsuleHeader->EmbeddedDriverCount != 0) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (FmpCapsuleHeader->PayloadItemCount == 0) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
 | 
						|
 | 
						|
  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
 | 
						|
 | 
						|
  for (Index = 0; Index < ItemNum; Index++) {
 | 
						|
    ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
 | 
						|
    if (!IsSystemFmpImage(ImageHeader)) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Validate if it is valid capsule header
 | 
						|
 | 
						|
  This function assumes the caller provided correct CapsuleHeader pointer
 | 
						|
  and CapsuleSize.
 | 
						|
 | 
						|
  This function validates the fields in EFI_CAPSULE_HEADER.
 | 
						|
 | 
						|
  @param[in]  CapsuleHeader    Points to a capsule header.
 | 
						|
  @param[in]  CapsuleSize      Size of the whole capsule image.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsValidCapsuleHeader (
 | 
						|
  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
 | 
						|
  IN UINT64              CapsuleSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
  if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Validate Fmp capsules layout.
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
 | 
						|
  This function assumes the caller validated the capsule by using
 | 
						|
  IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
 | 
						|
  The capsule buffer size is CapsuleHeader->CapsuleImageSize.
 | 
						|
 | 
						|
  This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
 | 
						|
  and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
 | 
						|
 | 
						|
  @param[in]   CapsuleHeader        Points to a capsule header.
 | 
						|
  @param[out]  IsSystemFmp          If it is a system FMP.
 | 
						|
  @param[out]  EmbeddedDriverCount  The EmbeddedDriverCount in the FMP capsule.
 | 
						|
 | 
						|
  @retval EFI_SUCESS             Input capsule is a correct FMP capsule.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Input capsule is not a correct FMP capsule.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ValidateFmpCapsule (
 | 
						|
  IN EFI_CAPSULE_HEADER *CapsuleHeader,
 | 
						|
  OUT BOOLEAN           *IsSystemFmp, OPTIONAL
 | 
						|
  OUT UINT16            *EmbeddedDriverCount OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;
 | 
						|
  UINT8                                        *EndOfCapsule;
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
 | 
						|
  UINT8                                        *EndOfPayload;
 | 
						|
  UINT64                                       *ItemOffsetList;
 | 
						|
  UINT32                                       ItemNum;
 | 
						|
  UINTN                                        Index;
 | 
						|
  UINTN                                        FmpCapsuleSize;
 | 
						|
  UINTN                                        FmpCapsuleHeaderSize;
 | 
						|
  UINT64                                       FmpImageSize;
 | 
						|
  UINTN                                        FmpImageHeaderSize;
 | 
						|
 | 
						|
  if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
 | 
						|
    DEBUG((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
 | 
						|
  EndOfCapsule     = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
 | 
						|
  FmpCapsuleSize   = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
 | 
						|
 | 
						|
  if (FmpCapsuleSize < sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
 | 
						|
    DEBUG((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
 | 
						|
  if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
 | 
						|
    DEBUG((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
 | 
						|
 | 
						|
  // No overflow
 | 
						|
  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
 | 
						|
 | 
						|
  if ((FmpCapsuleSize - sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof(UINT64) < ItemNum) {
 | 
						|
    DEBUG((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  FmpCapsuleHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof(UINT64)*ItemNum;
 | 
						|
 | 
						|
  // Check ItemOffsetList
 | 
						|
  for (Index = 0; Index < ItemNum; Index++) {
 | 
						|
    if (ItemOffsetList[Index] >= FmpCapsuleSize) {
 | 
						|
      DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
 | 
						|
      DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // All the address in ItemOffsetList must be stored in ascending order
 | 
						|
    //
 | 
						|
    if (Index > 0) {
 | 
						|
      if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
 | 
						|
        DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1]));
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
 | 
						|
  for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
 | 
						|
    ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
 | 
						|
    if (Index == ItemNum - 1) {
 | 
						|
      EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
 | 
						|
    } else {
 | 
						|
      EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
 | 
						|
    }
 | 
						|
    FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
 | 
						|
 | 
						|
    if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {
 | 
						|
      DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
 | 
						|
    if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
 | 
						|
        (ImageHeader->Version < 1)) {
 | 
						|
      DEBUG((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    if (ImageHeader->Version < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
 | 
						|
      FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
 | 
						|
    }
 | 
						|
 | 
						|
    // No overflow
 | 
						|
    if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
 | 
						|
      DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (ItemNum == 0) {
 | 
						|
    //
 | 
						|
    // No driver & payload element in FMP
 | 
						|
    //
 | 
						|
    EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
 | 
						|
    if (EndOfPayload != EndOfCapsule) {
 | 
						|
      DEBUG((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check in system FMP capsule
 | 
						|
  //
 | 
						|
  if (IsSystemFmp != NULL) {
 | 
						|
    *IsSystemFmp = IsSystemFmpCapsuleImage(CapsuleHeader);
 | 
						|
  }
 | 
						|
 | 
						|
  if (EmbeddedDriverCount != NULL) {
 | 
						|
    *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Recovery module entrypoint
 | 
						|
 | 
						|
  @param[in] FileHandle   Handle of the file being invoked.
 | 
						|
  @param[in] PeiServices  Describes the list of possible PEI Services.
 | 
						|
 | 
						|
  @return EFI_SUCCESS Recovery module is initialized.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
InitializeRecoveryModule (
 | 
						|
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
 | 
						|
  IN CONST EFI_PEI_SERVICES     **PeiServices
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINTN       BootMode;
 | 
						|
 | 
						|
  BootMode = GetBootModeHob();
 | 
						|
  ASSERT(BootMode == BOOT_IN_RECOVERY_MODE);
 | 
						|
 | 
						|
  Status = (**PeiServices).InstallPpi (PeiServices, &mRecoveryPpiList);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create hob and install FvInfo PPI for recovery capsule.
 | 
						|
 | 
						|
  @param[in]  FvImage         Points to the DXE FV image.
 | 
						|
  @param[in]  FvImageSize     The length of the DXE FV image in bytes.
 | 
						|
 | 
						|
  @retval EFI_SUCESS            Create hob and install FvInfo PPI successfully.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED  The input data is not an FV.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  No enough resource to process the input data.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CreateHobForRecoveryCapsule (
 | 
						|
  IN VOID                                *FvImage,
 | 
						|
  IN UINTN                               FvImageSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
 | 
						|
  UINT32                      FvAlignment;
 | 
						|
  UINT64                      FvLength;
 | 
						|
  VOID                        *NewFvBuffer;
 | 
						|
 | 
						|
  //
 | 
						|
  // FvImage should be at its required alignment.
 | 
						|
  //
 | 
						|
  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;
 | 
						|
  //
 | 
						|
  // Validate FV Header, if not as expected, return
 | 
						|
  //
 | 
						|
  if (ReadUnaligned32 (&FvHeader->Signature) != EFI_FVH_SIGNATURE) {
 | 
						|
    DEBUG((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Fv Signature Error)\n"));
 | 
						|
    return EFI_VOLUME_CORRUPTED;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
 | 
						|
  // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
 | 
						|
  // its initial linked location and maintain its alignment.
 | 
						|
  //
 | 
						|
  if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
 | 
						|
    //
 | 
						|
    // Get FvHeader alignment
 | 
						|
    //
 | 
						|
    FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
 | 
						|
    //
 | 
						|
    // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
 | 
						|
    //
 | 
						|
    if (FvAlignment < 8) {
 | 
						|
      FvAlignment = 8;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Allocate the aligned buffer for the FvImage.
 | 
						|
    //
 | 
						|
    if ((UINTN) FvHeader % FvAlignment != 0) {
 | 
						|
      DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule (FvHeader 0x%lx is not aligned)\n", (UINT64)(UINTN)FvHeader));
 | 
						|
      FvLength    = ReadUnaligned64 (&FvHeader->FvLength);
 | 
						|
      NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN) FvLength), FvAlignment);
 | 
						|
      if (NewFvBuffer == NULL) {
 | 
						|
        DEBUG((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Not enough resource to allocate 0x%lx bytes)\n", FvLength));
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
      CopyMem (NewFvBuffer, FvHeader, (UINTN) FvLength);
 | 
						|
      FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*) NewFvBuffer;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  BuildFvHob((UINT64)(UINTN)FvHeader, FvHeader->FvLength);
 | 
						|
  DEBUG((DEBUG_INFO, "BuildFvHob (FV in recovery) - 0x%lx - 0x%lx\n", (UINT64)(UINTN)FvHeader, FvHeader->FvLength));
 | 
						|
 | 
						|
  PeiServicesInstallFvInfoPpi(
 | 
						|
    NULL,
 | 
						|
    (VOID *)FvHeader,
 | 
						|
    (UINT32)FvHeader->FvLength,
 | 
						|
    NULL,
 | 
						|
    NULL
 | 
						|
    );
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create recovery context based upon System Firmware image and config file.
 | 
						|
 | 
						|
  @param[in]  SystemFirmwareImage     Points to the System Firmware image.
 | 
						|
  @param[in]  SystemFirmwareImageSize The length of the System Firmware image in bytes.
 | 
						|
  @param[in]  ConfigImage             Points to the config file image.
 | 
						|
  @param[in]  ConfigImageSize         The length of the config file image in bytes.
 | 
						|
 | 
						|
  @retval EFI_SUCESS             Process Recovery Image successfully.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
RecoverImage (
 | 
						|
  IN VOID                         *SystemFirmwareImage,
 | 
						|
  IN UINTN                        SystemFirmwareImageSize,
 | 
						|
  IN VOID                         *ConfigImage,
 | 
						|
  IN UINTN                        ConfigImageSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
  RECOVERY_CONFIG_DATA                  *ConfigData;
 | 
						|
  RECOVERY_CONFIG_DATA                  *RecoveryConfigData;
 | 
						|
  CONFIG_HEADER                         ConfigHeader;
 | 
						|
  UINTN                                 Index;
 | 
						|
 | 
						|
  if (ConfigImage == NULL) {
 | 
						|
    DEBUG((DEBUG_INFO, "RecoverImage (NoConfig)\n"));
 | 
						|
    Status = CreateHobForRecoveryCapsule(
 | 
						|
               SystemFirmwareImage,
 | 
						|
               SystemFirmwareImageSize
 | 
						|
               );
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  ConfigData        = NULL;
 | 
						|
  ZeroMem (&ConfigHeader, sizeof(ConfigHeader));
 | 
						|
  Status            = ParseRecoveryDataFile (
 | 
						|
                        ConfigImage,
 | 
						|
                        ConfigImageSize,
 | 
						|
                        &ConfigHeader,
 | 
						|
                        &ConfigData
 | 
						|
                        );
 | 
						|
  DEBUG((DEBUG_INFO, "ParseRecoveryDataFile - %r\n", Status));
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  DEBUG((DEBUG_INFO, "ConfigHeader.NumOfRecovery - 0x%x\n", ConfigHeader.NumOfRecovery));
 | 
						|
  DEBUG((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid)));
 | 
						|
 | 
						|
  Index = 0;
 | 
						|
  RecoveryConfigData = ConfigData;
 | 
						|
  while (Index < ConfigHeader.NumOfRecovery) {
 | 
						|
    if (CompareGuid(&RecoveryConfigData->FileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))) {
 | 
						|
      DEBUG((DEBUG_INFO, "FileGuid - %g (processing)\n", &RecoveryConfigData->FileGuid));
 | 
						|
      Status = CreateHobForRecoveryCapsule (
 | 
						|
                 (UINT8 *)SystemFirmwareImage + RecoveryConfigData->ImageOffset,
 | 
						|
                 RecoveryConfigData->Length
 | 
						|
                 );
 | 
						|
      //
 | 
						|
      // Shall updates be serialized so that if a recovery FV is not successfully completed,
 | 
						|
      // the remaining updates won't be performed.
 | 
						|
      //
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      DEBUG((DEBUG_INFO, "FileGuid - %g (ignored)\n", &RecoveryConfigData->FileGuid));
 | 
						|
    }
 | 
						|
 | 
						|
    Index++;
 | 
						|
    RecoveryConfigData++;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process recovery image.
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
 | 
						|
  @param[in]  Image         Points to the recovery image.
 | 
						|
  @param[in]  Length        The length of the recovery image in bytes.
 | 
						|
 | 
						|
  @retval EFI_SUCESS             Process Recovery Image successfully.
 | 
						|
  @retval EFI_SECURITY_VIOLATION Recovery image is not processed due to security violation.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ProcessRecoveryImage (
 | 
						|
  IN VOID   *Image,
 | 
						|
  IN UINTN  Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32                      LastAttemptVersion;
 | 
						|
  UINT32                      LastAttemptStatus;
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  VOID                        *SystemFirmwareImage;
 | 
						|
  UINTN                       SystemFirmwareImageSize;
 | 
						|
  VOID                        *ConfigImage;
 | 
						|
  UINTN                       ConfigImageSize;
 | 
						|
  VOID                        *AuthenticatedImage;
 | 
						|
  UINTN                       AuthenticatedImageSize;
 | 
						|
 | 
						|
  AuthenticatedImage     = NULL;
 | 
						|
  AuthenticatedImageSize = 0;
 | 
						|
 | 
						|
  Status = CapsuleAuthenticateSystemFirmware(Image, Length, TRUE, &LastAttemptVersion, &LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize);
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    DEBUG((DEBUG_INFO, "CapsuleAuthenticateSystemFirmware - %r\n", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  ExtractSystemFirmwareImage(AuthenticatedImage, AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize);
 | 
						|
  ExtractConfigImage(AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize);
 | 
						|
 | 
						|
  Status = RecoverImage(SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize);
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    DEBUG((DEBUG_INFO, "RecoverImage - %r\n", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process Firmware management protocol data capsule.
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
 | 
						|
  This function assumes the caller validated the capsule by using
 | 
						|
  ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
 | 
						|
 | 
						|
  @param[in]  CapsuleHeader         Points to a capsule header.
 | 
						|
  @param[in]  IsSystemFmp           If this capsule is a system FMP capsule.
 | 
						|
 | 
						|
  @retval EFI_SUCESS            Process Capsule Image successfully.
 | 
						|
  @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Not enough memory.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ProcessFmpCapsuleImage (
 | 
						|
  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
 | 
						|
  IN BOOLEAN             IsSystemFmp
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                                    Status;
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
 | 
						|
  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;
 | 
						|
  UINT8                                         *Image;
 | 
						|
  UINT64                                        *ItemOffsetList;
 | 
						|
  UINTN                                         ItemIndex;
 | 
						|
 | 
						|
  if (!IsSystemFmp) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
 | 
						|
  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
 | 
						|
 | 
						|
  for (ItemIndex = 0; ItemIndex < FmpCapsuleHeader->PayloadItemCount; ItemIndex++) {
 | 
						|
    ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemIndex]);
 | 
						|
    if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
 | 
						|
      Image = (UINT8 *)(ImageHeader + 1);
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId.
 | 
						|
      // Header should exclude UpdateHardwareInstance field
 | 
						|
      //
 | 
						|
      Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
 | 
						|
    }
 | 
						|
 | 
						|
    Status = ProcessRecoveryImage (Image, ImageHeader->UpdateImageSize);
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process recovery capsule image.
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
 | 
						|
  @param[in] CapsuleBuffer   The capsule image buffer.
 | 
						|
  @param[in] CapsuleSize     The size of the capsule image in bytes.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS               The recovery capsule is processed.
 | 
						|
  @retval EFI_SECURITY_VIOLATION    The recovery capsule is not process because of security violation.
 | 
						|
  @retval EFI_NOT_FOUND             The recovery capsule is not process because of unrecognization.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
ProcessRecoveryCapsule (
 | 
						|
  IN VOID                                *CapsuleBuffer,
 | 
						|
  IN UINTN                               CapsuleSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                   Status;
 | 
						|
  BOOLEAN                      IsSystemFmp;
 | 
						|
  EFI_CAPSULE_HEADER           *CapsuleHeader;
 | 
						|
 | 
						|
  CapsuleHeader = CapsuleBuffer;
 | 
						|
  if (!IsValidCapsuleHeader (CapsuleHeader, CapsuleSize)) {
 | 
						|
    DEBUG((DEBUG_ERROR, "CapsuleImageSize incorrect\n"));
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check FMP capsule layout
 | 
						|
  //
 | 
						|
  if (IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
 | 
						|
    DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule\n"));
 | 
						|
 | 
						|
    DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
 | 
						|
    DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
 | 
						|
    Status = ValidateFmpCapsule(CapsuleHeader, &IsSystemFmp, NULL);
 | 
						|
    DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Press EFI FMP Capsule
 | 
						|
    //
 | 
						|
    DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
 | 
						|
    Status = ProcessFmpCapsuleImage(CapsuleHeader, IsSystemFmp);
 | 
						|
    DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
 | 
						|
 | 
						|
    DEBUG((DEBUG_INFO, "CreateHobForRecoveryCapsule Done\n"));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Loads a DXE capsule from some media into memory and updates the HOB table
 | 
						|
  with the DXE firmware volume information.
 | 
						|
 | 
						|
  @param[in]  PeiServices   General-purpose services that are available to every PEIM.
 | 
						|
  @param[in]  This          Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS        The capsule was loaded correctly.
 | 
						|
  @retval EFI_DEVICE_ERROR   A device error occurred.
 | 
						|
  @retval EFI_NOT_FOUND      A recovery DXE capsule cannot be found.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
LoadRecoveryCapsule (
 | 
						|
  IN EFI_PEI_SERVICES                     **PeiServices,
 | 
						|
  IN EFI_PEI_RECOVERY_MODULE_PPI          *This
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
  EFI_PEI_DEVICE_RECOVERY_MODULE_PPI  *DeviceRecoveryPpi;
 | 
						|
  UINTN                               NumberRecoveryCapsules;
 | 
						|
  UINTN                               Instance;
 | 
						|
  UINTN                               CapsuleInstance;
 | 
						|
  UINTN                               CapsuleSize;
 | 
						|
  EFI_GUID                            CapsuleType;
 | 
						|
  VOID                                *CapsuleBuffer;
 | 
						|
 | 
						|
  DEBUG((DEBUG_INFO | DEBUG_LOAD, "Recovery Entry\n"));
 | 
						|
 | 
						|
  for (Instance = 0; ; Instance++) {
 | 
						|
    Status = PeiServicesLocatePpi (
 | 
						|
               &gEfiPeiDeviceRecoveryModulePpiGuid,
 | 
						|
               Instance,
 | 
						|
               NULL,
 | 
						|
               (VOID **)&DeviceRecoveryPpi
 | 
						|
               );
 | 
						|
    DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LocateRecoveryPpi (%d) - %r\n", Instance, Status));
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    NumberRecoveryCapsules = 0;
 | 
						|
    Status = DeviceRecoveryPpi->GetNumberRecoveryCapsules (
 | 
						|
                                  (EFI_PEI_SERVICES **)PeiServices,
 | 
						|
                                  DeviceRecoveryPpi,
 | 
						|
                                  &NumberRecoveryCapsules
 | 
						|
                                  );
 | 
						|
    DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules, Status));
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    for (CapsuleInstance = 1; CapsuleInstance <= NumberRecoveryCapsules; CapsuleInstance++) {
 | 
						|
      CapsuleSize = 0;
 | 
						|
      Status = DeviceRecoveryPpi->GetRecoveryCapsuleInfo (
 | 
						|
                                    (EFI_PEI_SERVICES **)PeiServices,
 | 
						|
                                    DeviceRecoveryPpi,
 | 
						|
                                    FeaturePcdGet(PcdFrameworkCompatibilitySupport) ? CapsuleInstance - 1 : CapsuleInstance,
 | 
						|
                                    &CapsuleSize,
 | 
						|
                                    &CapsuleType
 | 
						|
                                    );
 | 
						|
      DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance, CapsuleSize, Status));
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      CapsuleBuffer = AllocatePages (EFI_SIZE_TO_PAGES(CapsuleSize));
 | 
						|
      if (CapsuleBuffer == NULL) {
 | 
						|
        DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - AllocatePool fail\n"));
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      Status = DeviceRecoveryPpi->LoadRecoveryCapsule (
 | 
						|
                                    (EFI_PEI_SERVICES **)PeiServices,
 | 
						|
                                    DeviceRecoveryPpi,
 | 
						|
                                    FeaturePcdGet(PcdFrameworkCompatibilitySupport) ? CapsuleInstance - 1 : CapsuleInstance,
 | 
						|
                                    CapsuleBuffer
 | 
						|
                                    );
 | 
						|
      DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        FreePages (CapsuleBuffer, EFI_SIZE_TO_PAGES(CapsuleSize));
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // good, load capsule buffer
 | 
						|
      //
 | 
						|
      Status = ProcessRecoveryCapsule (CapsuleBuffer, CapsuleSize);
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 |