mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 19:13:50 +00:00 
			
		
		
		
	 1436aea4d5
			
		
	
	
		1436aea4d5
		
	
	
	
	
		
			
			REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the MdeModulePkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
		
			
				
	
	
		
			704 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			704 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;
 | |
| }
 |