diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-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.c | 1406 |
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; +} |
