diff options
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.c | 691 |
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; +} |