summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c691
1 files changed, 691 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
new file mode 100644
index 00000000..e721a64b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
@@ -0,0 +1,691 @@
+/** @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;
+}