summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
diff options
context:
space:
mode:
authorkx <kx@radix.pro>2024-06-04 06:43:08 +0300
committerkx <kx@radix.pro>2024-06-04 06:43:08 +0300
commit7e2ccccace24636f29ddc210b94606abd4c7e42b (patch)
tree545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
parent27b044605cd5f6b33a3d231576003850b3fe305b (diff)
downloadedk2-trunk.tar.xz
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c')
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c1406
1 files changed, 703 insertions, 703 deletions
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
index 2a38a3d95b..2ee59e4c68 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
@@ -1,703 +1,703 @@
-/** @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;
-}
+/** @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;
+}