mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 14:35:03 +00:00 
			
		
		
		
	The description of parameter CapFileName is missing in comments. So add the description. Cc: Jian J Wang <jian.j.wang@intel.com> Signed-off-by: Shenglei Zhang <shenglei.zhang@intel.com> Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
		
			
				
	
	
		
			692 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			692 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  DXE capsule process.
 | 
						|
 | 
						|
  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.
 | 
						|
 | 
						|
  ProcessCapsules(), ProcessTheseCapsules() will receive untrusted
 | 
						|
  input and do basic validation.
 | 
						|
 | 
						|
  Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include <PiDxe.h>
 | 
						|
#include <Protocol/EsrtManagement.h>
 | 
						|
#include <Protocol/FirmwareManagementProgress.h>
 | 
						|
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/UefiBootServicesTableLib.h>
 | 
						|
#include <Library/UefiRuntimeServicesTableLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/UefiLib.h>
 | 
						|
#include <Library/PcdLib.h>
 | 
						|
#include <Library/HobLib.h>
 | 
						|
#include <Library/ReportStatusCodeLib.h>
 | 
						|
#include <Library/CapsuleLib.h>
 | 
						|
#include <Library/DisplayUpdateProgressLib.h>
 | 
						|
 | 
						|
#include <IndustryStandard/WindowsUxCapsule.h>
 | 
						|
 | 
						|
extern EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL  *mFmpProgress;
 | 
						|
 | 
						|
/**
 | 
						|
  Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.
 | 
						|
 | 
						|
  @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
 | 
						|
 | 
						|
  @retval TRUE  It is a system FMP.
 | 
						|
  @retval FALSE It is a device FMP.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsFmpCapsule (
 | 
						|
  IN EFI_CAPSULE_HEADER  *CapsuleHeader
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  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.
 | 
						|
 | 
						|
  This function need support nested FMP capsule.
 | 
						|
 | 
						|
  @param[in]   CapsuleHeader        Points to a capsule header.
 | 
						|
  @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 UINT16             *EmbeddedDriverCount OPTIONAL
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
 | 
						|
 | 
						|
  @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
 | 
						|
 | 
						|
  @retval TRUE  It is a capsule name capsule.
 | 
						|
  @retval FALSE It is not a capsule name capsule.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsCapsuleNameCapsule (
 | 
						|
  IN EFI_CAPSULE_HEADER         *CapsuleHeader
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Check the integrity of the capsule name capsule.
 | 
						|
  If the capsule is vaild, return the physical address of each capsule name string.
 | 
						|
 | 
						|
  @param[in]  CapsuleHeader   Pointer to the capsule header of a capsule name capsule.
 | 
						|
  @param[out] CapsuleNameNum  Number of capsule name.
 | 
						|
 | 
						|
  @retval NULL                Capsule name capsule is not valid.
 | 
						|
  @retval CapsuleNameBuf      Array of capsule name physical address.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_PHYSICAL_ADDRESS *
 | 
						|
ValidateCapsuleNameCapsuleIntegrity (
 | 
						|
  IN  EFI_CAPSULE_HEADER            *CapsuleHeader,
 | 
						|
  OUT UINTN                         *CapsuleNameNum
 | 
						|
  );
 | 
						|
 | 
						|
extern BOOLEAN                   mDxeCapsuleLibEndOfDxe;
 | 
						|
BOOLEAN                          mNeedReset = FALSE;
 | 
						|
 | 
						|
VOID                        **mCapsulePtr;
 | 
						|
CHAR16                      **mCapsuleNamePtr;
 | 
						|
EFI_STATUS                  *mCapsuleStatusArray;
 | 
						|
UINT32                      mCapsuleTotalNumber;
 | 
						|
 | 
						|
/**
 | 
						|
  The firmware implements to process the capsule image.
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
 | 
						|
  @param[in]  CapsuleHeader         Points to a capsule header.
 | 
						|
  @param[in]  CapFileName           Capsule file name.
 | 
						|
  @param[out] ResetRequired         Indicates whether reset is required or not.
 | 
						|
 | 
						|
  @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
 | 
						|
EFIAPI
 | 
						|
ProcessThisCapsuleImage (
 | 
						|
  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
 | 
						|
  IN CHAR16              *CapFileName,  OPTIONAL
 | 
						|
  OUT BOOLEAN            *ResetRequired OPTIONAL
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Function indicate the current completion progress of the firmware
 | 
						|
  update. Platform may override with own specific progress function.
 | 
						|
 | 
						|
  @param[in]  Completion  A value between 1 and 100 indicating the current
 | 
						|
                          completion progress of the firmware update
 | 
						|
 | 
						|
  @retval EFI_SUCESS             The capsule update progress was updated.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Completion is greater than 100%.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UpdateImageProgress (
 | 
						|
  IN UINTN  Completion
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                           Status;
 | 
						|
  UINTN                                Seconds;
 | 
						|
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION  *Color;
 | 
						|
 | 
						|
  DEBUG((DEBUG_INFO, "Update Progress - %d%%\n", Completion));
 | 
						|
 | 
						|
  if (Completion > 100) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Use a default timeout of 5 minutes if there is not FMP Progress Protocol.
 | 
						|
  //
 | 
						|
  Seconds = 5 * 60;
 | 
						|
  Color   = NULL;
 | 
						|
  if (mFmpProgress != NULL) {
 | 
						|
    Seconds = mFmpProgress->WatchdogSeconds;
 | 
						|
    Color   = &mFmpProgress->ProgressBarForegroundColor;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Cancel the watchdog timer
 | 
						|
  //
 | 
						|
  gBS->SetWatchdogTimer (0, 0x0000, 0, NULL);
 | 
						|
 | 
						|
  if (Completion != 100) {
 | 
						|
    //
 | 
						|
    // Arm the watchdog timer from PCD setting
 | 
						|
    //
 | 
						|
    if (Seconds != 0) {
 | 
						|
      DEBUG ((DEBUG_VERBOSE, "Arm watchdog timer %d seconds\n", Seconds));
 | 
						|
      gBS->SetWatchdogTimer (Seconds, 0x0000, 0, NULL);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = DisplayUpdateProgress (Completion, Color);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function initializes the mCapsulePtr, mCapsuleStatusArray and mCapsuleTotalNumber.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
InitCapsulePtr (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_PEI_HOB_POINTERS        HobPointer;
 | 
						|
  UINTN                       Index;
 | 
						|
  UINTN                       Index2;
 | 
						|
  UINTN                       Index3;
 | 
						|
  UINTN                       CapsuleNameNumber;
 | 
						|
  UINTN                       CapsuleNameTotalNumber;
 | 
						|
  UINTN                       CapsuleNameCapsuleTotalNumber;
 | 
						|
  VOID                        **CapsuleNameCapsulePtr;
 | 
						|
  EFI_PHYSICAL_ADDRESS        *CapsuleNameAddress;
 | 
						|
 | 
						|
  CapsuleNameNumber             = 0;
 | 
						|
  CapsuleNameTotalNumber        = 0;
 | 
						|
  CapsuleNameCapsuleTotalNumber = 0;
 | 
						|
  CapsuleNameCapsulePtr         = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find all capsule images from hob
 | 
						|
  //
 | 
						|
  HobPointer.Raw = GetHobList ();
 | 
						|
  while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
 | 
						|
    if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) {
 | 
						|
      HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid
 | 
						|
    } else {
 | 
						|
      if (IsCapsuleNameCapsule((VOID *)(UINTN)HobPointer.Capsule->BaseAddress)) {
 | 
						|
        CapsuleNameCapsuleTotalNumber++;
 | 
						|
      } else {
 | 
						|
        mCapsuleTotalNumber++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    HobPointer.Raw = GET_NEXT_HOB (HobPointer);
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "mCapsuleTotalNumber - 0x%x\n", mCapsuleTotalNumber));
 | 
						|
 | 
						|
  if (mCapsuleTotalNumber == 0) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Init temp Capsule Data table.
 | 
						|
  //
 | 
						|
  mCapsulePtr       = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);
 | 
						|
  if (mCapsulePtr == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Allocate mCapsulePtr fail!\n"));
 | 
						|
    mCapsuleTotalNumber = 0;
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  mCapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * mCapsuleTotalNumber);
 | 
						|
  if (mCapsuleStatusArray == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Allocate mCapsuleStatusArray fail!\n"));
 | 
						|
    FreePool (mCapsulePtr);
 | 
						|
    mCapsulePtr = NULL;
 | 
						|
    mCapsuleTotalNumber = 0;
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  SetMemN (mCapsuleStatusArray, sizeof (EFI_STATUS) * mCapsuleTotalNumber, EFI_NOT_READY);
 | 
						|
 | 
						|
  CapsuleNameCapsulePtr =  (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleNameCapsuleTotalNumber);
 | 
						|
  if (CapsuleNameCapsulePtr == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Allocate CapsuleNameCapsulePtr fail!\n"));
 | 
						|
    FreePool (mCapsulePtr);
 | 
						|
    FreePool (mCapsuleStatusArray);
 | 
						|
    mCapsulePtr         = NULL;
 | 
						|
    mCapsuleStatusArray = NULL;
 | 
						|
    mCapsuleTotalNumber = 0;
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Find all capsule images from hob
 | 
						|
  //
 | 
						|
  HobPointer.Raw = GetHobList ();
 | 
						|
  Index  = 0;
 | 
						|
  Index2 = 0;
 | 
						|
  while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
 | 
						|
    if (IsCapsuleNameCapsule ((VOID *) (UINTN) HobPointer.Capsule->BaseAddress)) {
 | 
						|
      CapsuleNameCapsulePtr [Index2++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;
 | 
						|
    } else {
 | 
						|
      mCapsulePtr [Index++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;
 | 
						|
    }
 | 
						|
    HobPointer.Raw = GET_NEXT_HOB (HobPointer);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Find Capsule On Disk Names
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < CapsuleNameCapsuleTotalNumber; Index ++) {
 | 
						|
    CapsuleNameAddress = ValidateCapsuleNameCapsuleIntegrity (CapsuleNameCapsulePtr[Index], &CapsuleNameNumber);
 | 
						|
    if (CapsuleNameAddress != NULL ) {
 | 
						|
      CapsuleNameTotalNumber += CapsuleNameNumber;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (CapsuleNameTotalNumber == mCapsuleTotalNumber) {
 | 
						|
    mCapsuleNamePtr = (CHAR16 **) AllocateZeroPool (sizeof (CHAR16 *) * mCapsuleTotalNumber);
 | 
						|
    if (mCapsuleNamePtr == NULL) {
 | 
						|
      DEBUG ((DEBUG_ERROR, "Allocate mCapsuleNamePtr fail!\n"));
 | 
						|
      FreePool (mCapsulePtr);
 | 
						|
      FreePool (mCapsuleStatusArray);
 | 
						|
      FreePool (CapsuleNameCapsulePtr);
 | 
						|
      mCapsulePtr         = NULL;
 | 
						|
      mCapsuleStatusArray = NULL;
 | 
						|
      mCapsuleTotalNumber = 0;
 | 
						|
      return ;
 | 
						|
    }
 | 
						|
 | 
						|
    for (Index = 0, Index3 = 0; Index < CapsuleNameCapsuleTotalNumber; Index ++) {
 | 
						|
      CapsuleNameAddress = ValidateCapsuleNameCapsuleIntegrity (CapsuleNameCapsulePtr[Index], &CapsuleNameNumber);
 | 
						|
      if (CapsuleNameAddress != NULL ) {
 | 
						|
        for (Index2 = 0; Index2 < CapsuleNameNumber; Index2 ++) {
 | 
						|
          mCapsuleNamePtr[Index3 ++] = (CHAR16 *)(UINTN) CapsuleNameAddress[Index2];
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    mCapsuleNamePtr = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (CapsuleNameCapsulePtr);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function returns if all capsule images are processed.
 | 
						|
 | 
						|
  @retval TRUE   All capsule images are processed.
 | 
						|
  @retval FALSE  Not all capsule images are processed.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
AreAllImagesProcessed (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN  Index;
 | 
						|
 | 
						|
  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {
 | 
						|
    if (mCapsuleStatusArray[Index] == EFI_NOT_READY) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function populates capsule in the configuration table.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PopulateCapsuleInConfigurationTable (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID                        **CapsulePtrCache;
 | 
						|
  EFI_GUID                    *CapsuleGuidCache;
 | 
						|
  EFI_CAPSULE_HEADER          *CapsuleHeader;
 | 
						|
  EFI_CAPSULE_TABLE           *CapsuleTable;
 | 
						|
  UINT32                      CacheIndex;
 | 
						|
  UINT32                      CacheNumber;
 | 
						|
  UINT32                      CapsuleNumber;
 | 
						|
  UINTN                       Index;
 | 
						|
  UINTN                       Size;
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
 | 
						|
  if (mCapsuleTotalNumber == 0) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  CapsulePtrCache     = NULL;
 | 
						|
  CapsuleGuidCache    = NULL;
 | 
						|
  CacheIndex          = 0;
 | 
						|
  CacheNumber         = 0;
 | 
						|
 | 
						|
  CapsulePtrCache  = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);
 | 
						|
  if (CapsulePtrCache == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Allocate CapsulePtrCache fail!\n"));
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * mCapsuleTotalNumber);
 | 
						|
  if (CapsuleGuidCache == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Allocate CapsuleGuidCache fail!\n"));
 | 
						|
    FreePool (CapsulePtrCache);
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating
 | 
						|
  // System to have information persist across a system reset. EFI System Table must
 | 
						|
  // point to an array of capsules that contains the same CapsuleGuid value. And agents
 | 
						|
  // searching for this type capsule will look in EFI System Table and search for the
 | 
						|
  // capsule's Guid and associated pointer to retrieve the data. Two steps below describes
 | 
						|
  // how to sorting the capsules by the unique guid and install the array to EFI System Table.
 | 
						|
  // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an
 | 
						|
  // array for later sorting capsules by CapsuleGuid.
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {
 | 
						|
    CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];
 | 
						|
    if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {
 | 
						|
      //
 | 
						|
      // For each capsule, we compare it with known CapsuleGuid in the CacheArray.
 | 
						|
      // If already has the Guid, skip it. Whereas, record it in the CacheArray as
 | 
						|
      // an additional one.
 | 
						|
      //
 | 
						|
      CacheIndex = 0;
 | 
						|
      while (CacheIndex < CacheNumber) {
 | 
						|
        if (CompareGuid(&CapsuleGuidCache[CacheIndex],&CapsuleHeader->CapsuleGuid)) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        CacheIndex++;
 | 
						|
      }
 | 
						|
      if (CacheIndex == CacheNumber) {
 | 
						|
        CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules
 | 
						|
  // whose guid is the same as it, and malloc memory for an array which preceding
 | 
						|
  // with UINT32. The array fills with entry point of capsules that have the same
 | 
						|
  // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install
 | 
						|
  // this array into EFI System Table, so that agents searching for this type capsule
 | 
						|
  // will look in EFI System Table and search for the capsule's Guid and associated
 | 
						|
  // pointer to retrieve the data.
 | 
						|
  //
 | 
						|
  for (CacheIndex = 0; CacheIndex < CacheNumber; CacheIndex++) {
 | 
						|
    CapsuleNumber = 0;
 | 
						|
    for (Index = 0; Index < mCapsuleTotalNumber; Index++) {
 | 
						|
      CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];
 | 
						|
      if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {
 | 
						|
        if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {
 | 
						|
          //
 | 
						|
          // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid.
 | 
						|
          //
 | 
						|
          CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (CapsuleNumber != 0) {
 | 
						|
      Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*);
 | 
						|
      CapsuleTable = AllocateRuntimePool (Size);
 | 
						|
      if (CapsuleTable == NULL) {
 | 
						|
        DEBUG ((DEBUG_ERROR, "Allocate CapsuleTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      CapsuleTable->CapsuleArrayNumber =  CapsuleNumber;
 | 
						|
      CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));
 | 
						|
      Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        DEBUG ((DEBUG_ERROR, "InstallConfigurationTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool(CapsuleGuidCache);
 | 
						|
  FreePool(CapsulePtrCache);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  This routine is called to process capsules.
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
 | 
						|
  Each individual capsule result is recorded in capsule record variable.
 | 
						|
 | 
						|
  @param[in]  FirstRound         TRUE:  First round. Need skip the FMP capsules with non zero EmbeddedDriverCount.
 | 
						|
                                 FALSE: Process rest FMP capsules.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             There is no error when processing capsules.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ProcessTheseCapsules (
 | 
						|
  IN BOOLEAN  FirstRound
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  EFI_CAPSULE_HEADER          *CapsuleHeader;
 | 
						|
  UINT32                      Index;
 | 
						|
  ESRT_MANAGEMENT_PROTOCOL    *EsrtManagement;
 | 
						|
  UINT16                      EmbeddedDriverCount;
 | 
						|
  BOOLEAN                     ResetRequired;
 | 
						|
  CHAR16                      *CapsuleName;
 | 
						|
 | 
						|
  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));
 | 
						|
 | 
						|
  if (FirstRound) {
 | 
						|
    InitCapsulePtr ();
 | 
						|
  }
 | 
						|
 | 
						|
  if (mCapsuleTotalNumber == 0) {
 | 
						|
    //
 | 
						|
    // We didn't find a hob, so had no errors.
 | 
						|
    //
 | 
						|
    DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n"));
 | 
						|
    mNeedReset = TRUE;
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (AreAllImagesProcessed ()) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install
 | 
						|
  // capsuleTable to configure table with EFI_CAPSULE_GUID
 | 
						|
  //
 | 
						|
  if (FirstRound) {
 | 
						|
    PopulateCapsuleInConfigurationTable ();
 | 
						|
  }
 | 
						|
 | 
						|
  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdatingFirmware)));
 | 
						|
 | 
						|
  //
 | 
						|
  // If Windows UX capsule exist, process it first
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {
 | 
						|
    CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];
 | 
						|
    CapsuleName = (mCapsuleNamePtr == NULL) ? NULL : mCapsuleNamePtr[Index];
 | 
						|
    if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {
 | 
						|
      DEBUG ((DEBUG_INFO, "ProcessThisCapsuleImage (Ux) - 0x%x\n", CapsuleHeader));
 | 
						|
      DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n"));
 | 
						|
      Status = ProcessThisCapsuleImage (CapsuleHeader, CapsuleName, NULL);
 | 
						|
      mCapsuleStatusArray [Index] = EFI_SUCCESS;
 | 
						|
      DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage (Ux) - %r\n", Status));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "Updating the firmware ......\n"));
 | 
						|
 | 
						|
  //
 | 
						|
  // All capsules left are recognized by platform.
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {
 | 
						|
    if (mCapsuleStatusArray [Index] != EFI_NOT_READY) {
 | 
						|
      // already processed
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];
 | 
						|
    CapsuleName = (mCapsuleNamePtr == NULL) ? NULL : mCapsuleNamePtr[Index];
 | 
						|
    if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {
 | 
						|
      //
 | 
						|
      // Call capsule library to process capsule image.
 | 
						|
      //
 | 
						|
      EmbeddedDriverCount = 0;
 | 
						|
      if (IsFmpCapsule(CapsuleHeader)) {
 | 
						|
        Status = ValidateFmpCapsule (CapsuleHeader, &EmbeddedDriverCount);
 | 
						|
        if (EFI_ERROR(Status)) {
 | 
						|
          DEBUG((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n"));
 | 
						|
          mCapsuleStatusArray [Index] = EFI_ABORTED;
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        mCapsuleStatusArray [Index] = EFI_ABORTED;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      if ((!FirstRound) || (EmbeddedDriverCount == 0)) {
 | 
						|
        DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage - 0x%x\n", CapsuleHeader));
 | 
						|
        ResetRequired = FALSE;
 | 
						|
        Status = ProcessThisCapsuleImage (CapsuleHeader, CapsuleName, &ResetRequired);
 | 
						|
        mCapsuleStatusArray [Index] = Status;
 | 
						|
        DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage - %r\n", Status));
 | 
						|
 | 
						|
        if (Status != EFI_NOT_READY) {
 | 
						|
          if (EFI_ERROR(Status)) {
 | 
						|
            REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed)));
 | 
						|
            DEBUG ((DEBUG_ERROR, "Capsule process failed!\n"));
 | 
						|
          } else {
 | 
						|
            REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));
 | 
						|
          }
 | 
						|
 | 
						|
          mNeedReset |= ResetRequired;
 | 
						|
          if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0) {
 | 
						|
            mNeedReset = TRUE;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
 | 
						|
  //
 | 
						|
  // Always sync ESRT Cache from FMP Instance
 | 
						|
  //
 | 
						|
  if (!EFI_ERROR(Status)) {
 | 
						|
    EsrtManagement->SyncEsrtFmp();
 | 
						|
  }
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd)));
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Do reset system.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DoResetSystem (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  DEBUG((DEBUG_INFO, "Capsule Request Cold Reboot."));
 | 
						|
 | 
						|
  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeResettingSystem)));
 | 
						|
 | 
						|
  gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
 | 
						|
 | 
						|
  CpuDeadLoop();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  This routine is called to process capsules.
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
 | 
						|
  The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.
 | 
						|
  If there is no EFI_HOB_UEFI_CAPSULE, it means error occurs, force reset to
 | 
						|
  normal boot path.
 | 
						|
 | 
						|
  This routine should be called twice in BDS.
 | 
						|
  1) The first call must be before EndOfDxe. The system capsules is processed.
 | 
						|
     If device capsule FMP protocols are exposted at this time and device FMP
 | 
						|
     capsule has zero EmbeddedDriverCount, the device capsules are processed.
 | 
						|
     Each individual capsule result is recorded in capsule record variable.
 | 
						|
     System may reset in this function, if reset is required by capsule and
 | 
						|
     all capsules are processed.
 | 
						|
     If not all capsules are processed, reset will be defered to second call.
 | 
						|
 | 
						|
  2) The second call must be after EndOfDxe and after ConnectAll, so that all
 | 
						|
     device capsule FMP protocols are exposed.
 | 
						|
     The system capsules are skipped. If the device capsules are NOT processed
 | 
						|
     in first call, they are processed here.
 | 
						|
     Each individual capsule result is recorded in capsule record variable.
 | 
						|
     System may reset in this function, if reset is required by capsule
 | 
						|
     processed in first call and second call.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             There is no error when processing capsules.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
ProcessCapsules (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
 | 
						|
  if (!mDxeCapsuleLibEndOfDxe) {
 | 
						|
    Status = ProcessTheseCapsules(TRUE);
 | 
						|
 | 
						|
    //
 | 
						|
    // Reboot System if and only if all capsule processed.
 | 
						|
    // If not, defer reset to 2nd process.
 | 
						|
    //
 | 
						|
    if (mNeedReset && AreAllImagesProcessed()) {
 | 
						|
      DoResetSystem();
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    Status = ProcessTheseCapsules(FALSE);
 | 
						|
    //
 | 
						|
    // Reboot System if required after all capsule processed
 | 
						|
    //
 | 
						|
    if (mNeedReset) {
 | 
						|
      DoResetSystem();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 |