summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Library/DxeCapsuleLibFmp
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
parent27b044605cd5f6b33a3d231576003850b3fe305b (diff)
downloadedk2-trunk.tar.xz
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Library/DxeCapsuleLibFmp')
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c4026
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h150
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c3382
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf204
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni32
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c1406
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c140
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c1036
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c138
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c348
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf148
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni32
12 files changed, 5521 insertions, 5521 deletions
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
index 41b3282d29..00e975803a 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
@@ -1,2013 +1,2013 @@
-/** @file
- The implementation supports Capusle on Disk.
-
- Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "CapsuleOnDisk.h"
-
-/**
- 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.
-
- This routine assumes the capsule has been validated by IsValidCapsuleHeader(), so
- capsule memory overflow is not going to happen in this routine.
-
- @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
- )
-{
- UINT8 *CapsuleNamePtr;
- UINT8 *CapsuleNameBufStart;
- UINT8 *CapsuleNameBufEnd;
- UINTN Index;
- UINTN StringSize;
- EFI_PHYSICAL_ADDRESS *CapsuleNameBuf;
-
- if (!IsCapsuleNameCapsule (CapsuleHeader)) {
- return NULL;
- }
-
- //
- // Total string size must be even.
- //
- if (((CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize) & BIT0) != 0) {
- return NULL;
- }
-
- *CapsuleNameNum = 0;
- Index = 0;
- CapsuleNameBufStart = (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize;
-
- //
- // If strings are not aligned on a 16-bit boundary, reallocate memory for it.
- //
- if (((UINTN)CapsuleNameBufStart & BIT0) != 0) {
- CapsuleNameBufStart = AllocateCopyPool (CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize, CapsuleNameBufStart);
- if (CapsuleNameBufStart == NULL) {
- return NULL;
- }
- }
-
- CapsuleNameBufEnd = CapsuleNameBufStart + CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
-
- CapsuleNamePtr = CapsuleNameBufStart;
- while (CapsuleNamePtr < CapsuleNameBufEnd) {
- StringSize = StrnSizeS ((CHAR16 *)CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof (CHAR16));
- CapsuleNamePtr += StringSize;
- (*CapsuleNameNum)++;
- }
-
- //
- // Integrity check.
- //
- if (CapsuleNamePtr != CapsuleNameBufEnd) {
- if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {
- FreePool (CapsuleNameBufStart);
- }
-
- return NULL;
- }
-
- CapsuleNameBuf = AllocatePool (*CapsuleNameNum * sizeof (EFI_PHYSICAL_ADDRESS));
- if (CapsuleNameBuf == NULL) {
- if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {
- FreePool (CapsuleNameBufStart);
- }
-
- return NULL;
- }
-
- CapsuleNamePtr = CapsuleNameBufStart;
- while (CapsuleNamePtr < CapsuleNameBufEnd) {
- StringSize = StrnSizeS ((CHAR16 *)CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof (CHAR16));
- CapsuleNameBuf[Index] = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleNamePtr;
- CapsuleNamePtr += StringSize;
- Index++;
- }
-
- return CapsuleNameBuf;
-}
-
-/**
- This routine is called to upper case given unicode string.
-
- @param[in] Str String to upper case
-
- @retval upper cased string after process
-
-**/
-static
-CHAR16 *
-UpperCaseString (
- IN CHAR16 *Str
- )
-{
- CHAR16 *Cptr;
-
- for (Cptr = Str; *Cptr != L'\0'; Cptr++) {
- if ((L'a' <= *Cptr) && (*Cptr <= L'z')) {
- *Cptr = *Cptr - L'a' + L'A';
- }
- }
-
- return Str;
-}
-
-/**
- This routine is used to return substring before period '.' or '\0'
- Caller should respsonsible of substr space allocation & free
-
- @param[in] Str String to check
- @param[out] SubStr First part of string before period or '\0'
- @param[out] SubStrLen Length of first part of string
-
-**/
-static
-VOID
-GetSubStringBeforePeriod (
- IN CHAR16 *Str,
- OUT CHAR16 *SubStr,
- OUT UINTN *SubStrLen
- )
-{
- UINTN Index;
-
- for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {
- SubStr[Index] = Str[Index];
- }
-
- SubStr[Index] = L'\0';
- *SubStrLen = Index;
-}
-
-/**
- This routine pad the string in tail with input character.
-
- @param[in] StrBuf Str buffer to be padded, should be enough room for
- @param[in] PadLen Expected padding length
- @param[in] Character Character used to pad
-
-**/
-static
-VOID
-PadStrInTail (
- IN CHAR16 *StrBuf,
- IN UINTN PadLen,
- IN CHAR16 Character
- )
-{
- UINTN Index;
-
- for (Index = 0; StrBuf[Index] != L'\0'; Index++) {
- }
-
- while (PadLen != 0) {
- StrBuf[Index] = Character;
- Index++;
- PadLen--;
- }
-
- StrBuf[Index] = L'\0';
-}
-
-/**
- This routine find the offset of the last period '.' of string. If No period exists
- function FileNameExtension is set to L'\0'
-
- @param[in] FileName File name to split between last period
- @param[out] FileNameFirst First FileName before last period
- @param[out] FileNameExtension FileName after last period
-
-**/
-static
-VOID
-SplitFileNameExtension (
- IN CHAR16 *FileName,
- OUT CHAR16 *FileNameFirst,
- OUT CHAR16 *FileNameExtension
- )
-{
- UINTN Index;
- UINTN StringLen;
-
- StringLen = StrnLenS (FileName, MAX_FILE_NAME_SIZE);
- for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--) {
- }
-
- //
- // No period exists. No FileName Extension
- //
- if ((Index == 0) && (FileName[Index] != L'.')) {
- FileNameExtension[0] = L'\0';
- Index = StringLen;
- } else {
- StrCpyS (FileNameExtension, MAX_FILE_NAME_SIZE, &FileName[Index+1]);
- }
-
- //
- // Copy First file name
- //
- StrnCpyS (FileNameFirst, MAX_FILE_NAME_SIZE, FileName, Index);
- FileNameFirst[Index] = L'\0';
-}
-
-/**
- This routine is called to get all boot options in the order determnined by:
- 1. "OptionBuf"
- 2. "BootOrder"
-
- @param[out] OptionBuf BootList buffer to all boot options returned
- @param[out] OptionCount BootList count of all boot options returned
-
- @retval EFI_SUCCESS There is no error when processing capsule
-
-**/
-EFI_STATUS
-GetBootOptionInOrder (
- OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf,
- OUT UINTN *OptionCount
- )
-{
- EFI_STATUS Status;
- UINTN DataSize;
- UINT16 BootNext;
- CHAR16 BootOptionName[20];
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOrderOptionBuf;
- UINTN BootOrderCount;
- EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry;
- UINTN BootNextCount;
- EFI_BOOT_MANAGER_LOAD_OPTION *TempBuf;
-
- BootOrderOptionBuf = NULL;
- TempBuf = NULL;
- BootNextCount = 0;
- BootOrderCount = 0;
- *OptionBuf = NULL;
- *OptionCount = 0;
-
- //
- // First Get BootOption from "BootNext"
- //
- DataSize = sizeof (BootNext);
- Status = gRT->GetVariable (
- EFI_BOOT_NEXT_VARIABLE_NAME,
- &gEfiGlobalVariableGuid,
- NULL,
- &DataSize,
- (VOID *)&BootNext
- );
- //
- // BootNext variable is a single UINT16
- //
- if (!EFI_ERROR (Status) && (DataSize == sizeof (UINT16))) {
- //
- // Add the boot next boot option
- //
- UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootNext);
- ZeroMem (&BootNextOptionEntry, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
- Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);
-
- if (!EFI_ERROR (Status)) {
- BootNextCount = 1;
- }
- }
-
- //
- // Second get BootOption from "BootOrder"
- //
- BootOrderOptionBuf = EfiBootManagerGetLoadOptions (&BootOrderCount, LoadOptionTypeBoot);
- if ((BootNextCount == 0) && (BootOrderCount == 0)) {
- return EFI_NOT_FOUND;
- }
-
- //
- // At least one BootOption is found
- //
- TempBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (BootNextCount + BootOrderCount));
- if (TempBuf != NULL) {
- if (BootNextCount == 1) {
- CopyMem (TempBuf, &BootNextOptionEntry, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
- }
-
- if (BootOrderCount > 0) {
- CopyMem (TempBuf + BootNextCount, BootOrderOptionBuf, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * BootOrderCount);
- }
-
- *OptionBuf = TempBuf;
- *OptionCount = BootNextCount + BootOrderCount;
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_OUT_OF_RESOURCES;
- }
-
- FreePool (BootOrderOptionBuf);
-
- return Status;
-}
-
-/**
- This routine is called to get boot option by OptionNumber.
-
- @param[in] Number The OptionNumber of boot option
- @param[out] OptionBuf BootList buffer to all boot options returned
-
- @retval EFI_SUCCESS There is no error when getting boot option
-
-**/
-EFI_STATUS
-GetBootOptionByNumber (
- IN UINT16 Number,
- OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf
- )
-{
- EFI_STATUS Status;
- CHAR16 BootOptionName[20];
- EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
-
- UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", Number);
- ZeroMem (&BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
- Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootOption);
-
- if (!EFI_ERROR (Status)) {
- *OptionBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
- if (*OptionBuf != NULL) {
- CopyMem (*OptionBuf, &BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_OUT_OF_RESOURCES;
- }
- }
-
- return Status;
-}
-
-/**
- Get Active EFI System Partition within GPT based on device path.
-
- @param[in] DevicePath Device path to find a active EFI System Partition
- @param[out] FsHandle BootList points to all boot options returned
-
- @retval EFI_SUCCESS Active EFI System Partition is succesfully found
- @retval EFI_NOT_FOUND No Active EFI System Partition is found
-
-**/
-EFI_STATUS
-GetEfiSysPartitionFromDevPath (
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- OUT EFI_HANDLE *FsHandle
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
- HARDDRIVE_DEVICE_PATH *Hd;
- EFI_HANDLE Handle;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
-
- //
- // Check if the device path contains GPT node
- //
- TempDevicePath = DevicePath;
- while (!IsDevicePathEnd (TempDevicePath)) {
- if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
- (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP))
- {
- Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
- if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
- break;
- }
- }
-
- TempDevicePath = NextDevicePathNode (TempDevicePath);
- }
-
- if (!IsDevicePathEnd (TempDevicePath)) {
- //
- // Search for EFI system partition protocol on full device path in Boot Option
- //
- Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
-
- //
- // Search for simple file system on this handler
- //
- if (!EFI_ERROR (Status)) {
- Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
- if (!EFI_ERROR (Status)) {
- *FsHandle = Handle;
- return EFI_SUCCESS;
- }
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- This routine is called to get Simple File System protocol on the first EFI system partition found in
- active boot option. The boot option list is detemined in order by
- 1. "BootNext"
- 2. "BootOrder"
-
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
- device like USB can get enumerated.
- @param[in, out] LoadOptionNumber On input, specify the boot option to get EFI system partition.
- On output, return the OptionNumber of the boot option where EFI
- system partition is got from.
- @param[out] FsFsHandle Simple File System Protocol found on first active EFI system partition
-
- @retval EFI_SUCCESS Simple File System protocol found for EFI system partition
- @retval EFI_NOT_FOUND No Simple File System protocol found for EFI system partition
-
-**/
-EFI_STATUS
-GetEfiSysPartitionFromActiveBootOption (
- IN UINTN MaxRetry,
- IN OUT UINT16 **LoadOptionNumber,
- OUT EFI_HANDLE *FsHandle
- )
-{
- EFI_STATUS Status;
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuf;
- UINTN BootOptionNum;
- UINTN Index;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
- EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
-
- *FsHandle = NULL;
- CurFullPath = NULL;
-
- if (*LoadOptionNumber != NULL) {
- BootOptionNum = 1;
- Status = GetBootOptionByNumber (**LoadOptionNumber, &BootOptionBuf);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "GetBootOptionByIndex Failed %x! No BootOption available for connection\n", Status));
- return Status;
- }
- } else {
- Status = GetBootOptionInOrder (&BootOptionBuf, &BootOptionNum);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "GetBootOptionInOrder Failed %x! No BootOption available for connection\n", Status));
- return Status;
- }
- }
-
- //
- // Search BootOptionList to check if it is an active boot option with EFI system partition
- // 1. Connect device path
- // 2. expend short/plug in devicepath
- // 3. LoadImage
- //
- for (Index = 0; Index < BootOptionNum; Index++) {
- //
- // Get the boot option from the link list
- //
- DevicePath = BootOptionBuf[Index].FilePath;
-
- //
- // Skip inactive or legacy boot options
- //
- if (((BootOptionBuf[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) ||
- (DevicePathType (DevicePath) == BBS_DEVICE_PATH))
- {
- continue;
- }
-
- DEBUG_CODE_BEGIN ();
- CHAR16 *DevicePathStr;
-
- DevicePathStr = ConvertDevicePathToText (DevicePath, TRUE, TRUE);
- if (DevicePathStr != NULL) {
- DEBUG ((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));
- FreePool (DevicePathStr);
- } else {
- DEBUG ((DEBUG_INFO, "DevicePathToStr failed\n"));
- }
-
- DEBUG_CODE_END ();
-
- CurFullPath = NULL;
- //
- // Try every full device Path generated from bootoption
- //
- do {
- PreFullPath = CurFullPath;
- CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath (DevicePath, CurFullPath);
-
- if (PreFullPath != NULL) {
- FreePool (PreFullPath);
- }
-
- if (CurFullPath == NULL) {
- //
- // No Active EFI system partition is found in BootOption device path
- //
- Status = EFI_NOT_FOUND;
- break;
- }
-
- DEBUG_CODE_BEGIN ();
- CHAR16 *DevicePathStr1;
-
- DevicePathStr1 = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
- if (DevicePathStr1 != NULL) {
- DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr1));
- FreePool (DevicePathStr1);
- }
-
- DEBUG_CODE_END ();
-
- //
- // Make sure the boot option device path connected.
- // Only handle first device in boot option. Other optional device paths are described as OSV specific
- // FullDevice could contain extra directory & file info. So don't check connection status here.
- //
- EfiBootManagerConnectDevicePath (CurFullPath, NULL);
- Status = GetEfiSysPartitionFromDevPath (CurFullPath, FsHandle);
-
- //
- // Some relocation device like USB need more time to get enumerated
- //
- while (EFI_ERROR (Status) && MaxRetry > 0) {
- EfiBootManagerConnectDevicePath (CurFullPath, NULL);
-
- //
- // Search for EFI system partition protocol on full device path in Boot Option
- //
- Status = GetEfiSysPartitionFromDevPath (CurFullPath, FsHandle);
- if (!EFI_ERROR (Status)) {
- break;
- }
-
- DEBUG ((DEBUG_ERROR, "GetEfiSysPartitionFromDevPath Loop %x\n", Status));
- //
- // Stall 100ms if connection failed to ensure USB stack is ready
- //
- gBS->Stall (100000);
- MaxRetry--;
- }
- } while (EFI_ERROR (Status));
-
- //
- // Find a qualified Simple File System
- //
- if (!EFI_ERROR (Status)) {
- break;
- }
- }
-
- //
- // Return the OptionNumber of the boot option where EFI system partition is got from
- //
- if (*LoadOptionNumber == NULL) {
- *LoadOptionNumber = AllocateCopyPool (sizeof (UINT16), (UINT16 *)&BootOptionBuf[Index].OptionNumber);
- if (*LoadOptionNumber == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- }
- }
-
- //
- // No qualified EFI system partition found
- //
- if (*FsHandle == NULL) {
- Status = EFI_NOT_FOUND;
- }
-
- DEBUG_CODE_BEGIN ();
- CHAR16 *DevicePathStr2;
-
- if (*FsHandle != NULL) {
- DevicePathStr2 = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
- if (DevicePathStr2 != NULL) {
- DEBUG ((DEBUG_INFO, "Found Active EFI System Partion on %s\n", DevicePathStr2));
- FreePool (DevicePathStr2);
- }
- } else {
- DEBUG ((DEBUG_INFO, "Failed to found Active EFI System Partion\n"));
- }
-
- DEBUG_CODE_END ();
-
- if (CurFullPath != NULL) {
- FreePool (CurFullPath);
- }
-
- //
- // Free BootOption Buffer
- //
- for (Index = 0; Index < BootOptionNum; Index++) {
- if (BootOptionBuf[Index].Description != NULL) {
- FreePool (BootOptionBuf[Index].Description);
- }
-
- if (BootOptionBuf[Index].FilePath != NULL) {
- FreePool (BootOptionBuf[Index].FilePath);
- }
-
- if (BootOptionBuf[Index].OptionalData != NULL) {
- FreePool (BootOptionBuf[Index].OptionalData);
- }
- }
-
- FreePool (BootOptionBuf);
-
- return Status;
-}
-
-/**
- This routine is called to get all file infos with in a given dir & with given file attribute, the file info is listed in
- alphabetical order described in UEFI spec.
-
- @param[in] Dir Directory file handler
- @param[in] FileAttr Attribute of file to be red from directory
- @param[out] FileInfoList File images info list red from directory
- @param[out] FileNum File images number red from directory
-
- @retval EFI_SUCCESS File FileInfo list in the given
-
-**/
-EFI_STATUS
-GetFileInfoListInAlphabetFromDir (
- IN EFI_FILE_HANDLE Dir,
- IN UINT64 FileAttr,
- OUT LIST_ENTRY *FileInfoList,
- OUT UINTN *FileNum
- )
-{
- EFI_STATUS Status;
- FILE_INFO_ENTRY *NewFileInfoEntry;
- FILE_INFO_ENTRY *TempFileInfoEntry;
- EFI_FILE_INFO *FileInfo;
- CHAR16 *NewFileName;
- CHAR16 *ListedFileName;
- CHAR16 *NewFileNameExtension;
- CHAR16 *ListedFileNameExtension;
- CHAR16 *TempNewSubStr;
- CHAR16 *TempListedSubStr;
- LIST_ENTRY *Link;
- BOOLEAN NoFile;
- UINTN FileCount;
- UINTN IndexNew;
- UINTN IndexListed;
- UINTN NewSubStrLen;
- UINTN ListedSubStrLen;
- INTN SubStrCmpResult;
-
- Status = EFI_SUCCESS;
- NewFileName = NULL;
- ListedFileName = NULL;
- NewFileNameExtension = NULL;
- ListedFileNameExtension = NULL;
- TempNewSubStr = NULL;
- TempListedSubStr = NULL;
- FileInfo = NULL;
- NoFile = FALSE;
- FileCount = 0;
-
- InitializeListHead (FileInfoList);
-
- TempNewSubStr = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
- TempListedSubStr = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
-
- if ((TempNewSubStr == NULL) || (TempListedSubStr == NULL)) {
- Status = EFI_OUT_OF_RESOURCES;
- goto EXIT;
- }
-
- for ( Status = FileHandleFindFirstFile (Dir, &FileInfo)
- ; !EFI_ERROR (Status) && !NoFile
- ; Status = FileHandleFindNextFile (Dir, FileInfo, &NoFile)
- )
- {
- if (FileInfo == NULL) {
- goto EXIT;
- }
-
- //
- // Skip file with mismatching File attribute
- //
- if ((FileInfo->Attribute & (FileAttr)) == 0) {
- continue;
- }
-
- NewFileInfoEntry = NULL;
- NewFileInfoEntry = (FILE_INFO_ENTRY *)AllocateZeroPool (sizeof (FILE_INFO_ENTRY));
- if (NewFileInfoEntry == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto EXIT;
- }
-
- NewFileInfoEntry->Signature = FILE_INFO_SIGNATURE;
- NewFileInfoEntry->FileInfo = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo);
- if (NewFileInfoEntry->FileInfo == NULL) {
- FreePool (NewFileInfoEntry);
- Status = EFI_OUT_OF_RESOURCES;
- goto EXIT;
- }
-
- NewFileInfoEntry->FileNameFirstPart = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
- if (NewFileInfoEntry->FileNameFirstPart == NULL) {
- FreePool (NewFileInfoEntry->FileInfo);
- FreePool (NewFileInfoEntry);
- Status = EFI_OUT_OF_RESOURCES;
- goto EXIT;
- }
-
- NewFileInfoEntry->FileNameSecondPart = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
- if (NewFileInfoEntry->FileNameSecondPart == NULL) {
- FreePool (NewFileInfoEntry->FileInfo);
- FreePool (NewFileInfoEntry->FileNameFirstPart);
- FreePool (NewFileInfoEntry);
- Status = EFI_OUT_OF_RESOURCES;
- goto EXIT;
- }
-
- //
- // Splitter the whole New file name into 2 parts between the last period L'.' into NewFileName NewFileExtension
- // If no period in the whole file name. NewFileExtension is set to L'\0'
- //
- NewFileName = NewFileInfoEntry->FileNameFirstPart;
- NewFileNameExtension = NewFileInfoEntry->FileNameSecondPart;
- SplitFileNameExtension (FileInfo->FileName, NewFileName, NewFileNameExtension);
- UpperCaseString (NewFileName);
- UpperCaseString (NewFileNameExtension);
-
- //
- // Insert capsule file in alphabetical ordered list
- //
- for (Link = FileInfoList->ForwardLink; Link != FileInfoList; Link = Link->ForwardLink) {
- //
- // Get the FileInfo from the link list
- //
- TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
- ListedFileName = TempFileInfoEntry->FileNameFirstPart;
- ListedFileNameExtension = TempFileInfoEntry->FileNameSecondPart;
-
- //
- // Follow rule in UEFI spec 8.5.5 to compare file name
- //
- IndexListed = 0;
- IndexNew = 0;
- while (TRUE) {
- //
- // First compare each substrings in NewFileName & ListedFileName between periods
- //
- GetSubStringBeforePeriod (&NewFileName[IndexNew], TempNewSubStr, &NewSubStrLen);
- GetSubStringBeforePeriod (&ListedFileName[IndexListed], TempListedSubStr, &ListedSubStrLen);
- if (NewSubStrLen > ListedSubStrLen) {
- //
- // Substr in NewFileName is longer. Pad tail with SPACE
- //
- PadStrInTail (TempListedSubStr, NewSubStrLen - ListedSubStrLen, L' ');
- } else if (NewSubStrLen < ListedSubStrLen) {
- //
- // Substr in ListedFileName is longer. Pad tail with SPACE
- //
- PadStrInTail (TempNewSubStr, ListedSubStrLen - NewSubStrLen, L' ');
- }
-
- SubStrCmpResult = StrnCmp (TempNewSubStr, TempListedSubStr, MAX_FILE_NAME_LEN);
- if (SubStrCmpResult != 0) {
- break;
- }
-
- //
- // Move to skip this substring
- //
- IndexNew += NewSubStrLen;
- IndexListed += ListedSubStrLen;
- //
- // Reach File First Name end
- //
- if ((NewFileName[IndexNew] == L'\0') || (ListedFileName[IndexListed] == L'\0')) {
- break;
- }
-
- //
- // Skip the period L'.'
- //
- IndexNew++;
- IndexListed++;
- }
-
- if (SubStrCmpResult < 0) {
- //
- // NewFileName is smaller. Find the right place to insert New file
- //
- break;
- } else if (SubStrCmpResult == 0) {
- //
- // 2 cases whole NewFileName is smaller than ListedFileName
- // 1. if NewFileName == ListedFileName. Continue to compare FileNameExtension
- // 2. if NewFileName is shorter than ListedFileName
- //
- if (NewFileName[IndexNew] == L'\0') {
- if ((ListedFileName[IndexListed] != L'\0') || (StrnCmp (NewFileNameExtension, ListedFileNameExtension, MAX_FILE_NAME_LEN) < 0)) {
- break;
- }
- }
- }
-
- //
- // Other case, ListedFileName is smaller. Continue to compare the next file in the list
- //
- }
-
- //
- // If Find an entry in the list whose name is bigger than new FileInfo in alphabet order
- // Insert it before this entry
- // else
- // Insert at the tail of this list (Link = FileInfoList)
- //
- InsertTailList (Link, &NewFileInfoEntry->Link);
-
- FileCount++;
- }
-
- *FileNum = FileCount;
-
-EXIT:
-
- if (TempNewSubStr != NULL) {
- FreePool (TempNewSubStr);
- }
-
- if (TempListedSubStr != NULL) {
- FreePool (TempListedSubStr);
- }
-
- if (EFI_ERROR (Status)) {
- while (!IsListEmpty (FileInfoList)) {
- Link = FileInfoList->ForwardLink;
- RemoveEntryList (Link);
-
- TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
-
- FreePool (TempFileInfoEntry->FileInfo);
- FreePool (TempFileInfoEntry->FileNameFirstPart);
- FreePool (TempFileInfoEntry->FileNameSecondPart);
- FreePool (TempFileInfoEntry);
- }
-
- *FileNum = 0;
- }
-
- return Status;
-}
-
-/**
- This routine is called to get all qualified image from file from an given directory
- in alphabetic order. All the file image is copied to allocated boottime memory.
- Caller should free these memory
-
- @param[in] Dir Directory file handler
- @param[in] FileAttr Attribute of file to be red from directory
- @param[out] FilePtr File images Info buffer red from directory
- @param[out] FileNum File images number red from directory
-
- @retval EFI_SUCCESS Succeed to get all capsules in alphabetic order.
-
-**/
-EFI_STATUS
-GetFileImageInAlphabetFromDir (
- IN EFI_FILE_HANDLE Dir,
- IN UINT64 FileAttr,
- OUT IMAGE_INFO **FilePtr,
- OUT UINTN *FileNum
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- EFI_FILE_HANDLE FileHandle;
- FILE_INFO_ENTRY *FileInfoEntry;
- EFI_FILE_INFO *FileInfo;
- UINTN FileCount;
- IMAGE_INFO *TempFilePtrBuf;
- UINTN Size;
- LIST_ENTRY FileInfoList;
-
- FileHandle = NULL;
- FileCount = 0;
- TempFilePtrBuf = NULL;
- *FilePtr = NULL;
-
- //
- // Get file list in Dir in alphabetical order
- //
- Status = GetFileInfoListInAlphabetFromDir (
- Dir,
- FileAttr,
- &FileInfoList,
- &FileCount
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));
- goto EXIT;
- }
-
- if (FileCount == 0) {
- DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
- Status = EFI_NOT_FOUND;
- goto EXIT;
- }
-
- TempFilePtrBuf = (IMAGE_INFO *)AllocateZeroPool (sizeof (IMAGE_INFO) * FileCount);
- if (TempFilePtrBuf == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto EXIT;
- }
-
- //
- // Read all files from FileInfoList to BS memory
- //
- FileCount = 0;
- for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {
- //
- // Get FileInfo from the link list
- //
- FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
- FileInfo = FileInfoEntry->FileInfo;
-
- Status = Dir->Open (
- Dir,
- &FileHandle,
- FileInfo->FileName,
- EFI_FILE_MODE_READ,
- 0
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- Size = (UINTN)FileInfo->FileSize;
- TempFilePtrBuf[FileCount].ImageAddress = AllocateZeroPool (Size);
- if (TempFilePtrBuf[FileCount].ImageAddress == NULL) {
- DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsule. Stop processing the rest.\n"));
- break;
- }
-
- Status = FileHandle->Read (
- FileHandle,
- &Size,
- TempFilePtrBuf[FileCount].ImageAddress
- );
-
- FileHandle->Close (FileHandle);
-
- //
- // Skip read error file
- //
- if (EFI_ERROR (Status) || (Size != (UINTN)FileInfo->FileSize)) {
- //
- // Remove this error file info accordingly
- // & move Link to BackLink
- //
- Link = RemoveEntryList (Link);
- Link = Link->BackLink;
-
- FreePool (FileInfoEntry->FileInfo);
- FreePool (FileInfoEntry->FileNameFirstPart);
- FreePool (FileInfoEntry->FileNameSecondPart);
- FreePool (FileInfoEntry);
-
- FreePool (TempFilePtrBuf[FileCount].ImageAddress);
- TempFilePtrBuf[FileCount].ImageAddress = NULL;
- TempFilePtrBuf[FileCount].FileInfo = NULL;
-
- continue;
- }
-
- TempFilePtrBuf[FileCount].FileInfo = FileInfo;
- FileCount++;
- }
-
- DEBUG_CODE_BEGIN ();
- for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {
- FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
- FileInfo = FileInfoEntry->FileInfo;
- DEBUG ((DEBUG_INFO, "Successfully read capsule file %s from disk.\n", FileInfo->FileName));
- }
-
- DEBUG_CODE_END ();
-
-EXIT:
-
- *FilePtr = TempFilePtrBuf;
- *FileNum = FileCount;
-
- //
- // FileInfo will be freed by Calller
- //
- while (!IsListEmpty (&FileInfoList)) {
- Link = FileInfoList.ForwardLink;
- RemoveEntryList (Link);
-
- FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
-
- FreePool (FileInfoEntry->FileNameFirstPart);
- FreePool (FileInfoEntry->FileNameSecondPart);
- FreePool (FileInfoEntry);
- }
-
- return Status;
-}
-
-/**
- This routine is called to remove all qualified image from file from an given directory.
-
- @param[in] Dir Directory file handler
- @param[in] FileAttr Attribute of files to be deleted
-
- @retval EFI_SUCCESS Succeed to remove all files from an given directory.
-
-**/
-EFI_STATUS
-RemoveFileFromDir (
- IN EFI_FILE_HANDLE Dir,
- IN UINT64 FileAttr
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Link;
- LIST_ENTRY FileInfoList;
- EFI_FILE_HANDLE FileHandle;
- FILE_INFO_ENTRY *FileInfoEntry;
- EFI_FILE_INFO *FileInfo;
- UINTN FileCount;
-
- FileHandle = NULL;
-
- //
- // Get file list in Dir in alphabetical order
- //
- Status = GetFileInfoListInAlphabetFromDir (
- Dir,
- FileAttr,
- &FileInfoList,
- &FileCount
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));
- goto EXIT;
- }
-
- if (FileCount == 0) {
- DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
- Status = EFI_NOT_FOUND;
- goto EXIT;
- }
-
- //
- // Delete all files with given attribute in Dir
- //
- for (Link = FileInfoList.ForwardLink; Link != &(FileInfoList); Link = Link->ForwardLink) {
- //
- // Get FileInfo from the link list
- //
- FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
- FileInfo = FileInfoEntry->FileInfo;
-
- Status = Dir->Open (
- Dir,
- &FileHandle,
- FileInfo->FileName,
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
- 0
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- Status = FileHandle->Delete (FileHandle);
- }
-
-EXIT:
-
- while (!IsListEmpty (&FileInfoList)) {
- Link = FileInfoList.ForwardLink;
- RemoveEntryList (Link);
-
- FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
-
- FreePool (FileInfoEntry->FileInfo);
- FreePool (FileInfoEntry);
- }
-
- return Status;
-}
-
-/**
- This routine is called to get all caspules from file. The capsule file image is
- copied to BS memory. Caller is responsible to free them.
-
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
- devices like USB can get enumerated.
- @param[out] CapsulePtr Copied Capsule file Image Info buffer
- @param[out] CapsuleNum CapsuleNumber
- @param[out] FsHandle File system handle
- @param[out] LoadOptionNumber OptionNumber of boot option
-
- @retval EFI_SUCCESS Succeed to get all capsules.
-
-**/
-EFI_STATUS
-GetAllCapsuleOnDisk (
- IN UINTN MaxRetry,
- OUT IMAGE_INFO **CapsulePtr,
- OUT UINTN *CapsuleNum,
- OUT EFI_HANDLE *FsHandle,
- OUT UINT16 *LoadOptionNumber
- )
-{
- EFI_STATUS Status;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
- EFI_FILE_HANDLE RootDir;
- EFI_FILE_HANDLE FileDir;
- UINT16 *TempOptionNumber;
-
- TempOptionNumber = NULL;
- *CapsuleNum = 0;
-
- Status = GetEfiSysPartitionFromActiveBootOption (MaxRetry, &TempOptionNumber, FsHandle);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = gBS->HandleProtocol (*FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = Fs->OpenVolume (Fs, &RootDir);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = RootDir->Open (
- RootDir,
- &FileDir,
- EFI_CAPSULE_FILE_DIRECTORY,
- EFI_FILE_MODE_READ,
- 0
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "CodLibGetAllCapsuleOnDisk fail to open RootDir!\n"));
- RootDir->Close (RootDir);
- return Status;
- }
-
- RootDir->Close (RootDir);
-
- //
- // Only Load files with EFI_FILE_SYSTEM or EFI_FILE_ARCHIVE attribute
- // ignore EFI_FILE_READ_ONLY, EFI_FILE_HIDDEN, EFI_FILE_RESERVED, EFI_FILE_DIRECTORY
- //
- Status = GetFileImageInAlphabetFromDir (
- FileDir,
- EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE,
- CapsulePtr,
- CapsuleNum
- );
- DEBUG ((DEBUG_INFO, "GetFileImageInAlphabetFromDir status %x\n", Status));
-
- //
- // Always remove file to avoid deadloop in capsule process
- //
- Status = RemoveFileFromDir (FileDir, EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE);
- DEBUG ((DEBUG_INFO, "RemoveFileFromDir status %x\n", Status));
-
- FileDir->Close (FileDir);
-
- if (LoadOptionNumber != NULL) {
- *LoadOptionNumber = *TempOptionNumber;
- }
-
- return Status;
-}
-
-/**
- Build Gather list for a list of capsule images.
-
- @param[in] CapsuleBuffer An array of pointer to capsule images
- @param[in] CapsuleSize An array of UINTN to capsule images size
- @param[in] CapsuleNum The count of capsule images
- @param[out] BlockDescriptors The block descriptors for the capsule images
-
- @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
-
-**/
-EFI_STATUS
-BuildGatherList (
- IN VOID **CapsuleBuffer,
- IN UINTN *CapsuleSize,
- IN UINTN CapsuleNum,
- OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
- )
-{
- EFI_STATUS Status;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;
- UINTN Index;
-
- BlockDescriptors1 = NULL;
- BlockDescriptorPre = NULL;
- BlockDescriptorsHeader = NULL;
-
- for (Index = 0; Index < CapsuleNum; Index++) {
- //
- // Allocate memory for the descriptors.
- //
- BlockDescriptors1 = AllocateZeroPool (2 * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR));
- if (BlockDescriptors1 == NULL) {
- DEBUG ((DEBUG_ERROR, "BuildGatherList: failed to allocate memory for descriptors\n"));
- Status = EFI_OUT_OF_RESOURCES;
- goto ERREXIT;
- } else {
- DEBUG ((DEBUG_INFO, "BuildGatherList: creating capsule descriptors at 0x%X\n", (UINTN)BlockDescriptors1));
- }
-
- //
- // Record descirptor header
- //
- if (Index == 0) {
- BlockDescriptorsHeader = BlockDescriptors1;
- }
-
- if (BlockDescriptorPre != NULL) {
- BlockDescriptorPre->Union.ContinuationPointer = (UINTN)BlockDescriptors1;
- BlockDescriptorPre->Length = 0;
- }
-
- BlockDescriptors1->Union.DataBlock = (UINTN)CapsuleBuffer[Index];
- BlockDescriptors1->Length = CapsuleSize[Index];
-
- BlockDescriptorPre = BlockDescriptors1 + 1;
- BlockDescriptors1 = NULL;
- }
-
- //
- // Null-terminate.
- //
- if (BlockDescriptorPre != NULL) {
- BlockDescriptorPre->Union.ContinuationPointer = (UINTN)NULL;
- BlockDescriptorPre->Length = 0;
- *BlockDescriptors = BlockDescriptorsHeader;
- }
-
- return EFI_SUCCESS;
-
-ERREXIT:
- if (BlockDescriptors1 != NULL) {
- FreePool (BlockDescriptors1);
- }
-
- return Status;
-}
-
-/**
- This routine is called to check if CapsuleOnDisk flag in OsIndications Variable
- is enabled.
-
- @retval TRUE Flag is enabled
- @retval FALSE Flag is not enabled
-
-**/
-BOOLEAN
-EFIAPI
-CoDCheckCapsuleOnDiskFlag (
- VOID
- )
-{
- EFI_STATUS Status;
- UINT64 OsIndication;
- UINTN DataSize;
-
- //
- // Check File Capsule Delivery Supported Flag in OsIndication variable
- //
- OsIndication = 0;
- DataSize = sizeof (UINT64);
- Status = gRT->GetVariable (
- EFI_OS_INDICATIONS_VARIABLE_NAME,
- &gEfiGlobalVariableGuid,
- NULL,
- &DataSize,
- &OsIndication
- );
- if (!EFI_ERROR (Status) &&
- ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0))
- {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- This routine is called to clear CapsuleOnDisk flags including OsIndications and BootNext variable.
-
- @retval EFI_SUCCESS All Capsule On Disk flags are cleared
-
-**/
-EFI_STATUS
-EFIAPI
-CoDClearCapsuleOnDiskFlag (
- VOID
- )
-{
- EFI_STATUS Status;
- UINT64 OsIndication;
- UINTN DataSize;
-
- //
- // Reset File Capsule Delivery Supported Flag in OsIndication variable
- //
- OsIndication = 0;
- DataSize = sizeof (UINT64);
- Status = gRT->GetVariable (
- EFI_OS_INDICATIONS_VARIABLE_NAME,
- &gEfiGlobalVariableGuid,
- NULL,
- &DataSize,
- &OsIndication
- );
- if (EFI_ERROR (Status) ||
- ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) == 0))
- {
- return Status;
- }
-
- OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
- Status = gRT->SetVariable (
- EFI_OS_INDICATIONS_VARIABLE_NAME,
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
- sizeof (UINT64),
- &OsIndication
- );
- ASSERT (!EFI_ERROR (Status));
-
- //
- // Delete BootNext variable. Capsule Process may reset system, so can't rely on Bds to clear this variable
- //
- Status = gRT->SetVariable (
- EFI_BOOT_NEXT_VARIABLE_NAME,
- &gEfiGlobalVariableGuid,
- 0,
- 0,
- NULL
- );
- ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
-
- return EFI_SUCCESS;
-}
-
-/**
- This routine is called to clear CapsuleOnDisk Relocation Info variable.
- Total Capsule On Disk length is recorded in this variable
-
- @retval EFI_SUCCESS Capsule On Disk flags are cleared
-
-**/
-EFI_STATUS
-CoDClearCapsuleRelocationInfo (
- VOID
- )
-{
- return gRT->SetVariable (
- COD_RELOCATION_INFO_VAR_NAME,
- &gEfiCapsuleVendorGuid,
- 0,
- 0,
- NULL
- );
-}
-
-/**
- Relocate Capsule on Disk from EFI system partition to a platform-specific NV storage device
- with BlockIo protocol. Relocation device path, identified by PcdCodRelocationDevPath, must
- be a full device path.
- Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
- Function will stall 100ms between each retry.
-
- Side Effects:
- Content corruption. Block IO write directly touches low level write. Orignal partitions, file systems
- of the relocation device will be corrupted.
-
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
- devices like USB can get enumerated.
-
- @retval EFI_SUCCESS Capsule on Disk images are sucessfully relocated to the platform-specific device.
-
-**/
-EFI_STATUS
-RelocateCapsuleToDisk (
- UINTN MaxRetry
- )
-{
- EFI_STATUS Status;
- UINTN CapsuleOnDiskNum;
- UINTN Index;
- UINTN DataSize;
- UINT64 TotalImageSize;
- UINT64 TotalImageNameSize;
- IMAGE_INFO *CapsuleOnDiskBuf;
- EFI_HANDLE Handle;
- EFI_HANDLE TempHandle;
- EFI_HANDLE *HandleBuffer;
- UINTN NumberOfHandles;
- EFI_BLOCK_IO_PROTOCOL *BlockIo;
- UINT8 *CapsuleDataBuf;
- UINT8 *CapsulePtr;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
- EFI_FILE_HANDLE RootDir;
- EFI_FILE_HANDLE TempCodFile;
- UINT64 TempCodFileSize;
- EFI_DEVICE_PATH *TempDevicePath;
- BOOLEAN RelocationInfo;
- UINT16 LoadOptionNumber;
- EFI_CAPSULE_HEADER FileNameCapsuleHeader;
-
- RootDir = NULL;
- TempCodFile = NULL;
- HandleBuffer = NULL;
- CapsuleDataBuf = NULL;
- CapsuleOnDiskBuf = NULL;
- NumberOfHandles = 0;
-
- DEBUG ((DEBUG_INFO, "CapsuleOnDisk RelocateCapsule Enter\n"));
-
- //
- // 1. Load all Capsule On Disks in to memory
- //
- Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, &LoadOptionNumber);
- if (EFI_ERROR (Status) || (CapsuleOnDiskNum == 0) || (CapsuleOnDiskBuf == NULL)) {
- DEBUG ((DEBUG_INFO, "RelocateCapsule: GetAllCapsuleOnDisk Status - 0x%x\n", Status));
- return EFI_NOT_FOUND;
- }
-
- //
- // 2. Connect platform special device path as relocation device.
- // If no platform special device path specified or the device path is invalid, use the EFI system partition where
- // stores the capsules as relocation device.
- //
- if (IsDevicePathValid ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), PcdGetSize (PcdCodRelocationDevPath))) {
- Status = EfiBootManagerConnectDevicePath ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), &TempHandle);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "RelocateCapsule: EfiBootManagerConnectDevicePath Status - 0x%x\n", Status));
- goto EXIT;
- }
-
- //
- // Connect all the child handle. Partition & FAT drivers are allowed in this case
- //
- gBS->ConnectController (TempHandle, NULL, NULL, TRUE);
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiSimpleFileSystemProtocolGuid,
- NULL,
- &NumberOfHandles,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "RelocateCapsule: LocateHandleBuffer Status - 0x%x\n", Status));
- goto EXIT;
- }
-
- //
- // Find first Simple File System Handle which can match PcdCodRelocationDevPath
- //
- for (Index = 0; Index < NumberOfHandles; Index++) {
- Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&TempDevicePath);
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- DataSize = GetDevicePathSize ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath)) - sizeof (EFI_DEVICE_PATH);
- if (0 == CompareMem ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), TempDevicePath, DataSize)) {
- Handle = HandleBuffer[Index];
- break;
- }
- }
-
- FreePool (HandleBuffer);
-
- if (Index == NumberOfHandles) {
- DEBUG ((DEBUG_ERROR, "RelocateCapsule: No simple file system protocol found.\n"));
- Status = EFI_NOT_FOUND;
- }
- }
-
- Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
- if (EFI_ERROR (Status) || BlockIo->Media->ReadOnly) {
- DEBUG ((DEBUG_ERROR, "Fail to find Capsule on Disk relocation BlockIo device or device is ReadOnly!\n"));
- goto EXIT;
- }
-
- Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
- if (EFI_ERROR (Status)) {
- goto EXIT;
- }
-
- //
- // Check if device used to relocate Capsule On Disk is big enough
- //
- TotalImageSize = 0;
- TotalImageNameSize = 0;
- for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
- //
- // Overflow check
- //
- if (MAX_ADDRESS - (UINTN)TotalImageSize <= CapsuleOnDiskBuf[Index].FileInfo->FileSize) {
- Status = EFI_INVALID_PARAMETER;
- goto EXIT;
- }
-
- if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName)) {
- Status = EFI_INVALID_PARAMETER;
- goto EXIT;
- }
-
- TotalImageSize += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
- TotalImageNameSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
- DEBUG ((DEBUG_INFO, "RelocateCapsule: %x Size %x\n", CapsuleOnDiskBuf[Index].FileInfo->FileName, CapsuleOnDiskBuf[Index].FileInfo->FileSize));
- }
-
- DEBUG ((DEBUG_INFO, "RelocateCapsule: TotalImageSize %x\n", TotalImageSize));
- DEBUG ((DEBUG_INFO, "RelocateCapsule: TotalImageNameSize %x\n", TotalImageNameSize));
-
- if ((MAX_ADDRESS - (UINTN)TotalImageNameSize <= sizeof (UINT64) * 2) ||
- (MAX_ADDRESS - (UINTN)TotalImageSize <= (UINTN)TotalImageNameSize + sizeof (UINT64) * 2))
- {
- Status = EFI_INVALID_PARAMETER;
- goto EXIT;
- }
-
- TempCodFileSize = sizeof (UINT64) + TotalImageSize + sizeof (EFI_CAPSULE_HEADER) + TotalImageNameSize;
-
- //
- // Check if CapsuleTotalSize. There could be reminder, so use LastBlock number directly
- //
- if (DivU64x32 (TempCodFileSize, BlockIo->Media->BlockSize) > BlockIo->Media->LastBlock) {
- DEBUG ((DEBUG_ERROR, "RelocateCapsule: Relocation device isn't big enough to hold all Capsule on Disk!\n"));
- DEBUG ((DEBUG_ERROR, "TotalImageSize = %x\n", TotalImageSize));
- DEBUG ((DEBUG_ERROR, "TotalImageNameSize = %x\n", TotalImageNameSize));
- DEBUG ((DEBUG_ERROR, "RelocationDev BlockSize = %x LastBlock = %x\n", BlockIo->Media->BlockSize, BlockIo->Media->LastBlock));
- Status = EFI_OUT_OF_RESOURCES;
- goto EXIT;
- }
-
- CapsuleDataBuf = AllocatePool ((UINTN)TempCodFileSize);
- if (CapsuleDataBuf == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto EXIT;
- }
-
- //
- // First UINT64 reserved for total image size, including capsule name capsule.
- //
- *(UINT64 *)CapsuleDataBuf = TotalImageSize + sizeof (EFI_CAPSULE_HEADER) + TotalImageNameSize;
-
- //
- // Line up all the Capsule on Disk and write to relocation disk at one time. It could save some time in disk write
- //
- for (Index = 0, CapsulePtr = CapsuleDataBuf + sizeof (UINT64); Index < CapsuleOnDiskNum; Index++) {
- CopyMem (CapsulePtr, CapsuleOnDiskBuf[Index].ImageAddress, (UINTN)CapsuleOnDiskBuf[Index].FileInfo->FileSize);
- CapsulePtr += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
- }
-
- //
- // Line the capsule header for capsule name capsule.
- //
- CopyGuid (&FileNameCapsuleHeader.CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
- FileNameCapsuleHeader.CapsuleImageSize = (UINT32)TotalImageNameSize + sizeof (EFI_CAPSULE_HEADER);
- FileNameCapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
- FileNameCapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER);
- CopyMem (CapsulePtr, &FileNameCapsuleHeader, FileNameCapsuleHeader.HeaderSize);
- CapsulePtr += FileNameCapsuleHeader.HeaderSize;
-
- //
- // Line up all the Capsule file names.
- //
- for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
- CopyMem (CapsulePtr, CapsuleOnDiskBuf[Index].FileInfo->FileName, StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName));
- CapsulePtr += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
- }
-
- //
- // 5. Flash all Capsules on Disk to TempCoD.tmp under RootDir
- //
- Status = Fs->OpenVolume (Fs, &RootDir);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "RelocateCapsule: OpenVolume error. %x\n", Status));
- goto EXIT;
- }
-
- Status = RootDir->Open (
- RootDir,
- &TempCodFile,
- (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
- 0
- );
- if (!EFI_ERROR (Status)) {
- //
- // Error handling code to prevent malicious code to hold this file to block capsule on disk
- //
- TempCodFile->Delete (TempCodFile);
- }
-
- Status = RootDir->Open (
- RootDir,
- &TempCodFile,
- (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
- 0
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "RelocateCapsule: Open TemCoD.tmp error. %x\n", Status));
- goto EXIT;
- }
-
- //
- // Always write at the begining of TempCap file
- //
- DataSize = (UINTN)TempCodFileSize;
- Status = TempCodFile->Write (
- TempCodFile,
- &DataSize,
- CapsuleDataBuf
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "RelocateCapsule: Write TemCoD.tmp error. %x\n", Status));
- goto EXIT;
- }
-
- if (DataSize != TempCodFileSize) {
- Status = EFI_DEVICE_ERROR;
- goto EXIT;
- }
-
- //
- // Save Capsule On Disk relocation info to "CodRelocationInfo" Var
- // It is used in next reboot by TCB
- //
- RelocationInfo = TRUE;
- Status = gRT->SetVariable (
- COD_RELOCATION_INFO_VAR_NAME,
- &gEfiCapsuleVendorGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
- sizeof (BOOLEAN),
- &RelocationInfo
- );
- //
- // Save the LoadOptionNumber of the boot option, where the capsule is relocated,
- // into "CodRelocationLoadOption" var. It is used in next reboot after capsule is
- // updated out of TCB to remove the TempCoDFile.
- //
- Status = gRT->SetVariable (
- COD_RELOCATION_LOAD_OPTION_VAR_NAME,
- &gEfiCapsuleVendorGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
- sizeof (UINT16),
- &LoadOptionNumber
- );
-
-EXIT:
-
- if (CapsuleDataBuf != NULL) {
- FreePool (CapsuleDataBuf);
- }
-
- if (CapsuleOnDiskBuf != NULL) {
- //
- // Free resources allocated by CodLibGetAllCapsuleOnDisk
- //
- for (Index = 0; Index < CapsuleOnDiskNum; Index++ ) {
- FreePool (CapsuleOnDiskBuf[Index].ImageAddress);
- FreePool (CapsuleOnDiskBuf[Index].FileInfo);
- }
-
- FreePool (CapsuleOnDiskBuf);
- }
-
- if (TempCodFile != NULL) {
- if (EFI_ERROR (Status)) {
- TempCodFile->Delete (TempCodFile);
- } else {
- TempCodFile->Close (TempCodFile);
- }
- }
-
- if (RootDir != NULL) {
- RootDir->Close (RootDir);
- }
-
- return Status;
-}
-
-/**
- For the platforms that support Capsule In Ram, reuse the Capsule In Ram to deliver capsule.
- Relocate Capsule On Disk to memory and call UpdateCapsule().
- Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
- Function will stall 100ms between each retry.
-
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
- devices like USB can get enumerated.
-
- @retval EFI_SUCCESS Deliver capsule through Capsule In Ram successfully.
-
-**/
-EFI_STATUS
-RelocateCapsuleToRam (
- UINTN MaxRetry
- )
-{
- EFI_STATUS Status;
- UINTN CapsuleOnDiskNum;
- IMAGE_INFO *CapsuleOnDiskBuf;
- EFI_HANDLE Handle;
- EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;
- VOID **CapsuleBuffer;
- UINTN *CapsuleSize;
- EFI_CAPSULE_HEADER *FileNameCapsule;
- UINTN Index;
- UINT8 *StringBuf;
- UINTN StringSize;
- UINTN TotalStringSize;
- UINTN CapsulesToProcess;
-
- CapsuleOnDiskBuf = NULL;
- BlockDescriptors = NULL;
- CapsuleBuffer = NULL;
- CapsuleSize = NULL;
- FileNameCapsule = NULL;
- TotalStringSize = 0;
-
- //
- // 1. Load all Capsule On Disks into memory
- //
- Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, NULL);
- if (EFI_ERROR (Status) || (CapsuleOnDiskNum == 0) || (CapsuleOnDiskBuf == NULL)) {
- DEBUG ((DEBUG_ERROR, "GetAllCapsuleOnDisk Status - 0x%x\n", Status));
- return EFI_NOT_FOUND;
- }
-
- //
- // 2. Add a capsule for Capsule file name strings
- //
- CapsuleBuffer = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (VOID *));
- if (CapsuleBuffer == NULL) {
- DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
- return EFI_OUT_OF_RESOURCES;
- }
-
- CapsuleSize = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (UINTN));
- if (CapsuleSize == NULL) {
- DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
- FreePool (CapsuleBuffer);
- return EFI_OUT_OF_RESOURCES;
- }
-
- for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
- CapsuleBuffer[Index] = (VOID *)(UINTN)CapsuleOnDiskBuf[Index].ImageAddress;
- CapsuleSize[Index] = (UINTN)CapsuleOnDiskBuf[Index].FileInfo->FileSize;
- TotalStringSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
- }
-
- // If Persist Across Reset isn't supported, skip the file name strings capsule
- if (!FeaturePcdGet (PcdSupportUpdateCapsuleReset)) {
- CapsulesToProcess = CapsuleOnDiskNum;
- goto BuildGather;
- }
-
- CapsulesToProcess = CapsuleOnDiskNum + 1;
-
- FileNameCapsule = AllocateZeroPool (sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);
- if (FileNameCapsule == NULL) {
- DEBUG ((DEBUG_ERROR, "Fail to allocate memory for name capsule.\n"));
- FreePool (CapsuleBuffer);
- FreePool (CapsuleSize);
- return EFI_OUT_OF_RESOURCES;
- }
-
- FileNameCapsule->CapsuleImageSize = (UINT32)(sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);
- FileNameCapsule->Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
- FileNameCapsule->HeaderSize = sizeof (EFI_CAPSULE_HEADER);
- CopyGuid (&(FileNameCapsule->CapsuleGuid), &gEdkiiCapsuleOnDiskNameGuid);
-
- StringBuf = (UINT8 *)FileNameCapsule + FileNameCapsule->HeaderSize;
- for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
- StringSize = StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
- CopyMem (StringBuf, CapsuleOnDiskBuf[Index].FileInfo->FileName, StringSize);
- StringBuf += StringSize;
- }
-
- CapsuleBuffer[CapsuleOnDiskNum] = FileNameCapsule;
- CapsuleSize[CapsuleOnDiskNum] = TotalStringSize + sizeof (EFI_CAPSULE_HEADER);
-
- //
- // 3. Build Gather list for the capsules
- //
-BuildGather:
- Status = BuildGatherList (CapsuleBuffer, CapsuleSize, CapsulesToProcess, &BlockDescriptors);
- if (EFI_ERROR (Status) || (BlockDescriptors == NULL)) {
- FreePool (CapsuleBuffer);
- FreePool (CapsuleSize);
- if (FileNameCapsule != NULL) {
- FreePool (FileNameCapsule);
- }
-
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // 4. Call UpdateCapsule() service
- //
- Status = gRT->UpdateCapsule (
- (EFI_CAPSULE_HEADER **)CapsuleBuffer,
- CapsulesToProcess,
- (UINTN)BlockDescriptors
- );
-
- return Status;
-}
-
-/**
- Relocate Capsule on Disk from EFI system partition.
-
- Two solution to deliver Capsule On Disk:
- Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On Disk to memory and call UpdateCapsule().
- Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On Disk to a platform-specific NV storage
- device with BlockIo protocol.
-
- Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
- Function will stall 100ms between each retry.
-
- Side Effects:
- Capsule Delivery Supported Flag in OsIndication variable and BootNext variable will be cleared.
- Solution B: Content corruption. Block IO write directly touches low level write. Orignal partitions, file
- systems of the relocation device will be corrupted.
-
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
- devices like USB can get enumerated. Input 0 means no retry.
-
- @retval EFI_SUCCESS Capsule on Disk images are successfully relocated.
-
-**/
-EFI_STATUS
-EFIAPI
-CoDRelocateCapsule (
- UINTN MaxRetry
- )
-{
- if (!PcdGetBool (PcdCapsuleOnDiskSupport)) {
- return EFI_UNSUPPORTED;
- }
-
- //
- // Clear CapsuleOnDisk Flag firstly.
- //
- CoDClearCapsuleOnDiskFlag ();
-
- //
- // If Capsule In Ram is supported, delivery capsules through memory
- //
- if (PcdGetBool (PcdCapsuleInRamSupport)) {
- DEBUG ((DEBUG_INFO, "Capsule In Ram is supported, call gRT->UpdateCapsule().\n"));
- return RelocateCapsuleToRam (MaxRetry);
- } else {
- DEBUG ((DEBUG_INFO, "Reallcoate all Capsule on Disks to %s in RootDir.\n", (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName)));
- return RelocateCapsuleToDisk (MaxRetry);
- }
-}
-
-/**
- Remove the temp file from the root of EFI System Partition.
- Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
- Function will stall 100ms between each retry.
-
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
- devices like USB can get enumerated. Input 0 means no retry.
-
- @retval EFI_SUCCESS Remove the temp file successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-CoDRemoveTempFile (
- UINTN MaxRetry
- )
-{
- EFI_STATUS Status;
- UINTN DataSize;
- UINT16 *LoadOptionNumber;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
- EFI_HANDLE FsHandle;
- EFI_FILE_HANDLE RootDir;
- EFI_FILE_HANDLE TempCodFile;
-
- RootDir = NULL;
- TempCodFile = NULL;
- DataSize = sizeof (UINT16);
-
- LoadOptionNumber = AllocatePool (sizeof (UINT16));
- if (LoadOptionNumber == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Check if capsule files are relocated
- //
- Status = gRT->GetVariable (
- COD_RELOCATION_LOAD_OPTION_VAR_NAME,
- &gEfiCapsuleVendorGuid,
- NULL,
- &DataSize,
- (VOID *)LoadOptionNumber
- );
- if (EFI_ERROR (Status) || (DataSize != sizeof (UINT16))) {
- goto EXIT;
- }
-
- //
- // Get the EFI file system from the boot option where the capsules are relocated
- //
- Status = GetEfiSysPartitionFromActiveBootOption (MaxRetry, &LoadOptionNumber, &FsHandle);
- if (EFI_ERROR (Status)) {
- goto EXIT;
- }
-
- Status = gBS->HandleProtocol (FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
- if (EFI_ERROR (Status)) {
- goto EXIT;
- }
-
- Status = Fs->OpenVolume (Fs, &RootDir);
- if (EFI_ERROR (Status)) {
- goto EXIT;
- }
-
- //
- // Delete the TempCoDFile
- //
- Status = RootDir->Open (
- RootDir,
- &TempCodFile,
- (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
- 0
- );
- if (EFI_ERROR (Status)) {
- goto EXIT;
- }
-
- TempCodFile->Delete (TempCodFile);
-
- //
- // Clear "CoDRelocationLoadOption" variable
- //
- Status = gRT->SetVariable (
- COD_RELOCATION_LOAD_OPTION_VAR_NAME,
- &gEfiCapsuleVendorGuid,
- 0,
- 0,
- NULL
- );
-
-EXIT:
- if (LoadOptionNumber != NULL) {
- FreePool (LoadOptionNumber);
- }
-
- if (RootDir != NULL) {
- RootDir->Close (RootDir);
- }
-
- return Status;
-}
+/** @file
+ The implementation supports Capusle on Disk.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleOnDisk.h"
+
+/**
+ 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.
+
+ This routine assumes the capsule has been validated by IsValidCapsuleHeader(), so
+ capsule memory overflow is not going to happen in this routine.
+
+ @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
+ )
+{
+ UINT8 *CapsuleNamePtr;
+ UINT8 *CapsuleNameBufStart;
+ UINT8 *CapsuleNameBufEnd;
+ UINTN Index;
+ UINTN StringSize;
+ EFI_PHYSICAL_ADDRESS *CapsuleNameBuf;
+
+ if (!IsCapsuleNameCapsule (CapsuleHeader)) {
+ return NULL;
+ }
+
+ //
+ // Total string size must be even.
+ //
+ if (((CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize) & BIT0) != 0) {
+ return NULL;
+ }
+
+ *CapsuleNameNum = 0;
+ Index = 0;
+ CapsuleNameBufStart = (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize;
+
+ //
+ // If strings are not aligned on a 16-bit boundary, reallocate memory for it.
+ //
+ if (((UINTN)CapsuleNameBufStart & BIT0) != 0) {
+ CapsuleNameBufStart = AllocateCopyPool (CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize, CapsuleNameBufStart);
+ if (CapsuleNameBufStart == NULL) {
+ return NULL;
+ }
+ }
+
+ CapsuleNameBufEnd = CapsuleNameBufStart + CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
+
+ CapsuleNamePtr = CapsuleNameBufStart;
+ while (CapsuleNamePtr < CapsuleNameBufEnd) {
+ StringSize = StrnSizeS ((CHAR16 *)CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof (CHAR16));
+ CapsuleNamePtr += StringSize;
+ (*CapsuleNameNum)++;
+ }
+
+ //
+ // Integrity check.
+ //
+ if (CapsuleNamePtr != CapsuleNameBufEnd) {
+ if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {
+ FreePool (CapsuleNameBufStart);
+ }
+
+ return NULL;
+ }
+
+ CapsuleNameBuf = AllocatePool (*CapsuleNameNum * sizeof (EFI_PHYSICAL_ADDRESS));
+ if (CapsuleNameBuf == NULL) {
+ if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {
+ FreePool (CapsuleNameBufStart);
+ }
+
+ return NULL;
+ }
+
+ CapsuleNamePtr = CapsuleNameBufStart;
+ while (CapsuleNamePtr < CapsuleNameBufEnd) {
+ StringSize = StrnSizeS ((CHAR16 *)CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof (CHAR16));
+ CapsuleNameBuf[Index] = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleNamePtr;
+ CapsuleNamePtr += StringSize;
+ Index++;
+ }
+
+ return CapsuleNameBuf;
+}
+
+/**
+ This routine is called to upper case given unicode string.
+
+ @param[in] Str String to upper case
+
+ @retval upper cased string after process
+
+**/
+static
+CHAR16 *
+UpperCaseString (
+ IN CHAR16 *Str
+ )
+{
+ CHAR16 *Cptr;
+
+ for (Cptr = Str; *Cptr != L'\0'; Cptr++) {
+ if ((L'a' <= *Cptr) && (*Cptr <= L'z')) {
+ *Cptr = *Cptr - L'a' + L'A';
+ }
+ }
+
+ return Str;
+}
+
+/**
+ This routine is used to return substring before period '.' or '\0'
+ Caller should respsonsible of substr space allocation & free
+
+ @param[in] Str String to check
+ @param[out] SubStr First part of string before period or '\0'
+ @param[out] SubStrLen Length of first part of string
+
+**/
+static
+VOID
+GetSubStringBeforePeriod (
+ IN CHAR16 *Str,
+ OUT CHAR16 *SubStr,
+ OUT UINTN *SubStrLen
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {
+ SubStr[Index] = Str[Index];
+ }
+
+ SubStr[Index] = L'\0';
+ *SubStrLen = Index;
+}
+
+/**
+ This routine pad the string in tail with input character.
+
+ @param[in] StrBuf Str buffer to be padded, should be enough room for
+ @param[in] PadLen Expected padding length
+ @param[in] Character Character used to pad
+
+**/
+static
+VOID
+PadStrInTail (
+ IN CHAR16 *StrBuf,
+ IN UINTN PadLen,
+ IN CHAR16 Character
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; StrBuf[Index] != L'\0'; Index++) {
+ }
+
+ while (PadLen != 0) {
+ StrBuf[Index] = Character;
+ Index++;
+ PadLen--;
+ }
+
+ StrBuf[Index] = L'\0';
+}
+
+/**
+ This routine find the offset of the last period '.' of string. If No period exists
+ function FileNameExtension is set to L'\0'
+
+ @param[in] FileName File name to split between last period
+ @param[out] FileNameFirst First FileName before last period
+ @param[out] FileNameExtension FileName after last period
+
+**/
+static
+VOID
+SplitFileNameExtension (
+ IN CHAR16 *FileName,
+ OUT CHAR16 *FileNameFirst,
+ OUT CHAR16 *FileNameExtension
+ )
+{
+ UINTN Index;
+ UINTN StringLen;
+
+ StringLen = StrnLenS (FileName, MAX_FILE_NAME_SIZE);
+ for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--) {
+ }
+
+ //
+ // No period exists. No FileName Extension
+ //
+ if ((Index == 0) && (FileName[Index] != L'.')) {
+ FileNameExtension[0] = L'\0';
+ Index = StringLen;
+ } else {
+ StrCpyS (FileNameExtension, MAX_FILE_NAME_SIZE, &FileName[Index+1]);
+ }
+
+ //
+ // Copy First file name
+ //
+ StrnCpyS (FileNameFirst, MAX_FILE_NAME_SIZE, FileName, Index);
+ FileNameFirst[Index] = L'\0';
+}
+
+/**
+ This routine is called to get all boot options in the order determnined by:
+ 1. "OptionBuf"
+ 2. "BootOrder"
+
+ @param[out] OptionBuf BootList buffer to all boot options returned
+ @param[out] OptionCount BootList count of all boot options returned
+
+ @retval EFI_SUCCESS There is no error when processing capsule
+
+**/
+EFI_STATUS
+GetBootOptionInOrder (
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf,
+ OUT UINTN *OptionCount
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ UINT16 BootNext;
+ CHAR16 BootOptionName[20];
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOrderOptionBuf;
+ UINTN BootOrderCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry;
+ UINTN BootNextCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION *TempBuf;
+
+ BootOrderOptionBuf = NULL;
+ TempBuf = NULL;
+ BootNextCount = 0;
+ BootOrderCount = 0;
+ *OptionBuf = NULL;
+ *OptionCount = 0;
+
+ //
+ // First Get BootOption from "BootNext"
+ //
+ DataSize = sizeof (BootNext);
+ Status = gRT->GetVariable (
+ EFI_BOOT_NEXT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ (VOID *)&BootNext
+ );
+ //
+ // BootNext variable is a single UINT16
+ //
+ if (!EFI_ERROR (Status) && (DataSize == sizeof (UINT16))) {
+ //
+ // Add the boot next boot option
+ //
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootNext);
+ ZeroMem (&BootNextOptionEntry, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);
+
+ if (!EFI_ERROR (Status)) {
+ BootNextCount = 1;
+ }
+ }
+
+ //
+ // Second get BootOption from "BootOrder"
+ //
+ BootOrderOptionBuf = EfiBootManagerGetLoadOptions (&BootOrderCount, LoadOptionTypeBoot);
+ if ((BootNextCount == 0) && (BootOrderCount == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // At least one BootOption is found
+ //
+ TempBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (BootNextCount + BootOrderCount));
+ if (TempBuf != NULL) {
+ if (BootNextCount == 1) {
+ CopyMem (TempBuf, &BootNextOptionEntry, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ }
+
+ if (BootOrderCount > 0) {
+ CopyMem (TempBuf + BootNextCount, BootOrderOptionBuf, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * BootOrderCount);
+ }
+
+ *OptionBuf = TempBuf;
+ *OptionCount = BootNextCount + BootOrderCount;
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+
+ FreePool (BootOrderOptionBuf);
+
+ return Status;
+}
+
+/**
+ This routine is called to get boot option by OptionNumber.
+
+ @param[in] Number The OptionNumber of boot option
+ @param[out] OptionBuf BootList buffer to all boot options returned
+
+ @retval EFI_SUCCESS There is no error when getting boot option
+
+**/
+EFI_STATUS
+GetBootOptionByNumber (
+ IN UINT16 Number,
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 BootOptionName[20];
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", Number);
+ ZeroMem (&BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootOption);
+
+ if (!EFI_ERROR (Status)) {
+ *OptionBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ if (*OptionBuf != NULL) {
+ CopyMem (*OptionBuf, &BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Get Active EFI System Partition within GPT based on device path.
+
+ @param[in] DevicePath Device path to find a active EFI System Partition
+ @param[out] FsHandle BootList points to all boot options returned
+
+ @retval EFI_SUCCESS Active EFI System Partition is succesfully found
+ @retval EFI_NOT_FOUND No Active EFI System Partition is found
+
+**/
+EFI_STATUS
+GetEfiSysPartitionFromDevPath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_HANDLE *FsHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ HARDDRIVE_DEVICE_PATH *Hd;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+
+ //
+ // Check if the device path contains GPT node
+ //
+ TempDevicePath = DevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP))
+ {
+ Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
+ if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
+ break;
+ }
+ }
+
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ if (!IsDevicePathEnd (TempDevicePath)) {
+ //
+ // Search for EFI system partition protocol on full device path in Boot Option
+ //
+ Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
+
+ //
+ // Search for simple file system on this handler
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (!EFI_ERROR (Status)) {
+ *FsHandle = Handle;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This routine is called to get Simple File System protocol on the first EFI system partition found in
+ active boot option. The boot option list is detemined in order by
+ 1. "BootNext"
+ 2. "BootOrder"
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ device like USB can get enumerated.
+ @param[in, out] LoadOptionNumber On input, specify the boot option to get EFI system partition.
+ On output, return the OptionNumber of the boot option where EFI
+ system partition is got from.
+ @param[out] FsFsHandle Simple File System Protocol found on first active EFI system partition
+
+ @retval EFI_SUCCESS Simple File System protocol found for EFI system partition
+ @retval EFI_NOT_FOUND No Simple File System protocol found for EFI system partition
+
+**/
+EFI_STATUS
+GetEfiSysPartitionFromActiveBootOption (
+ IN UINTN MaxRetry,
+ IN OUT UINT16 **LoadOptionNumber,
+ OUT EFI_HANDLE *FsHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuf;
+ UINTN BootOptionNum;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
+
+ *FsHandle = NULL;
+ CurFullPath = NULL;
+
+ if (*LoadOptionNumber != NULL) {
+ BootOptionNum = 1;
+ Status = GetBootOptionByNumber (**LoadOptionNumber, &BootOptionBuf);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetBootOptionByIndex Failed %x! No BootOption available for connection\n", Status));
+ return Status;
+ }
+ } else {
+ Status = GetBootOptionInOrder (&BootOptionBuf, &BootOptionNum);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetBootOptionInOrder Failed %x! No BootOption available for connection\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // Search BootOptionList to check if it is an active boot option with EFI system partition
+ // 1. Connect device path
+ // 2. expend short/plug in devicepath
+ // 3. LoadImage
+ //
+ for (Index = 0; Index < BootOptionNum; Index++) {
+ //
+ // Get the boot option from the link list
+ //
+ DevicePath = BootOptionBuf[Index].FilePath;
+
+ //
+ // Skip inactive or legacy boot options
+ //
+ if (((BootOptionBuf[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) ||
+ (DevicePathType (DevicePath) == BBS_DEVICE_PATH))
+ {
+ continue;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ CHAR16 *DevicePathStr;
+
+ DevicePathStr = ConvertDevicePathToText (DevicePath, TRUE, TRUE);
+ if (DevicePathStr != NULL) {
+ DEBUG ((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));
+ FreePool (DevicePathStr);
+ } else {
+ DEBUG ((DEBUG_INFO, "DevicePathToStr failed\n"));
+ }
+
+ DEBUG_CODE_END ();
+
+ CurFullPath = NULL;
+ //
+ // Try every full device Path generated from bootoption
+ //
+ do {
+ PreFullPath = CurFullPath;
+ CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath (DevicePath, CurFullPath);
+
+ if (PreFullPath != NULL) {
+ FreePool (PreFullPath);
+ }
+
+ if (CurFullPath == NULL) {
+ //
+ // No Active EFI system partition is found in BootOption device path
+ //
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ CHAR16 *DevicePathStr1;
+
+ DevicePathStr1 = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
+ if (DevicePathStr1 != NULL) {
+ DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr1));
+ FreePool (DevicePathStr1);
+ }
+
+ DEBUG_CODE_END ();
+
+ //
+ // Make sure the boot option device path connected.
+ // Only handle first device in boot option. Other optional device paths are described as OSV specific
+ // FullDevice could contain extra directory & file info. So don't check connection status here.
+ //
+ EfiBootManagerConnectDevicePath (CurFullPath, NULL);
+ Status = GetEfiSysPartitionFromDevPath (CurFullPath, FsHandle);
+
+ //
+ // Some relocation device like USB need more time to get enumerated
+ //
+ while (EFI_ERROR (Status) && MaxRetry > 0) {
+ EfiBootManagerConnectDevicePath (CurFullPath, NULL);
+
+ //
+ // Search for EFI system partition protocol on full device path in Boot Option
+ //
+ Status = GetEfiSysPartitionFromDevPath (CurFullPath, FsHandle);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+
+ DEBUG ((DEBUG_ERROR, "GetEfiSysPartitionFromDevPath Loop %x\n", Status));
+ //
+ // Stall 100ms if connection failed to ensure USB stack is ready
+ //
+ gBS->Stall (100000);
+ MaxRetry--;
+ }
+ } while (EFI_ERROR (Status));
+
+ //
+ // Find a qualified Simple File System
+ //
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ //
+ // Return the OptionNumber of the boot option where EFI system partition is got from
+ //
+ if (*LoadOptionNumber == NULL) {
+ *LoadOptionNumber = AllocateCopyPool (sizeof (UINT16), (UINT16 *)&BootOptionBuf[Index].OptionNumber);
+ if (*LoadOptionNumber == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // No qualified EFI system partition found
+ //
+ if (*FsHandle == NULL) {
+ Status = EFI_NOT_FOUND;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ CHAR16 *DevicePathStr2;
+
+ if (*FsHandle != NULL) {
+ DevicePathStr2 = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
+ if (DevicePathStr2 != NULL) {
+ DEBUG ((DEBUG_INFO, "Found Active EFI System Partion on %s\n", DevicePathStr2));
+ FreePool (DevicePathStr2);
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "Failed to found Active EFI System Partion\n"));
+ }
+
+ DEBUG_CODE_END ();
+
+ if (CurFullPath != NULL) {
+ FreePool (CurFullPath);
+ }
+
+ //
+ // Free BootOption Buffer
+ //
+ for (Index = 0; Index < BootOptionNum; Index++) {
+ if (BootOptionBuf[Index].Description != NULL) {
+ FreePool (BootOptionBuf[Index].Description);
+ }
+
+ if (BootOptionBuf[Index].FilePath != NULL) {
+ FreePool (BootOptionBuf[Index].FilePath);
+ }
+
+ if (BootOptionBuf[Index].OptionalData != NULL) {
+ FreePool (BootOptionBuf[Index].OptionalData);
+ }
+ }
+
+ FreePool (BootOptionBuf);
+
+ return Status;
+}
+
+/**
+ This routine is called to get all file infos with in a given dir & with given file attribute, the file info is listed in
+ alphabetical order described in UEFI spec.
+
+ @param[in] Dir Directory file handler
+ @param[in] FileAttr Attribute of file to be red from directory
+ @param[out] FileInfoList File images info list red from directory
+ @param[out] FileNum File images number red from directory
+
+ @retval EFI_SUCCESS File FileInfo list in the given
+
+**/
+EFI_STATUS
+GetFileInfoListInAlphabetFromDir (
+ IN EFI_FILE_HANDLE Dir,
+ IN UINT64 FileAttr,
+ OUT LIST_ENTRY *FileInfoList,
+ OUT UINTN *FileNum
+ )
+{
+ EFI_STATUS Status;
+ FILE_INFO_ENTRY *NewFileInfoEntry;
+ FILE_INFO_ENTRY *TempFileInfoEntry;
+ EFI_FILE_INFO *FileInfo;
+ CHAR16 *NewFileName;
+ CHAR16 *ListedFileName;
+ CHAR16 *NewFileNameExtension;
+ CHAR16 *ListedFileNameExtension;
+ CHAR16 *TempNewSubStr;
+ CHAR16 *TempListedSubStr;
+ LIST_ENTRY *Link;
+ BOOLEAN NoFile;
+ UINTN FileCount;
+ UINTN IndexNew;
+ UINTN IndexListed;
+ UINTN NewSubStrLen;
+ UINTN ListedSubStrLen;
+ INTN SubStrCmpResult;
+
+ Status = EFI_SUCCESS;
+ NewFileName = NULL;
+ ListedFileName = NULL;
+ NewFileNameExtension = NULL;
+ ListedFileNameExtension = NULL;
+ TempNewSubStr = NULL;
+ TempListedSubStr = NULL;
+ FileInfo = NULL;
+ NoFile = FALSE;
+ FileCount = 0;
+
+ InitializeListHead (FileInfoList);
+
+ TempNewSubStr = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
+ TempListedSubStr = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
+
+ if ((TempNewSubStr == NULL) || (TempListedSubStr == NULL)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ for ( Status = FileHandleFindFirstFile (Dir, &FileInfo)
+ ; !EFI_ERROR (Status) && !NoFile
+ ; Status = FileHandleFindNextFile (Dir, FileInfo, &NoFile)
+ )
+ {
+ if (FileInfo == NULL) {
+ goto EXIT;
+ }
+
+ //
+ // Skip file with mismatching File attribute
+ //
+ if ((FileInfo->Attribute & (FileAttr)) == 0) {
+ continue;
+ }
+
+ NewFileInfoEntry = NULL;
+ NewFileInfoEntry = (FILE_INFO_ENTRY *)AllocateZeroPool (sizeof (FILE_INFO_ENTRY));
+ if (NewFileInfoEntry == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ NewFileInfoEntry->Signature = FILE_INFO_SIGNATURE;
+ NewFileInfoEntry->FileInfo = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo);
+ if (NewFileInfoEntry->FileInfo == NULL) {
+ FreePool (NewFileInfoEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ NewFileInfoEntry->FileNameFirstPart = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
+ if (NewFileInfoEntry->FileNameFirstPart == NULL) {
+ FreePool (NewFileInfoEntry->FileInfo);
+ FreePool (NewFileInfoEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ NewFileInfoEntry->FileNameSecondPart = (CHAR16 *)AllocateZeroPool (MAX_FILE_NAME_SIZE);
+ if (NewFileInfoEntry->FileNameSecondPart == NULL) {
+ FreePool (NewFileInfoEntry->FileInfo);
+ FreePool (NewFileInfoEntry->FileNameFirstPart);
+ FreePool (NewFileInfoEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Splitter the whole New file name into 2 parts between the last period L'.' into NewFileName NewFileExtension
+ // If no period in the whole file name. NewFileExtension is set to L'\0'
+ //
+ NewFileName = NewFileInfoEntry->FileNameFirstPart;
+ NewFileNameExtension = NewFileInfoEntry->FileNameSecondPart;
+ SplitFileNameExtension (FileInfo->FileName, NewFileName, NewFileNameExtension);
+ UpperCaseString (NewFileName);
+ UpperCaseString (NewFileNameExtension);
+
+ //
+ // Insert capsule file in alphabetical ordered list
+ //
+ for (Link = FileInfoList->ForwardLink; Link != FileInfoList; Link = Link->ForwardLink) {
+ //
+ // Get the FileInfo from the link list
+ //
+ TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+ ListedFileName = TempFileInfoEntry->FileNameFirstPart;
+ ListedFileNameExtension = TempFileInfoEntry->FileNameSecondPart;
+
+ //
+ // Follow rule in UEFI spec 8.5.5 to compare file name
+ //
+ IndexListed = 0;
+ IndexNew = 0;
+ while (TRUE) {
+ //
+ // First compare each substrings in NewFileName & ListedFileName between periods
+ //
+ GetSubStringBeforePeriod (&NewFileName[IndexNew], TempNewSubStr, &NewSubStrLen);
+ GetSubStringBeforePeriod (&ListedFileName[IndexListed], TempListedSubStr, &ListedSubStrLen);
+ if (NewSubStrLen > ListedSubStrLen) {
+ //
+ // Substr in NewFileName is longer. Pad tail with SPACE
+ //
+ PadStrInTail (TempListedSubStr, NewSubStrLen - ListedSubStrLen, L' ');
+ } else if (NewSubStrLen < ListedSubStrLen) {
+ //
+ // Substr in ListedFileName is longer. Pad tail with SPACE
+ //
+ PadStrInTail (TempNewSubStr, ListedSubStrLen - NewSubStrLen, L' ');
+ }
+
+ SubStrCmpResult = StrnCmp (TempNewSubStr, TempListedSubStr, MAX_FILE_NAME_LEN);
+ if (SubStrCmpResult != 0) {
+ break;
+ }
+
+ //
+ // Move to skip this substring
+ //
+ IndexNew += NewSubStrLen;
+ IndexListed += ListedSubStrLen;
+ //
+ // Reach File First Name end
+ //
+ if ((NewFileName[IndexNew] == L'\0') || (ListedFileName[IndexListed] == L'\0')) {
+ break;
+ }
+
+ //
+ // Skip the period L'.'
+ //
+ IndexNew++;
+ IndexListed++;
+ }
+
+ if (SubStrCmpResult < 0) {
+ //
+ // NewFileName is smaller. Find the right place to insert New file
+ //
+ break;
+ } else if (SubStrCmpResult == 0) {
+ //
+ // 2 cases whole NewFileName is smaller than ListedFileName
+ // 1. if NewFileName == ListedFileName. Continue to compare FileNameExtension
+ // 2. if NewFileName is shorter than ListedFileName
+ //
+ if (NewFileName[IndexNew] == L'\0') {
+ if ((ListedFileName[IndexListed] != L'\0') || (StrnCmp (NewFileNameExtension, ListedFileNameExtension, MAX_FILE_NAME_LEN) < 0)) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Other case, ListedFileName is smaller. Continue to compare the next file in the list
+ //
+ }
+
+ //
+ // If Find an entry in the list whose name is bigger than new FileInfo in alphabet order
+ // Insert it before this entry
+ // else
+ // Insert at the tail of this list (Link = FileInfoList)
+ //
+ InsertTailList (Link, &NewFileInfoEntry->Link);
+
+ FileCount++;
+ }
+
+ *FileNum = FileCount;
+
+EXIT:
+
+ if (TempNewSubStr != NULL) {
+ FreePool (TempNewSubStr);
+ }
+
+ if (TempListedSubStr != NULL) {
+ FreePool (TempListedSubStr);
+ }
+
+ if (EFI_ERROR (Status)) {
+ while (!IsListEmpty (FileInfoList)) {
+ Link = FileInfoList->ForwardLink;
+ RemoveEntryList (Link);
+
+ TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+
+ FreePool (TempFileInfoEntry->FileInfo);
+ FreePool (TempFileInfoEntry->FileNameFirstPart);
+ FreePool (TempFileInfoEntry->FileNameSecondPart);
+ FreePool (TempFileInfoEntry);
+ }
+
+ *FileNum = 0;
+ }
+
+ return Status;
+}
+
+/**
+ This routine is called to get all qualified image from file from an given directory
+ in alphabetic order. All the file image is copied to allocated boottime memory.
+ Caller should free these memory
+
+ @param[in] Dir Directory file handler
+ @param[in] FileAttr Attribute of file to be red from directory
+ @param[out] FilePtr File images Info buffer red from directory
+ @param[out] FileNum File images number red from directory
+
+ @retval EFI_SUCCESS Succeed to get all capsules in alphabetic order.
+
+**/
+EFI_STATUS
+GetFileImageInAlphabetFromDir (
+ IN EFI_FILE_HANDLE Dir,
+ IN UINT64 FileAttr,
+ OUT IMAGE_INFO **FilePtr,
+ OUT UINTN *FileNum
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ EFI_FILE_HANDLE FileHandle;
+ FILE_INFO_ENTRY *FileInfoEntry;
+ EFI_FILE_INFO *FileInfo;
+ UINTN FileCount;
+ IMAGE_INFO *TempFilePtrBuf;
+ UINTN Size;
+ LIST_ENTRY FileInfoList;
+
+ FileHandle = NULL;
+ FileCount = 0;
+ TempFilePtrBuf = NULL;
+ *FilePtr = NULL;
+
+ //
+ // Get file list in Dir in alphabetical order
+ //
+ Status = GetFileInfoListInAlphabetFromDir (
+ Dir,
+ FileAttr,
+ &FileInfoList,
+ &FileCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));
+ goto EXIT;
+ }
+
+ if (FileCount == 0) {
+ DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
+ Status = EFI_NOT_FOUND;
+ goto EXIT;
+ }
+
+ TempFilePtrBuf = (IMAGE_INFO *)AllocateZeroPool (sizeof (IMAGE_INFO) * FileCount);
+ if (TempFilePtrBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Read all files from FileInfoList to BS memory
+ //
+ FileCount = 0;
+ for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {
+ //
+ // Get FileInfo from the link list
+ //
+ FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+ FileInfo = FileInfoEntry->FileInfo;
+
+ Status = Dir->Open (
+ Dir,
+ &FileHandle,
+ FileInfo->FileName,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Size = (UINTN)FileInfo->FileSize;
+ TempFilePtrBuf[FileCount].ImageAddress = AllocateZeroPool (Size);
+ if (TempFilePtrBuf[FileCount].ImageAddress == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsule. Stop processing the rest.\n"));
+ break;
+ }
+
+ Status = FileHandle->Read (
+ FileHandle,
+ &Size,
+ TempFilePtrBuf[FileCount].ImageAddress
+ );
+
+ FileHandle->Close (FileHandle);
+
+ //
+ // Skip read error file
+ //
+ if (EFI_ERROR (Status) || (Size != (UINTN)FileInfo->FileSize)) {
+ //
+ // Remove this error file info accordingly
+ // & move Link to BackLink
+ //
+ Link = RemoveEntryList (Link);
+ Link = Link->BackLink;
+
+ FreePool (FileInfoEntry->FileInfo);
+ FreePool (FileInfoEntry->FileNameFirstPart);
+ FreePool (FileInfoEntry->FileNameSecondPart);
+ FreePool (FileInfoEntry);
+
+ FreePool (TempFilePtrBuf[FileCount].ImageAddress);
+ TempFilePtrBuf[FileCount].ImageAddress = NULL;
+ TempFilePtrBuf[FileCount].FileInfo = NULL;
+
+ continue;
+ }
+
+ TempFilePtrBuf[FileCount].FileInfo = FileInfo;
+ FileCount++;
+ }
+
+ DEBUG_CODE_BEGIN ();
+ for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {
+ FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+ FileInfo = FileInfoEntry->FileInfo;
+ DEBUG ((DEBUG_INFO, "Successfully read capsule file %s from disk.\n", FileInfo->FileName));
+ }
+
+ DEBUG_CODE_END ();
+
+EXIT:
+
+ *FilePtr = TempFilePtrBuf;
+ *FileNum = FileCount;
+
+ //
+ // FileInfo will be freed by Calller
+ //
+ while (!IsListEmpty (&FileInfoList)) {
+ Link = FileInfoList.ForwardLink;
+ RemoveEntryList (Link);
+
+ FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+
+ FreePool (FileInfoEntry->FileNameFirstPart);
+ FreePool (FileInfoEntry->FileNameSecondPart);
+ FreePool (FileInfoEntry);
+ }
+
+ return Status;
+}
+
+/**
+ This routine is called to remove all qualified image from file from an given directory.
+
+ @param[in] Dir Directory file handler
+ @param[in] FileAttr Attribute of files to be deleted
+
+ @retval EFI_SUCCESS Succeed to remove all files from an given directory.
+
+**/
+EFI_STATUS
+RemoveFileFromDir (
+ IN EFI_FILE_HANDLE Dir,
+ IN UINT64 FileAttr
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ LIST_ENTRY FileInfoList;
+ EFI_FILE_HANDLE FileHandle;
+ FILE_INFO_ENTRY *FileInfoEntry;
+ EFI_FILE_INFO *FileInfo;
+ UINTN FileCount;
+
+ FileHandle = NULL;
+
+ //
+ // Get file list in Dir in alphabetical order
+ //
+ Status = GetFileInfoListInAlphabetFromDir (
+ Dir,
+ FileAttr,
+ &FileInfoList,
+ &FileCount
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));
+ goto EXIT;
+ }
+
+ if (FileCount == 0) {
+ DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
+ Status = EFI_NOT_FOUND;
+ goto EXIT;
+ }
+
+ //
+ // Delete all files with given attribute in Dir
+ //
+ for (Link = FileInfoList.ForwardLink; Link != &(FileInfoList); Link = Link->ForwardLink) {
+ //
+ // Get FileInfo from the link list
+ //
+ FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+ FileInfo = FileInfoEntry->FileInfo;
+
+ Status = Dir->Open (
+ Dir,
+ &FileHandle,
+ FileInfo->FileName,
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = FileHandle->Delete (FileHandle);
+ }
+
+EXIT:
+
+ while (!IsListEmpty (&FileInfoList)) {
+ Link = FileInfoList.ForwardLink;
+ RemoveEntryList (Link);
+
+ FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);
+
+ FreePool (FileInfoEntry->FileInfo);
+ FreePool (FileInfoEntry);
+ }
+
+ return Status;
+}
+
+/**
+ This routine is called to get all caspules from file. The capsule file image is
+ copied to BS memory. Caller is responsible to free them.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated.
+ @param[out] CapsulePtr Copied Capsule file Image Info buffer
+ @param[out] CapsuleNum CapsuleNumber
+ @param[out] FsHandle File system handle
+ @param[out] LoadOptionNumber OptionNumber of boot option
+
+ @retval EFI_SUCCESS Succeed to get all capsules.
+
+**/
+EFI_STATUS
+GetAllCapsuleOnDisk (
+ IN UINTN MaxRetry,
+ OUT IMAGE_INFO **CapsulePtr,
+ OUT UINTN *CapsuleNum,
+ OUT EFI_HANDLE *FsHandle,
+ OUT UINT16 *LoadOptionNumber
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_FILE_HANDLE RootDir;
+ EFI_FILE_HANDLE FileDir;
+ UINT16 *TempOptionNumber;
+
+ TempOptionNumber = NULL;
+ *CapsuleNum = 0;
+
+ Status = GetEfiSysPartitionFromActiveBootOption (MaxRetry, &TempOptionNumber, FsHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (*FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Fs->OpenVolume (Fs, &RootDir);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = RootDir->Open (
+ RootDir,
+ &FileDir,
+ EFI_CAPSULE_FILE_DIRECTORY,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "CodLibGetAllCapsuleOnDisk fail to open RootDir!\n"));
+ RootDir->Close (RootDir);
+ return Status;
+ }
+
+ RootDir->Close (RootDir);
+
+ //
+ // Only Load files with EFI_FILE_SYSTEM or EFI_FILE_ARCHIVE attribute
+ // ignore EFI_FILE_READ_ONLY, EFI_FILE_HIDDEN, EFI_FILE_RESERVED, EFI_FILE_DIRECTORY
+ //
+ Status = GetFileImageInAlphabetFromDir (
+ FileDir,
+ EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE,
+ CapsulePtr,
+ CapsuleNum
+ );
+ DEBUG ((DEBUG_INFO, "GetFileImageInAlphabetFromDir status %x\n", Status));
+
+ //
+ // Always remove file to avoid deadloop in capsule process
+ //
+ Status = RemoveFileFromDir (FileDir, EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE);
+ DEBUG ((DEBUG_INFO, "RemoveFileFromDir status %x\n", Status));
+
+ FileDir->Close (FileDir);
+
+ if (LoadOptionNumber != NULL) {
+ *LoadOptionNumber = *TempOptionNumber;
+ }
+
+ return Status;
+}
+
+/**
+ Build Gather list for a list of capsule images.
+
+ @param[in] CapsuleBuffer An array of pointer to capsule images
+ @param[in] CapsuleSize An array of UINTN to capsule images size
+ @param[in] CapsuleNum The count of capsule images
+ @param[out] BlockDescriptors The block descriptors for the capsule images
+
+ @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
+
+**/
+EFI_STATUS
+BuildGatherList (
+ IN VOID **CapsuleBuffer,
+ IN UINTN *CapsuleSize,
+ IN UINTN CapsuleNum,
+ OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
+ )
+{
+ EFI_STATUS Status;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;
+ UINTN Index;
+
+ BlockDescriptors1 = NULL;
+ BlockDescriptorPre = NULL;
+ BlockDescriptorsHeader = NULL;
+
+ for (Index = 0; Index < CapsuleNum; Index++) {
+ //
+ // Allocate memory for the descriptors.
+ //
+ BlockDescriptors1 = AllocateZeroPool (2 * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR));
+ if (BlockDescriptors1 == NULL) {
+ DEBUG ((DEBUG_ERROR, "BuildGatherList: failed to allocate memory for descriptors\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ERREXIT;
+ } else {
+ DEBUG ((DEBUG_INFO, "BuildGatherList: creating capsule descriptors at 0x%X\n", (UINTN)BlockDescriptors1));
+ }
+
+ //
+ // Record descirptor header
+ //
+ if (Index == 0) {
+ BlockDescriptorsHeader = BlockDescriptors1;
+ }
+
+ if (BlockDescriptorPre != NULL) {
+ BlockDescriptorPre->Union.ContinuationPointer = (UINTN)BlockDescriptors1;
+ BlockDescriptorPre->Length = 0;
+ }
+
+ BlockDescriptors1->Union.DataBlock = (UINTN)CapsuleBuffer[Index];
+ BlockDescriptors1->Length = CapsuleSize[Index];
+
+ BlockDescriptorPre = BlockDescriptors1 + 1;
+ BlockDescriptors1 = NULL;
+ }
+
+ //
+ // Null-terminate.
+ //
+ if (BlockDescriptorPre != NULL) {
+ BlockDescriptorPre->Union.ContinuationPointer = (UINTN)NULL;
+ BlockDescriptorPre->Length = 0;
+ *BlockDescriptors = BlockDescriptorsHeader;
+ }
+
+ return EFI_SUCCESS;
+
+ERREXIT:
+ if (BlockDescriptors1 != NULL) {
+ FreePool (BlockDescriptors1);
+ }
+
+ return Status;
+}
+
+/**
+ This routine is called to check if CapsuleOnDisk flag in OsIndications Variable
+ is enabled.
+
+ @retval TRUE Flag is enabled
+ @retval FALSE Flag is not enabled
+
+**/
+BOOLEAN
+EFIAPI
+CoDCheckCapsuleOnDiskFlag (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndication;
+ UINTN DataSize;
+
+ //
+ // Check File Capsule Delivery Supported Flag in OsIndication variable
+ //
+ OsIndication = 0;
+ DataSize = sizeof (UINT64);
+ Status = gRT->GetVariable (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndication
+ );
+ if (!EFI_ERROR (Status) &&
+ ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This routine is called to clear CapsuleOnDisk flags including OsIndications and BootNext variable.
+
+ @retval EFI_SUCCESS All Capsule On Disk flags are cleared
+
+**/
+EFI_STATUS
+EFIAPI
+CoDClearCapsuleOnDiskFlag (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndication;
+ UINTN DataSize;
+
+ //
+ // Reset File Capsule Delivery Supported Flag in OsIndication variable
+ //
+ OsIndication = 0;
+ DataSize = sizeof (UINT64);
+ Status = gRT->GetVariable (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndication
+ );
+ if (EFI_ERROR (Status) ||
+ ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) == 0))
+ {
+ return Status;
+ }
+
+ OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
+ Status = gRT->SetVariable (
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT64),
+ &OsIndication
+ );
+ ASSERT (!EFI_ERROR (Status));
+
+ //
+ // Delete BootNext variable. Capsule Process may reset system, so can't rely on Bds to clear this variable
+ //
+ Status = gRT->SetVariable (
+ EFI_BOOT_NEXT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine is called to clear CapsuleOnDisk Relocation Info variable.
+ Total Capsule On Disk length is recorded in this variable
+
+ @retval EFI_SUCCESS Capsule On Disk flags are cleared
+
+**/
+EFI_STATUS
+CoDClearCapsuleRelocationInfo (
+ VOID
+ )
+{
+ return gRT->SetVariable (
+ COD_RELOCATION_INFO_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ 0,
+ 0,
+ NULL
+ );
+}
+
+/**
+ Relocate Capsule on Disk from EFI system partition to a platform-specific NV storage device
+ with BlockIo protocol. Relocation device path, identified by PcdCodRelocationDevPath, must
+ be a full device path.
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ Side Effects:
+ Content corruption. Block IO write directly touches low level write. Orignal partitions, file systems
+ of the relocation device will be corrupted.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated.
+
+ @retval EFI_SUCCESS Capsule on Disk images are sucessfully relocated to the platform-specific device.
+
+**/
+EFI_STATUS
+RelocateCapsuleToDisk (
+ UINTN MaxRetry
+ )
+{
+ EFI_STATUS Status;
+ UINTN CapsuleOnDiskNum;
+ UINTN Index;
+ UINTN DataSize;
+ UINT64 TotalImageSize;
+ UINT64 TotalImageNameSize;
+ IMAGE_INFO *CapsuleOnDiskBuf;
+ EFI_HANDLE Handle;
+ EFI_HANDLE TempHandle;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ UINT8 *CapsuleDataBuf;
+ UINT8 *CapsulePtr;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_FILE_HANDLE RootDir;
+ EFI_FILE_HANDLE TempCodFile;
+ UINT64 TempCodFileSize;
+ EFI_DEVICE_PATH *TempDevicePath;
+ BOOLEAN RelocationInfo;
+ UINT16 LoadOptionNumber;
+ EFI_CAPSULE_HEADER FileNameCapsuleHeader;
+
+ RootDir = NULL;
+ TempCodFile = NULL;
+ HandleBuffer = NULL;
+ CapsuleDataBuf = NULL;
+ CapsuleOnDiskBuf = NULL;
+ NumberOfHandles = 0;
+
+ DEBUG ((DEBUG_INFO, "CapsuleOnDisk RelocateCapsule Enter\n"));
+
+ //
+ // 1. Load all Capsule On Disks in to memory
+ //
+ Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, &LoadOptionNumber);
+ if (EFI_ERROR (Status) || (CapsuleOnDiskNum == 0) || (CapsuleOnDiskBuf == NULL)) {
+ DEBUG ((DEBUG_INFO, "RelocateCapsule: GetAllCapsuleOnDisk Status - 0x%x\n", Status));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // 2. Connect platform special device path as relocation device.
+ // If no platform special device path specified or the device path is invalid, use the EFI system partition where
+ // stores the capsules as relocation device.
+ //
+ if (IsDevicePathValid ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), PcdGetSize (PcdCodRelocationDevPath))) {
+ Status = EfiBootManagerConnectDevicePath ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), &TempHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RelocateCapsule: EfiBootManagerConnectDevicePath Status - 0x%x\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // Connect all the child handle. Partition & FAT drivers are allowed in this case
+ //
+ gBS->ConnectController (TempHandle, NULL, NULL, TRUE);
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RelocateCapsule: LocateHandleBuffer Status - 0x%x\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // Find first Simple File System Handle which can match PcdCodRelocationDevPath
+ //
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&TempDevicePath);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ DataSize = GetDevicePathSize ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath)) - sizeof (EFI_DEVICE_PATH);
+ if (0 == CompareMem ((EFI_DEVICE_PATH *)PcdGetPtr (PcdCodRelocationDevPath), TempDevicePath, DataSize)) {
+ Handle = HandleBuffer[Index];
+ break;
+ }
+ }
+
+ FreePool (HandleBuffer);
+
+ if (Index == NumberOfHandles) {
+ DEBUG ((DEBUG_ERROR, "RelocateCapsule: No simple file system protocol found.\n"));
+ Status = EFI_NOT_FOUND;
+ }
+ }
+
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ if (EFI_ERROR (Status) || BlockIo->Media->ReadOnly) {
+ DEBUG ((DEBUG_ERROR, "Fail to find Capsule on Disk relocation BlockIo device or device is ReadOnly!\n"));
+ goto EXIT;
+ }
+
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Check if device used to relocate Capsule On Disk is big enough
+ //
+ TotalImageSize = 0;
+ TotalImageNameSize = 0;
+ for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
+ //
+ // Overflow check
+ //
+ if (MAX_ADDRESS - (UINTN)TotalImageSize <= CapsuleOnDiskBuf[Index].FileInfo->FileSize) {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ TotalImageSize += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
+ TotalImageNameSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
+ DEBUG ((DEBUG_INFO, "RelocateCapsule: %x Size %x\n", CapsuleOnDiskBuf[Index].FileInfo->FileName, CapsuleOnDiskBuf[Index].FileInfo->FileSize));
+ }
+
+ DEBUG ((DEBUG_INFO, "RelocateCapsule: TotalImageSize %x\n", TotalImageSize));
+ DEBUG ((DEBUG_INFO, "RelocateCapsule: TotalImageNameSize %x\n", TotalImageNameSize));
+
+ if ((MAX_ADDRESS - (UINTN)TotalImageNameSize <= sizeof (UINT64) * 2) ||
+ (MAX_ADDRESS - (UINTN)TotalImageSize <= (UINTN)TotalImageNameSize + sizeof (UINT64) * 2))
+ {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ TempCodFileSize = sizeof (UINT64) + TotalImageSize + sizeof (EFI_CAPSULE_HEADER) + TotalImageNameSize;
+
+ //
+ // Check if CapsuleTotalSize. There could be reminder, so use LastBlock number directly
+ //
+ if (DivU64x32 (TempCodFileSize, BlockIo->Media->BlockSize) > BlockIo->Media->LastBlock) {
+ DEBUG ((DEBUG_ERROR, "RelocateCapsule: Relocation device isn't big enough to hold all Capsule on Disk!\n"));
+ DEBUG ((DEBUG_ERROR, "TotalImageSize = %x\n", TotalImageSize));
+ DEBUG ((DEBUG_ERROR, "TotalImageNameSize = %x\n", TotalImageNameSize));
+ DEBUG ((DEBUG_ERROR, "RelocationDev BlockSize = %x LastBlock = %x\n", BlockIo->Media->BlockSize, BlockIo->Media->LastBlock));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ CapsuleDataBuf = AllocatePool ((UINTN)TempCodFileSize);
+ if (CapsuleDataBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // First UINT64 reserved for total image size, including capsule name capsule.
+ //
+ *(UINT64 *)CapsuleDataBuf = TotalImageSize + sizeof (EFI_CAPSULE_HEADER) + TotalImageNameSize;
+
+ //
+ // Line up all the Capsule on Disk and write to relocation disk at one time. It could save some time in disk write
+ //
+ for (Index = 0, CapsulePtr = CapsuleDataBuf + sizeof (UINT64); Index < CapsuleOnDiskNum; Index++) {
+ CopyMem (CapsulePtr, CapsuleOnDiskBuf[Index].ImageAddress, (UINTN)CapsuleOnDiskBuf[Index].FileInfo->FileSize);
+ CapsulePtr += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
+ }
+
+ //
+ // Line the capsule header for capsule name capsule.
+ //
+ CopyGuid (&FileNameCapsuleHeader.CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
+ FileNameCapsuleHeader.CapsuleImageSize = (UINT32)TotalImageNameSize + sizeof (EFI_CAPSULE_HEADER);
+ FileNameCapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
+ FileNameCapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER);
+ CopyMem (CapsulePtr, &FileNameCapsuleHeader, FileNameCapsuleHeader.HeaderSize);
+ CapsulePtr += FileNameCapsuleHeader.HeaderSize;
+
+ //
+ // Line up all the Capsule file names.
+ //
+ for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
+ CopyMem (CapsulePtr, CapsuleOnDiskBuf[Index].FileInfo->FileName, StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName));
+ CapsulePtr += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
+ }
+
+ //
+ // 5. Flash all Capsules on Disk to TempCoD.tmp under RootDir
+ //
+ Status = Fs->OpenVolume (Fs, &RootDir);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RelocateCapsule: OpenVolume error. %x\n", Status));
+ goto EXIT;
+ }
+
+ Status = RootDir->Open (
+ RootDir,
+ &TempCodFile,
+ (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Error handling code to prevent malicious code to hold this file to block capsule on disk
+ //
+ TempCodFile->Delete (TempCodFile);
+ }
+
+ Status = RootDir->Open (
+ RootDir,
+ &TempCodFile,
+ (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RelocateCapsule: Open TemCoD.tmp error. %x\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // Always write at the begining of TempCap file
+ //
+ DataSize = (UINTN)TempCodFileSize;
+ Status = TempCodFile->Write (
+ TempCodFile,
+ &DataSize,
+ CapsuleDataBuf
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "RelocateCapsule: Write TemCoD.tmp error. %x\n", Status));
+ goto EXIT;
+ }
+
+ if (DataSize != TempCodFileSize) {
+ Status = EFI_DEVICE_ERROR;
+ goto EXIT;
+ }
+
+ //
+ // Save Capsule On Disk relocation info to "CodRelocationInfo" Var
+ // It is used in next reboot by TCB
+ //
+ RelocationInfo = TRUE;
+ Status = gRT->SetVariable (
+ COD_RELOCATION_INFO_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (BOOLEAN),
+ &RelocationInfo
+ );
+ //
+ // Save the LoadOptionNumber of the boot option, where the capsule is relocated,
+ // into "CodRelocationLoadOption" var. It is used in next reboot after capsule is
+ // updated out of TCB to remove the TempCoDFile.
+ //
+ Status = gRT->SetVariable (
+ COD_RELOCATION_LOAD_OPTION_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (UINT16),
+ &LoadOptionNumber
+ );
+
+EXIT:
+
+ if (CapsuleDataBuf != NULL) {
+ FreePool (CapsuleDataBuf);
+ }
+
+ if (CapsuleOnDiskBuf != NULL) {
+ //
+ // Free resources allocated by CodLibGetAllCapsuleOnDisk
+ //
+ for (Index = 0; Index < CapsuleOnDiskNum; Index++ ) {
+ FreePool (CapsuleOnDiskBuf[Index].ImageAddress);
+ FreePool (CapsuleOnDiskBuf[Index].FileInfo);
+ }
+
+ FreePool (CapsuleOnDiskBuf);
+ }
+
+ if (TempCodFile != NULL) {
+ if (EFI_ERROR (Status)) {
+ TempCodFile->Delete (TempCodFile);
+ } else {
+ TempCodFile->Close (TempCodFile);
+ }
+ }
+
+ if (RootDir != NULL) {
+ RootDir->Close (RootDir);
+ }
+
+ return Status;
+}
+
+/**
+ For the platforms that support Capsule In Ram, reuse the Capsule In Ram to deliver capsule.
+ Relocate Capsule On Disk to memory and call UpdateCapsule().
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated.
+
+ @retval EFI_SUCCESS Deliver capsule through Capsule In Ram successfully.
+
+**/
+EFI_STATUS
+RelocateCapsuleToRam (
+ UINTN MaxRetry
+ )
+{
+ EFI_STATUS Status;
+ UINTN CapsuleOnDiskNum;
+ IMAGE_INFO *CapsuleOnDiskBuf;
+ EFI_HANDLE Handle;
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;
+ VOID **CapsuleBuffer;
+ UINTN *CapsuleSize;
+ EFI_CAPSULE_HEADER *FileNameCapsule;
+ UINTN Index;
+ UINT8 *StringBuf;
+ UINTN StringSize;
+ UINTN TotalStringSize;
+ UINTN CapsulesToProcess;
+
+ CapsuleOnDiskBuf = NULL;
+ BlockDescriptors = NULL;
+ CapsuleBuffer = NULL;
+ CapsuleSize = NULL;
+ FileNameCapsule = NULL;
+ TotalStringSize = 0;
+
+ //
+ // 1. Load all Capsule On Disks into memory
+ //
+ Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, NULL);
+ if (EFI_ERROR (Status) || (CapsuleOnDiskNum == 0) || (CapsuleOnDiskBuf == NULL)) {
+ DEBUG ((DEBUG_ERROR, "GetAllCapsuleOnDisk Status - 0x%x\n", Status));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // 2. Add a capsule for Capsule file name strings
+ //
+ CapsuleBuffer = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (VOID *));
+ if (CapsuleBuffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CapsuleSize = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (UINTN));
+ if (CapsuleSize == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
+ FreePool (CapsuleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
+ CapsuleBuffer[Index] = (VOID *)(UINTN)CapsuleOnDiskBuf[Index].ImageAddress;
+ CapsuleSize[Index] = (UINTN)CapsuleOnDiskBuf[Index].FileInfo->FileSize;
+ TotalStringSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
+ }
+
+ // If Persist Across Reset isn't supported, skip the file name strings capsule
+ if (!FeaturePcdGet (PcdSupportUpdateCapsuleReset)) {
+ CapsulesToProcess = CapsuleOnDiskNum;
+ goto BuildGather;
+ }
+
+ CapsulesToProcess = CapsuleOnDiskNum + 1;
+
+ FileNameCapsule = AllocateZeroPool (sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);
+ if (FileNameCapsule == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory for name capsule.\n"));
+ FreePool (CapsuleBuffer);
+ FreePool (CapsuleSize);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileNameCapsule->CapsuleImageSize = (UINT32)(sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);
+ FileNameCapsule->Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
+ FileNameCapsule->HeaderSize = sizeof (EFI_CAPSULE_HEADER);
+ CopyGuid (&(FileNameCapsule->CapsuleGuid), &gEdkiiCapsuleOnDiskNameGuid);
+
+ StringBuf = (UINT8 *)FileNameCapsule + FileNameCapsule->HeaderSize;
+ for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
+ StringSize = StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
+ CopyMem (StringBuf, CapsuleOnDiskBuf[Index].FileInfo->FileName, StringSize);
+ StringBuf += StringSize;
+ }
+
+ CapsuleBuffer[CapsuleOnDiskNum] = FileNameCapsule;
+ CapsuleSize[CapsuleOnDiskNum] = TotalStringSize + sizeof (EFI_CAPSULE_HEADER);
+
+ //
+ // 3. Build Gather list for the capsules
+ //
+BuildGather:
+ Status = BuildGatherList (CapsuleBuffer, CapsuleSize, CapsulesToProcess, &BlockDescriptors);
+ if (EFI_ERROR (Status) || (BlockDescriptors == NULL)) {
+ FreePool (CapsuleBuffer);
+ FreePool (CapsuleSize);
+ if (FileNameCapsule != NULL) {
+ FreePool (FileNameCapsule);
+ }
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // 4. Call UpdateCapsule() service
+ //
+ Status = gRT->UpdateCapsule (
+ (EFI_CAPSULE_HEADER **)CapsuleBuffer,
+ CapsulesToProcess,
+ (UINTN)BlockDescriptors
+ );
+
+ return Status;
+}
+
+/**
+ Relocate Capsule on Disk from EFI system partition.
+
+ Two solution to deliver Capsule On Disk:
+ Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On Disk to memory and call UpdateCapsule().
+ Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On Disk to a platform-specific NV storage
+ device with BlockIo protocol.
+
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ Side Effects:
+ Capsule Delivery Supported Flag in OsIndication variable and BootNext variable will be cleared.
+ Solution B: Content corruption. Block IO write directly touches low level write. Orignal partitions, file
+ systems of the relocation device will be corrupted.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated. Input 0 means no retry.
+
+ @retval EFI_SUCCESS Capsule on Disk images are successfully relocated.
+
+**/
+EFI_STATUS
+EFIAPI
+CoDRelocateCapsule (
+ UINTN MaxRetry
+ )
+{
+ if (!PcdGetBool (PcdCapsuleOnDiskSupport)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Clear CapsuleOnDisk Flag firstly.
+ //
+ CoDClearCapsuleOnDiskFlag ();
+
+ //
+ // If Capsule In Ram is supported, delivery capsules through memory
+ //
+ if (PcdGetBool (PcdCapsuleInRamSupport)) {
+ DEBUG ((DEBUG_INFO, "Capsule In Ram is supported, call gRT->UpdateCapsule().\n"));
+ return RelocateCapsuleToRam (MaxRetry);
+ } else {
+ DEBUG ((DEBUG_INFO, "Reallcoate all Capsule on Disks to %s in RootDir.\n", (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName)));
+ return RelocateCapsuleToDisk (MaxRetry);
+ }
+}
+
+/**
+ Remove the temp file from the root of EFI System Partition.
+ Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.
+ Function will stall 100ms between each retry.
+
+ @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure
+ devices like USB can get enumerated. Input 0 means no retry.
+
+ @retval EFI_SUCCESS Remove the temp file successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+CoDRemoveTempFile (
+ UINTN MaxRetry
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ UINT16 *LoadOptionNumber;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ EFI_HANDLE FsHandle;
+ EFI_FILE_HANDLE RootDir;
+ EFI_FILE_HANDLE TempCodFile;
+
+ RootDir = NULL;
+ TempCodFile = NULL;
+ DataSize = sizeof (UINT16);
+
+ LoadOptionNumber = AllocatePool (sizeof (UINT16));
+ if (LoadOptionNumber == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check if capsule files are relocated
+ //
+ Status = gRT->GetVariable (
+ COD_RELOCATION_LOAD_OPTION_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ NULL,
+ &DataSize,
+ (VOID *)LoadOptionNumber
+ );
+ if (EFI_ERROR (Status) || (DataSize != sizeof (UINT16))) {
+ goto EXIT;
+ }
+
+ //
+ // Get the EFI file system from the boot option where the capsules are relocated
+ //
+ Status = GetEfiSysPartitionFromActiveBootOption (MaxRetry, &LoadOptionNumber, &FsHandle);
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ Status = gBS->HandleProtocol (FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ Status = Fs->OpenVolume (Fs, &RootDir);
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Delete the TempCoDFile
+ //
+ Status = RootDir->Open (
+ RootDir,
+ &TempCodFile,
+ (CHAR16 *)PcdGetPtr (PcdCoDRelocationFileName),
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ TempCodFile->Delete (TempCodFile);
+
+ //
+ // Clear "CoDRelocationLoadOption" variable
+ //
+ Status = gRT->SetVariable (
+ COD_RELOCATION_LOAD_OPTION_VAR_NAME,
+ &gEfiCapsuleVendorGuid,
+ 0,
+ 0,
+ NULL
+ );
+
+EXIT:
+ if (LoadOptionNumber != NULL) {
+ FreePool (LoadOptionNumber);
+ }
+
+ if (RootDir != NULL) {
+ RootDir->Close (RootDir);
+ }
+
+ return Status;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h b/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h
index 39f9596d50..ef52199e9b 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h
@@ -1,75 +1,75 @@
-/** @file
- Defines several datastructures used by Capsule On Disk feature.
- They are mainly used for FAT files.
-
- Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _CAPSULES_ON_DISK_H_
-#define _CAPSULES_ON_DISK_H_
-
-#include <Uefi.h>
-#include <Pi/PiMultiPhase.h>
-
-#include <Library/UefiLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiRuntimeServicesTableLib.h>
-#include <Library/UefiRuntimeLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/FileHandleLib.h>
-#include <Library/CapsuleLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/PrintLib.h>
-#include <Library/UefiBootManagerLib.h>
-
-#include <Protocol/SimpleFileSystem.h>
-#include <Protocol/DiskIo.h>
-#include <Protocol/BlockIo.h>
-
-#include <Guid/CapsuleVendor.h>
-#include <Guid/FileInfo.h>
-#include <Guid/GlobalVariable.h>
-
-//
-// This data structure is the part of FILE_INFO_ENTRY
-//
-#define FILE_INFO_SIGNATURE SIGNATURE_32 ('F', 'L', 'I', 'F')
-
-//
-// LoadOptionNumber of the boot option where the capsules is relocated.
-//
-#define COD_RELOCATION_LOAD_OPTION_VAR_NAME L"CodRelocationLoadOption"
-
-//
-// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)
-//
-#define MAX_FILE_NAME_SIZE 522
-#define MAX_FILE_NAME_LEN (MAX_FILE_NAME_SIZE / sizeof(CHAR16))
-#define MAX_FILE_INFO_LEN (OFFSET_OF(EFI_FILE_INFO, FileName) + MAX_FILE_NAME_LEN)
-
-typedef struct {
- UINTN Signature;
- LIST_ENTRY Link; /// Linked list members.
- EFI_FILE_INFO *FileInfo; /// Pointer to the FileInfo struct for this file or NULL.
- CHAR16 *FileNameFirstPart; /// Text to the left of right-most period in the file name. String is capitialized
- CHAR16 *FileNameSecondPart; /// Text to the right of right-most period in the file name.String is capitialized. Maybe NULL
-} FILE_INFO_ENTRY;
-
-typedef struct {
- //
- // image address.
- //
- VOID *ImageAddress;
- //
- // The file info of the image comes from.
- // if FileInfo == NULL. means image does not come from file
- //
- EFI_FILE_INFO *FileInfo;
-} IMAGE_INFO;
-
-#endif // _CAPSULES_ON_DISK_H_
+/** @file
+ Defines several datastructures used by Capsule On Disk feature.
+ They are mainly used for FAT files.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _CAPSULES_ON_DISK_H_
+#define _CAPSULES_ON_DISK_H_
+
+#include <Uefi.h>
+#include <Pi/PiMultiPhase.h>
+
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootManagerLib.h>
+
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/BlockIo.h>
+
+#include <Guid/CapsuleVendor.h>
+#include <Guid/FileInfo.h>
+#include <Guid/GlobalVariable.h>
+
+//
+// This data structure is the part of FILE_INFO_ENTRY
+//
+#define FILE_INFO_SIGNATURE SIGNATURE_32 ('F', 'L', 'I', 'F')
+
+//
+// LoadOptionNumber of the boot option where the capsules is relocated.
+//
+#define COD_RELOCATION_LOAD_OPTION_VAR_NAME L"CodRelocationLoadOption"
+
+//
+// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)
+//
+#define MAX_FILE_NAME_SIZE 522
+#define MAX_FILE_NAME_LEN (MAX_FILE_NAME_SIZE / sizeof(CHAR16))
+#define MAX_FILE_INFO_LEN (OFFSET_OF(EFI_FILE_INFO, FileName) + MAX_FILE_NAME_LEN)
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link; /// Linked list members.
+ EFI_FILE_INFO *FileInfo; /// Pointer to the FileInfo struct for this file or NULL.
+ CHAR16 *FileNameFirstPart; /// Text to the left of right-most period in the file name. String is capitialized
+ CHAR16 *FileNameSecondPart; /// Text to the right of right-most period in the file name.String is capitialized. Maybe NULL
+} FILE_INFO_ENTRY;
+
+typedef struct {
+ //
+ // image address.
+ //
+ VOID *ImageAddress;
+ //
+ // The file info of the image comes from.
+ // if FileInfo == NULL. means image does not come from file
+ //
+ EFI_FILE_INFO *FileInfo;
+} IMAGE_INFO;
+
+#endif // _CAPSULES_ON_DISK_H_
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
index 2433c76a8c..c17231d8b1 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
@@ -1,1691 +1,1691 @@
-/** @file
- DXE capsule library.
-
- 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.
-
- SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),
- ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted input and
- performs basic validation.
-
- Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-
-#include <IndustryStandard/WindowsUxCapsule.h>
-
-#include <Guid/FmpCapsule.h>
-#include <Guid/SystemResourceTable.h>
-#include <Guid/EventGroup.h>
-
-#include <Library/BaseLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/DxeServicesTableLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiRuntimeServicesTableLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/CapsuleLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/UefiLib.h>
-#include <Library/BmpSupportLib.h>
-
-#include <Protocol/GraphicsOutput.h>
-#include <Protocol/EsrtManagement.h>
-#include <Protocol/FirmwareManagement.h>
-#include <Protocol/FirmwareManagementProgress.h>
-#include <Protocol/DevicePath.h>
-
-EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL;
-
-BOOLEAN mDxeCapsuleLibEndOfDxe = FALSE;
-EFI_EVENT mDxeCapsuleLibEndOfDxeEvent = NULL;
-
-EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *mFmpProgress = NULL;
-
-/**
- Initialize capsule related variables.
-**/
-VOID
-InitCapsuleVariable (
- VOID
- );
-
-/**
- Record capsule status variable.
-
- @param[in] CapsuleHeader The capsule image header
- @param[in] CapsuleStatus The capsule process stauts
-
- @retval EFI_SUCCESS The capsule status variable is recorded.
- @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
-**/
-EFI_STATUS
-RecordCapsuleStatusVariable (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN EFI_STATUS CapsuleStatus
- );
-
-/**
- Record FMP capsule status variable.
-
- @param[in] CapsuleHeader The capsule image header
- @param[in] CapsuleStatus The capsule process stauts
- @param[in] PayloadIndex FMP payload index
- @param[in] ImageHeader FMP image header
- @param[in] FmpDevicePath DevicePath associated with the FMP producer
- @param[in] CapFileName Capsule file name
-
- @retval EFI_SUCCESS The capsule status variable is recorded.
- @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
-**/
-EFI_STATUS
-RecordFmpCapsuleStatusVariable (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN EFI_STATUS CapsuleStatus,
- IN UINTN PayloadIndex,
- IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
- IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL,
- IN CHAR16 *CapFileName 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
- );
-
-/**
- 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
- )
-{
- return CompareGuid (&CapsuleHeader->CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
-}
-
-/**
- Return if this CapsuleGuid is a FMP capsule GUID or not.
-
- @param[in] CapsuleGuid A pointer to EFI_GUID
-
- @retval TRUE It is a FMP capsule GUID.
- @retval FALSE It is not a FMP capsule GUID.
-**/
-BOOLEAN
-IsFmpCapsuleGuid (
- IN EFI_GUID *CapsuleGuid
- )
-{
- if (CompareGuid (&gEfiFmpCapsuleGuid, CapsuleGuid)) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Validate if it is valid capsule header
-
- Caution: This function may receive untrusted input.
-
- 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
- )
-{
- if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
- return FALSE;
- }
-
- if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- 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
- )
-{
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
- UINT8 *EndOfCapsule;
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
- UINT8 *EndOfPayload;
- UINT64 *ItemOffsetList;
- UINT32 ItemNum;
- UINTN Index;
- UINTN FmpCapsuleSize;
- UINTN FmpCapsuleHeaderSize;
- UINT64 FmpImageSize;
- UINTN FmpImageHeaderSize;
-
- if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
- return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);
- }
-
- if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
- DEBUG ((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
- return EFI_INVALID_PARAMETER;
- }
-
- FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
- EndOfCapsule = (UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize;
- FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
-
- if (FmpCapsuleSize < sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
- DEBUG ((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
- return EFI_INVALID_PARAMETER;
- }
-
- // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
- if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
- DEBUG ((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
- return EFI_INVALID_PARAMETER;
- }
-
- ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
-
- // No overflow
- ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
-
- if ((FmpCapsuleSize - sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof (UINT64) < ItemNum) {
- DEBUG ((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
- return EFI_INVALID_PARAMETER;
- }
-
- FmpCapsuleHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof (UINT64)*ItemNum;
-
- // Check ItemOffsetList
- for (Index = 0; Index < ItemNum; Index++) {
- if (ItemOffsetList[Index] >= FmpCapsuleSize) {
- DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
- return EFI_INVALID_PARAMETER;
- }
-
- if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
- DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // All the address in ItemOffsetList must be stored in ascending order
- //
- if (Index > 0) {
- if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
- DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index - 1, ItemOffsetList[Index - 1]));
- return EFI_INVALID_PARAMETER;
- }
- }
- }
-
- // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
- for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
- ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
- if (Index == ItemNum - 1) {
- EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
- } else {
- EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
- }
-
- FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
-
- FmpImageHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
- if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
- (ImageHeader->Version < 1))
- {
- DEBUG ((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
- return EFI_INVALID_PARAMETER;
- }
-
- if (ImageHeader->Version == 1) {
- FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
- } else if (ImageHeader->Version == 2) {
- FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
- }
-
- if (FmpImageSize < FmpImageHeaderSize) {
- DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) < FmpImageHeaderSize(0x%x)\n", FmpImageSize, FmpImageHeaderSize));
- return EFI_INVALID_PARAMETER;
- }
-
- // No overflow
- if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
- DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
- return EFI_INVALID_PARAMETER;
- }
- }
-
- if (ItemNum == 0) {
- //
- // No driver & payload element in FMP
- //
- EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
- if (EndOfPayload != EndOfCapsule) {
- DEBUG ((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
- return EFI_INVALID_PARAMETER;
- }
-
- return EFI_UNSUPPORTED;
- }
-
- if (EmbeddedDriverCount != NULL) {
- *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Those capsules supported by the firmwares.
-
- Caution: This function may receive untrusted input.
-
- @param[in] CapsuleHeader Points to a capsule header.
-
- @retval EFI_SUCESS Input capsule is supported by firmware.
- @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
-**/
-EFI_STATUS
-DisplayCapsuleImage (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
- )
-{
- DISPLAY_DISPLAY_PAYLOAD *ImagePayload;
- UINTN PayloadSize;
- EFI_STATUS Status;
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
- UINTN BltSize;
- UINTN Height;
- UINTN Width;
- EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
-
- //
- // UX capsule doesn't have extended header entries.
- //
- if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {
- return EFI_UNSUPPORTED;
- }
-
- ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize);
- //
- // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().
- //
- PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
-
- //
- // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.
- // Further size check is performed by the logic translating BMP to GOP BLT.
- //
- if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (ImagePayload->Version != 1) {
- return EFI_UNSUPPORTED;
- }
-
- if (CalculateCheckSum8 ((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {
- return EFI_UNSUPPORTED;
- }
-
- //
- // Only Support Bitmap by now
- //
- if (ImagePayload->ImageType != 0) {
- return EFI_UNSUPPORTED;
- }
-
- //
- // Try to open GOP
- //
- Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
- if (EFI_ERROR (Status)) {
- Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);
- if (EFI_ERROR (Status)) {
- return EFI_UNSUPPORTED;
- }
- }
-
- if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {
- return EFI_UNSUPPORTED;
- }
-
- Blt = NULL;
- Width = 0;
- Height = 0;
- Status = TranslateBmpToGopBlt (
- ImagePayload + 1,
- PayloadSize - sizeof (DISPLAY_DISPLAY_PAYLOAD),
- &Blt,
- &BltSize,
- &Height,
- &Width
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = GraphicsOutput->Blt (
- GraphicsOutput,
- Blt,
- EfiBltBufferToVideo,
- 0,
- 0,
- (UINTN)ImagePayload->OffsetX,
- (UINTN)ImagePayload->OffsetY,
- Width,
- Height,
- Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
- );
-
- FreePool (Blt);
-
- return Status;
-}
-
-/**
- Dump FMP information.
-
- @param[in] ImageInfoSize The size of ImageInfo, in bytes.
- @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
- @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
- @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
- @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
- @param[in] PackageVersion The version of package.
- @param[in] PackageVersionName The version name of package.
-**/
-VOID
-DumpFmpImageInfo (
- IN UINTN ImageInfoSize,
- IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
- IN UINT32 DescriptorVersion,
- IN UINT8 DescriptorCount,
- IN UINTN DescriptorSize,
- IN UINT32 PackageVersion,
- IN CHAR16 *PackageVersionName
- )
-{
- EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;
- UINTN Index;
-
- DEBUG ((DEBUG_VERBOSE, " DescriptorVersion - 0x%x\n", DescriptorVersion));
- DEBUG ((DEBUG_VERBOSE, " DescriptorCount - 0x%x\n", DescriptorCount));
- DEBUG ((DEBUG_VERBOSE, " DescriptorSize - 0x%x\n", DescriptorSize));
- DEBUG ((DEBUG_VERBOSE, " PackageVersion - 0x%x\n", PackageVersion));
- DEBUG ((DEBUG_VERBOSE, " PackageVersionName - %s\n\n", PackageVersionName));
- CurrentImageInfo = ImageInfo;
- for (Index = 0; Index < DescriptorCount; Index++) {
- DEBUG ((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));
- DEBUG ((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex));
- DEBUG ((DEBUG_VERBOSE, " ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId));
- DEBUG ((DEBUG_VERBOSE, " ImageId - 0x%lx\n", CurrentImageInfo->ImageId));
- DEBUG ((DEBUG_VERBOSE, " ImageIdName - %s\n", CurrentImageInfo->ImageIdName));
- DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", CurrentImageInfo->Version));
- DEBUG ((DEBUG_VERBOSE, " VersionName - %s\n", CurrentImageInfo->VersionName));
- DEBUG ((DEBUG_VERBOSE, " Size - 0x%x\n", CurrentImageInfo->Size));
- DEBUG ((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported));
- DEBUG ((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting));
- DEBUG ((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities));
- if (DescriptorVersion > 1) {
- DEBUG ((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));
- if (DescriptorVersion > 2) {
- DEBUG ((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion));
- DEBUG ((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", CurrentImageInfo->LastAttemptStatus));
- DEBUG ((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance));
- }
- }
-
- //
- // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
- //
- CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);
- }
-}
-
-/**
- Dump a non-nested FMP capsule.
-
- @param[in] CapsuleHeader A pointer to CapsuleHeader
-**/
-VOID
-DumpFmpCapsule (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
- )
-{
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
- UINTN Index;
- UINT64 *ItemOffsetList;
-
- FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
-
- DEBUG ((DEBUG_VERBOSE, "FmpCapsule:\n"));
- DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", FmpCapsuleHeader->Version));
- DEBUG ((DEBUG_VERBOSE, " EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));
- DEBUG ((DEBUG_VERBOSE, " PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));
-
- ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
- for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
- DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
- }
-
- for ( ; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {
- DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
- ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
-
- DEBUG ((DEBUG_VERBOSE, " ImageHeader:\n"));
- DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", ImageHeader->Version));
- DEBUG ((DEBUG_VERBOSE, " UpdateImageTypeId - %g\n", &ImageHeader->UpdateImageTypeId));
- DEBUG ((DEBUG_VERBOSE, " UpdateImageIndex - 0x%x\n", ImageHeader->UpdateImageIndex));
- DEBUG ((DEBUG_VERBOSE, " UpdateImageSize - 0x%x\n", ImageHeader->UpdateImageSize));
- DEBUG ((DEBUG_VERBOSE, " UpdateVendorCodeSize - 0x%x\n", ImageHeader->UpdateVendorCodeSize));
- if (ImageHeader->Version >= 2) {
- DEBUG ((DEBUG_VERBOSE, " UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));
- if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
- DEBUG ((DEBUG_VERBOSE, " ImageCapsuleSupport - 0x%lx\n", ImageHeader->ImageCapsuleSupport));
- }
- }
- }
-}
-
-/**
- Dump all FMP information.
-**/
-VOID
-DumpAllFmpInfo (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE *HandleBuffer;
- UINTN NumberOfHandles;
- EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
- UINTN Index;
- UINTN ImageInfoSize;
- EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
- UINT32 FmpImageInfoDescriptorVer;
- UINT8 FmpImageInfoCount;
- UINTN DescriptorSize;
- UINT32 PackageVersion;
- CHAR16 *PackageVersionName;
-
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiFirmwareManagementProtocolGuid,
- NULL,
- &NumberOfHandles,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- return;
- }
-
- for (Index = 0; Index < NumberOfHandles; Index++) {
- Status = gBS->HandleProtocol (
- HandleBuffer[Index],
- &gEfiFirmwareManagementProtocolGuid,
- (VOID **)&Fmp
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- ImageInfoSize = 0;
- Status = Fmp->GetImageInfo (
- Fmp,
- &ImageInfoSize,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
- );
- if (Status != EFI_BUFFER_TOO_SMALL) {
- continue;
- }
-
- FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
- if (FmpImageInfoBuf == NULL) {
- continue;
- }
-
- PackageVersionName = NULL;
- Status = Fmp->GetImageInfo (
- Fmp,
- &ImageInfoSize, // ImageInfoSize
- FmpImageInfoBuf, // ImageInfo
- &FmpImageInfoDescriptorVer, // DescriptorVersion
- &FmpImageInfoCount, // DescriptorCount
- &DescriptorSize, // DescriptorSize
- &PackageVersion, // PackageVersion
- &PackageVersionName // PackageVersionName
- );
- if (EFI_ERROR (Status)) {
- FreePool (FmpImageInfoBuf);
- continue;
- }
-
- DEBUG ((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));
- DumpFmpImageInfo (
- ImageInfoSize, // ImageInfoSize
- FmpImageInfoBuf, // ImageInfo
- FmpImageInfoDescriptorVer, // DescriptorVersion
- FmpImageInfoCount, // DescriptorCount
- DescriptorSize, // DescriptorSize
- PackageVersion, // PackageVersion
- PackageVersionName // PackageVersionName
- );
-
- if (PackageVersionName != NULL) {
- FreePool (PackageVersionName);
- }
-
- FreePool (FmpImageInfoBuf);
- }
-
- FreePool (HandleBuffer);
-
- return;
-}
-
-/**
- Get FMP handle by ImageTypeId and HardwareInstance.
-
- @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update.
- @param[in] UpdateHardwareInstance The HardwareInstance to target with this update.
- @param[out] NoHandles The number of handles returned in HandleBuf.
- @param[out] HandleBuf A pointer to the buffer to return the requested array of handles.
- @param[out] ResetRequiredBuf A pointer to the buffer to return reset required flag for
- the requested array of handles.
-
- @retval EFI_SUCCESS The array of handles and their reset required flag were returned in
- HandleBuf and ResetRequiredBuf, and the number of handles in HandleBuf
- was returned in NoHandles.
- @retval EFI_NOT_FOUND No handles match the search.
- @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
-**/
-EFI_STATUS
-GetFmpHandleBufferByType (
- IN EFI_GUID *UpdateImageTypeId,
- IN UINT64 UpdateHardwareInstance,
- OUT UINTN *NoHandles OPTIONAL,
- OUT EFI_HANDLE **HandleBuf OPTIONAL,
- OUT BOOLEAN **ResetRequiredBuf OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE *HandleBuffer;
- UINTN NumberOfHandles;
- EFI_HANDLE *MatchedHandleBuffer;
- BOOLEAN *MatchedResetRequiredBuffer;
- UINTN MatchedNumberOfHandles;
- EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
- UINTN Index;
- UINTN ImageInfoSize;
- EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
- UINT32 FmpImageInfoDescriptorVer;
- UINT8 FmpImageInfoCount;
- UINTN DescriptorSize;
- UINT32 PackageVersion;
- CHAR16 *PackageVersionName;
- UINTN Index2;
- EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
-
- if (NoHandles != NULL) {
- *NoHandles = 0;
- }
-
- if (HandleBuf != NULL) {
- *HandleBuf = NULL;
- }
-
- if (ResetRequiredBuf != NULL) {
- *ResetRequiredBuf = NULL;
- }
-
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiFirmwareManagementProtocolGuid,
- NULL,
- &NumberOfHandles,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- MatchedNumberOfHandles = 0;
-
- MatchedHandleBuffer = NULL;
- if (HandleBuf != NULL) {
- MatchedHandleBuffer = AllocateZeroPool (sizeof (EFI_HANDLE) * NumberOfHandles);
- if (MatchedHandleBuffer == NULL) {
- FreePool (HandleBuffer);
- return EFI_OUT_OF_RESOURCES;
- }
- }
-
- MatchedResetRequiredBuffer = NULL;
- if (ResetRequiredBuf != NULL) {
- MatchedResetRequiredBuffer = AllocateZeroPool (sizeof (BOOLEAN) * NumberOfHandles);
- if (MatchedResetRequiredBuffer == NULL) {
- if (MatchedHandleBuffer != NULL) {
- FreePool (MatchedHandleBuffer);
- }
-
- FreePool (HandleBuffer);
- return EFI_OUT_OF_RESOURCES;
- }
- }
-
- for (Index = 0; Index < NumberOfHandles; Index++) {
- Status = gBS->HandleProtocol (
- HandleBuffer[Index],
- &gEfiFirmwareManagementProtocolGuid,
- (VOID **)&Fmp
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- ImageInfoSize = 0;
- Status = Fmp->GetImageInfo (
- Fmp,
- &ImageInfoSize,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
- );
- if (Status != EFI_BUFFER_TOO_SMALL) {
- continue;
- }
-
- FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
- if (FmpImageInfoBuf == NULL) {
- continue;
- }
-
- PackageVersionName = NULL;
- Status = Fmp->GetImageInfo (
- Fmp,
- &ImageInfoSize, // ImageInfoSize
- FmpImageInfoBuf, // ImageInfo
- &FmpImageInfoDescriptorVer, // DescriptorVersion
- &FmpImageInfoCount, // DescriptorCount
- &DescriptorSize, // DescriptorSize
- &PackageVersion, // PackageVersion
- &PackageVersionName // PackageVersionName
- );
- if (EFI_ERROR (Status)) {
- FreePool (FmpImageInfoBuf);
- continue;
- }
-
- if (PackageVersionName != NULL) {
- FreePool (PackageVersionName);
- }
-
- TempFmpImageInfo = FmpImageInfoBuf;
- for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
- //
- // Check if this FMP instance matches
- //
- if (CompareGuid (UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {
- if ((UpdateHardwareInstance == 0) ||
- ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&
- (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance)))
- {
- if (MatchedHandleBuffer != NULL) {
- MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];
- }
-
- if (MatchedResetRequiredBuffer != NULL) {
- MatchedResetRequiredBuffer[MatchedNumberOfHandles] = (((TempFmpImageInfo->AttributesSupported &
- IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) &&
- ((TempFmpImageInfo->AttributesSetting &
- IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0));
- }
-
- MatchedNumberOfHandles++;
- break;
- }
- }
-
- TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
- }
-
- FreePool (FmpImageInfoBuf);
- }
-
- FreePool (HandleBuffer);
-
- if (MatchedNumberOfHandles == 0) {
- return EFI_NOT_FOUND;
- }
-
- if (NoHandles != NULL) {
- *NoHandles = MatchedNumberOfHandles;
- }
-
- if (HandleBuf != NULL) {
- *HandleBuf = MatchedHandleBuffer;
- }
-
- if (ResetRequiredBuf != NULL) {
- *ResetRequiredBuf = MatchedResetRequiredBuffer;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Return FmpImageInfoDescriptorVer by an FMP handle.
-
- @param[in] Handle A FMP handle.
-
- @return FmpImageInfoDescriptorVer associated with the FMP.
-**/
-UINT32
-GetFmpImageInfoDescriptorVer (
- IN EFI_HANDLE Handle
- )
-{
- EFI_STATUS Status;
- EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
- UINTN ImageInfoSize;
- EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
- UINT32 FmpImageInfoDescriptorVer;
- UINT8 FmpImageInfoCount;
- UINTN DescriptorSize;
- UINT32 PackageVersion;
- CHAR16 *PackageVersionName;
-
- Status = gBS->HandleProtocol (
- Handle,
- &gEfiFirmwareManagementProtocolGuid,
- (VOID **)&Fmp
- );
- if (EFI_ERROR (Status)) {
- return 0;
- }
-
- ImageInfoSize = 0;
- Status = Fmp->GetImageInfo (
- Fmp,
- &ImageInfoSize,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
- );
- if (Status != EFI_BUFFER_TOO_SMALL) {
- return 0;
- }
-
- FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
- if (FmpImageInfoBuf == NULL) {
- return 0;
- }
-
- PackageVersionName = NULL;
- Status = Fmp->GetImageInfo (
- Fmp,
- &ImageInfoSize, // ImageInfoSize
- FmpImageInfoBuf, // ImageInfo
- &FmpImageInfoDescriptorVer, // DescriptorVersion
- &FmpImageInfoCount, // DescriptorCount
- &DescriptorSize, // DescriptorSize
- &PackageVersion, // PackageVersion
- &PackageVersionName // PackageVersionName
- );
- if (EFI_ERROR (Status)) {
- FreePool (FmpImageInfoBuf);
- return 0;
- }
-
- return FmpImageInfoDescriptorVer;
-}
-
-/**
- Set FMP image data.
-
- @param[in] Handle A FMP handle.
- @param[in] ImageHeader The payload image header.
- @param[in] PayloadIndex The index of the payload.
-
- @return The status of FMP->SetImage.
-**/
-EFI_STATUS
-SetFmpImageData (
- IN EFI_HANDLE Handle,
- IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
- IN UINTN PayloadIndex
- )
-{
- EFI_STATUS Status;
- EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
- UINT8 *Image;
- VOID *VendorCode;
- CHAR16 *AbortReason;
- EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS ProgressCallback;
-
- Status = gBS->HandleProtocol (
- Handle,
- &gEfiFirmwareManagementProtocolGuid,
- (VOID **)&Fmp
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Lookup Firmware Management Progress Protocol before SetImage() is called
- // This is an optional protocol that may not be present on Handle.
- //
- Status = gBS->HandleProtocol (
- Handle,
- &gEdkiiFirmwareManagementProgressProtocolGuid,
- (VOID **)&mFmpProgress
- );
- if (EFI_ERROR (Status)) {
- mFmpProgress = NULL;
- }
-
- if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
- Image = (UINT8 *)(ImageHeader + 1);
- } else {
- //
- // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,
- // Header should exclude UpdateHardwareInstance field, and
- // ImageCapsuleSupport field if version is 2.
- //
- if (ImageHeader->Version == 1) {
- Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
- } else {
- Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
- }
- }
-
- if (ImageHeader->UpdateVendorCodeSize == 0) {
- VendorCode = NULL;
- } else {
- VendorCode = Image + ImageHeader->UpdateImageSize;
- }
-
- AbortReason = NULL;
- DEBUG ((DEBUG_INFO, "Fmp->SetImage ...\n"));
- DEBUG ((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));
- DEBUG ((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));
- DEBUG ((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));
- if (ImageHeader->Version >= 2) {
- DEBUG ((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));
- if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
- DEBUG ((DEBUG_INFO, "(ImageCapsuleSupport - 0x%x)", ImageHeader->ImageCapsuleSupport));
- }
- }
-
- DEBUG ((DEBUG_INFO, "\n"));
-
- //
- // Before calling SetImage(), reset the progress bar to 0%
- //
- ProgressCallback = UpdateImageProgress;
- Status = UpdateImageProgress (0);
- if (EFI_ERROR (Status)) {
- ProgressCallback = NULL;
- }
-
- Status = Fmp->SetImage (
- Fmp,
- ImageHeader->UpdateImageIndex, // ImageIndex
- Image, // Image
- ImageHeader->UpdateImageSize, // ImageSize
- VendorCode, // VendorCode
- ProgressCallback, // Progress
- &AbortReason // AbortReason
- );
- //
- // Set the progress bar to 100% after returning from SetImage()
- //
- if (ProgressCallback != NULL) {
- UpdateImageProgress (100);
- }
-
- DEBUG ((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));
- if (AbortReason != NULL) {
- DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));
- FreePool (AbortReason);
- }
-
- //
- // Clear mFmpProgress after SetImage() returns
- //
- mFmpProgress = NULL;
-
- return Status;
-}
-
-/**
- Start a UEFI image in the FMP payload.
-
- @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded..
- @param[in] ImageSize The size in bytes of ImageBuffer.
-
- @return The status of gBS->LoadImage and gBS->StartImage.
-**/
-EFI_STATUS
-StartFmpImage (
- IN VOID *ImageBuffer,
- IN UINTN ImageSize
- )
-{
- MEMMAP_DEVICE_PATH MemMapNode;
- EFI_STATUS Status;
- EFI_HANDLE ImageHandle;
- EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
- UINTN ExitDataSize;
-
- SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
- MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;
- MemMapNode.Header.SubType = HW_MEMMAP_DP;
- MemMapNode.MemoryType = EfiBootServicesCode;
- MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;
- MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);
-
- DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
- if (DriverDevicePath == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));
- Status = gBS->LoadImage (
- FALSE,
- gImageHandle,
- DriverDevicePath,
- ImageBuffer,
- ImageSize,
- &ImageHandle
- );
- DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));
- if (EFI_ERROR (Status)) {
- //
- // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
- // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
- // If the caller doesn't have the option to defer the execution of an image, we should
- // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
- //
- if (Status == EFI_SECURITY_VIOLATION) {
- gBS->UnloadImage (ImageHandle);
- }
-
- FreePool (DriverDevicePath);
- return Status;
- }
-
- DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));
- Status = gBS->StartImage (
- ImageHandle,
- &ExitDataSize,
- NULL
- );
- DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
- }
-
- FreePool (DriverDevicePath);
- return Status;
-}
-
-/**
- Record FMP capsule status.
-
- @param[in] Handle A FMP handle.
- @param[in] CapsuleHeader The capsule image header
- @param[in] CapsuleStatus The capsule process stauts
- @param[in] PayloadIndex FMP payload index
- @param[in] ImageHeader FMP image header
- @param[in] CapFileName Capsule file name
-**/
-VOID
-RecordFmpCapsuleStatus (
- IN EFI_HANDLE Handle OPTIONAL,
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN EFI_STATUS CapsuleStatus,
- IN UINTN PayloadIndex,
- IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
- IN CHAR16 *CapFileName OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;
- UINT32 FmpImageInfoDescriptorVer;
- EFI_STATUS StatusEsrt;
- ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
- EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;
-
- FmpDevicePath = NULL;
- if (Handle != NULL) {
- gBS->HandleProtocol (
- Handle,
- &gEfiDevicePathProtocolGuid,
- (VOID **)&FmpDevicePath
- );
- }
-
- RecordFmpCapsuleStatusVariable (
- CapsuleHeader,
- CapsuleStatus,
- PayloadIndex,
- ImageHeader,
- FmpDevicePath,
- CapFileName
- );
-
- //
- // Update corresponding ESRT entry LastAttemp Status
- //
- Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
- if (EFI_ERROR (Status)) {
- return;
- }
-
- if (Handle == NULL) {
- return;
- }
-
- //
- // Update EsrtEntry For V1, V2 FMP instance.
- // V3 FMP ESRT cache will be synced up through SyncEsrtFmp interface
- //
- FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);
- if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {
- StatusEsrt = EsrtProtocol->GetEsrtEntry (&ImageHeader->UpdateImageTypeId, &EsrtEntry);
- if (!EFI_ERROR (StatusEsrt)) {
- if (!EFI_ERROR (CapsuleStatus)) {
- EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
- } else {
- EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
- }
-
- EsrtEntry.LastAttemptVersion = 0;
- EsrtProtocol->UpdateEsrtEntry (&EsrtEntry);
- }
- }
-}
-
-/**
- Process Firmware management protocol data capsule.
-
- This function assumes the caller validated the capsule by using
- ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
-
- This function need support nested FMP capsule.
-
- @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.
- @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule.
-**/
-EFI_STATUS
-ProcessFmpCapsuleImage (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN CHAR16 *CapFileName OPTIONAL,
- OUT BOOLEAN *ResetRequired OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
- UINT64 *ItemOffsetList;
- UINT32 ItemNum;
- UINTN Index;
- EFI_HANDLE *HandleBuffer;
- BOOLEAN *ResetRequiredBuffer;
- UINTN NumberOfHandles;
- UINTN DriverLen;
- UINT64 UpdateHardwareInstance;
- UINTN Index2;
- BOOLEAN NotReady;
- BOOLEAN Abort;
-
- if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
- return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), CapFileName, ResetRequired);
- }
-
- NotReady = FALSE;
- Abort = FALSE;
-
- DumpFmpCapsule (CapsuleHeader);
-
- FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
-
- if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
- return EFI_INVALID_PARAMETER;
- }
-
- ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
-
- ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
-
- //
- // capsule in which driver count and payload count are both zero is not processed.
- //
- if (ItemNum == 0) {
- return EFI_SUCCESS;
- }
-
- //
- // 1. Try to load & start all the drivers within capsule
- //
- for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
- if ((FmpCapsuleHeader->PayloadItemCount == 0) &&
- (Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1))
- {
- //
- // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
- //
- DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
- } else {
- DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
- }
-
- Status = StartFmpImage (
- (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
- DriverLen
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
- return Status;
- }
- }
-
- //
- // 2. Route payload to right FMP instance
- //
- DEBUG ((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));
-
- DumpAllFmpInfo ();
-
- //
- // Check all the payload entry in capsule payload list
- //
- for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
- ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
-
- UpdateHardwareInstance = 0;
- ///
- /// UpdateHardwareInstance field was added in Version 2
- ///
- if (ImageHeader->Version >= 2) {
- UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;
- }
-
- Status = GetFmpHandleBufferByType (
- &ImageHeader->UpdateImageTypeId,
- UpdateHardwareInstance,
- &NumberOfHandles,
- &HandleBuffer,
- &ResetRequiredBuffer
- );
- if (EFI_ERROR (Status) ||
- (HandleBuffer == NULL) ||
- (ResetRequiredBuffer == NULL))
- {
- NotReady = TRUE;
- RecordFmpCapsuleStatus (
- NULL,
- CapsuleHeader,
- EFI_NOT_READY,
- Index - FmpCapsuleHeader->EmbeddedDriverCount,
- ImageHeader,
- CapFileName
- );
- continue;
- }
-
- for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
- if (Abort) {
- RecordFmpCapsuleStatus (
- HandleBuffer[Index2],
- CapsuleHeader,
- EFI_ABORTED,
- Index - FmpCapsuleHeader->EmbeddedDriverCount,
- ImageHeader,
- CapFileName
- );
- continue;
- }
-
- Status = SetFmpImageData (
- HandleBuffer[Index2],
- ImageHeader,
- Index - FmpCapsuleHeader->EmbeddedDriverCount
- );
- if (Status != EFI_SUCCESS) {
- Abort = TRUE;
- } else {
- if (ResetRequired != NULL) {
- *ResetRequired |= ResetRequiredBuffer[Index2];
- }
- }
-
- RecordFmpCapsuleStatus (
- HandleBuffer[Index2],
- CapsuleHeader,
- Status,
- Index - FmpCapsuleHeader->EmbeddedDriverCount,
- ImageHeader,
- CapFileName
- );
- }
-
- if (HandleBuffer != NULL) {
- FreePool (HandleBuffer);
- }
-
- if (ResetRequiredBuffer != NULL) {
- FreePool (ResetRequiredBuffer);
- }
- }
-
- if (NotReady) {
- return EFI_NOT_READY;
- }
-
- //
- // always return SUCCESS to indicate this capsule is processed.
- // The status of SetImage is recorded in capsule result variable.
- //
- return EFI_SUCCESS;
-}
-
-/**
- Return if there is a FMP header below capsule header.
-
- @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
-
- @retval TRUE There is a FMP header below capsule header.
- @retval FALSE There is not a FMP header below capsule header
-**/
-BOOLEAN
-IsNestedFmpCapsule (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
- )
-{
- EFI_STATUS Status;
- EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
- UINTN Index;
- BOOLEAN EsrtGuidFound;
- EFI_CAPSULE_HEADER *NestedCapsuleHeader;
- UINTN NestedCapsuleSize;
- ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
- EFI_SYSTEM_RESOURCE_ENTRY Entry;
-
- EsrtGuidFound = FALSE;
- if (mEsrtTable != NULL) {
- EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);
- for (Index = 0; Index < mEsrtTable->FwResourceCount; Index++, EsrtEntry++) {
- if (CompareGuid (&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
- EsrtGuidFound = TRUE;
- break;
- }
- }
- } else {
- //
- // Check ESRT protocol
- //
- Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
- if (!EFI_ERROR (Status)) {
- Status = EsrtProtocol->GetEsrtEntry (&CapsuleHeader->CapsuleGuid, &Entry);
- if (!EFI_ERROR (Status)) {
- EsrtGuidFound = TRUE;
- }
- }
-
- //
- // Check Firmware Management Protocols
- //
- if (!EsrtGuidFound) {
- Status = GetFmpHandleBufferByType (
- &CapsuleHeader->CapsuleGuid,
- 0,
- NULL,
- NULL,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- EsrtGuidFound = TRUE;
- }
- }
- }
-
- if (!EsrtGuidFound) {
- return FALSE;
- }
-
- //
- // Check nested capsule header
- // FMP GUID after ESRT one
- //
- NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
- NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize - (UINTN)NestedCapsuleHeader;
- if (NestedCapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {
- return FALSE;
- }
-
- if (!IsValidCapsuleHeader (NestedCapsuleHeader, NestedCapsuleSize)) {
- return FALSE;
- }
-
- if (!IsFmpCapsuleGuid (&NestedCapsuleHeader->CapsuleGuid)) {
- return FALSE;
- }
-
- DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));
- return TRUE;
-}
-
-/**
- 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
- )
-{
- if (IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
- return TRUE;
- }
-
- if (IsNestedFmpCapsule (CapsuleHeader)) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Those capsules supported by the firmwares.
-
- Caution: This function may receive untrusted input.
-
- @param[in] CapsuleHeader Points to a capsule header.
-
- @retval EFI_SUCESS Input capsule is supported by firmware.
- @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
- @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
-**/
-EFI_STATUS
-EFIAPI
-SupportCapsuleImage (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
- )
-{
- //
- // check Display Capsule Guid
- //
- if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
- return EFI_SUCCESS;
- }
-
- //
- // Check capsule file name capsule
- //
- if (IsCapsuleNameCapsule (CapsuleHeader)) {
- return EFI_SUCCESS;
- }
-
- if (IsFmpCapsule (CapsuleHeader)) {
- //
- // Fake capsule header is valid case in QueryCapsuleCpapbilities().
- //
- if (CapsuleHeader->HeaderSize == CapsuleHeader->CapsuleImageSize) {
- return EFI_SUCCESS;
- }
-
- //
- // Check layout of FMP capsule
- //
- return ValidateFmpCapsule (CapsuleHeader, NULL);
- }
-
- DEBUG ((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));
- return EFI_UNSUPPORTED;
-}
-
-/**
- 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
- )
-{
- EFI_STATUS Status;
-
- if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
- RecordCapsuleStatusVariable (CapsuleHeader, EFI_UNSUPPORTED);
- return EFI_UNSUPPORTED;
- }
-
- //
- // Display image in firmware update display capsule
- //
- if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
- DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));
- Status = DisplayCapsuleImage (CapsuleHeader);
- RecordCapsuleStatusVariable (CapsuleHeader, Status);
- return Status;
- }
-
- //
- // Check FMP capsule layout
- //
- if (IsFmpCapsule (CapsuleHeader)) {
- DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
- DEBUG ((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
- Status = ValidateFmpCapsule (CapsuleHeader, NULL);
- DEBUG ((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
- if (EFI_ERROR (Status)) {
- RecordCapsuleStatusVariable (CapsuleHeader, Status);
- return Status;
- }
-
- //
- // Process EFI FMP Capsule
- //
- DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
- Status = ProcessFmpCapsuleImage (CapsuleHeader, CapFileName, ResetRequired);
- DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
-
- return Status;
- }
-
- return EFI_UNSUPPORTED;
-}
-
-/**
- The firmware implements to process the capsule image.
-
- Caution: This function may receive untrusted input.
-
- @param[in] CapsuleHeader Points to a capsule header.
-
- @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
-ProcessCapsuleImage (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
- )
-{
- return ProcessThisCapsuleImage (CapsuleHeader, NULL, NULL);
-}
-
-/**
- Callback function executed when the EndOfDxe event group is signaled.
-
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context The pointer to the notification function's context, which
- is implementation-dependent.
-**/
-VOID
-EFIAPI
-DxeCapsuleLibEndOfDxe (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- mDxeCapsuleLibEndOfDxe = TRUE;
-}
-
-/**
- The constructor function.
-
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The constructor successfully .
-**/
-EFI_STATUS
-EFIAPI
-DxeCapsuleLibConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- DxeCapsuleLibEndOfDxe,
- NULL,
- &gEfiEndOfDxeEventGroupGuid,
- &mDxeCapsuleLibEndOfDxeEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- InitCapsuleVariable ();
-
- return EFI_SUCCESS;
-}
-
-/**
- The destructor function closes the End of DXE event.
-
- @param ImageHandle The firmware allocated handle for the EFI image.
- @param SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The destructor completed successfully.
-**/
-EFI_STATUS
-EFIAPI
-DxeCapsuleLibDestructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- //
- // Close the End of DXE event.
- //
- Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);
- ASSERT_EFI_ERROR (Status);
-
- return EFI_SUCCESS;
-}
+/** @file
+ DXE capsule library.
+
+ 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.
+
+ SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),
+ ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted input and
+ performs basic validation.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+#include <Guid/FmpCapsule.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BmpSupportLib.h>
+
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/EsrtManagement.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/FirmwareManagementProgress.h>
+#include <Protocol/DevicePath.h>
+
+EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL;
+
+BOOLEAN mDxeCapsuleLibEndOfDxe = FALSE;
+EFI_EVENT mDxeCapsuleLibEndOfDxeEvent = NULL;
+
+EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *mFmpProgress = NULL;
+
+/**
+ Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable (
+ VOID
+ );
+
+/**
+ Record capsule status variable.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus
+ );
+
+/**
+ Record FMP capsule status variable.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+ @param[in] PayloadIndex FMP payload index
+ @param[in] ImageHeader FMP image header
+ @param[in] FmpDevicePath DevicePath associated with the FMP producer
+ @param[in] CapFileName Capsule file name
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordFmpCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus,
+ IN UINTN PayloadIndex,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL,
+ IN CHAR16 *CapFileName 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
+ );
+
+/**
+ 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
+ )
+{
+ return CompareGuid (&CapsuleHeader->CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
+}
+
+/**
+ Return if this CapsuleGuid is a FMP capsule GUID or not.
+
+ @param[in] CapsuleGuid A pointer to EFI_GUID
+
+ @retval TRUE It is a FMP capsule GUID.
+ @retval FALSE It is not a FMP capsule GUID.
+**/
+BOOLEAN
+IsFmpCapsuleGuid (
+ IN EFI_GUID *CapsuleGuid
+ )
+{
+ if (CompareGuid (&gEfiFmpCapsuleGuid, CapsuleGuid)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Validate if it is valid capsule header
+
+ Caution: This function may receive untrusted input.
+
+ 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
+ )
+{
+ if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
+ return FALSE;
+ }
+
+ if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ 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
+ )
+{
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ UINT8 *EndOfCapsule;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINT8 *EndOfPayload;
+ UINT64 *ItemOffsetList;
+ UINT32 ItemNum;
+ UINTN Index;
+ UINTN FmpCapsuleSize;
+ UINTN FmpCapsuleHeaderSize;
+ UINT64 FmpImageSize;
+ UINTN FmpImageHeaderSize;
+
+ if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
+ return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);
+ }
+
+ if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+ DEBUG ((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+ EndOfCapsule = (UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize;
+ FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
+
+ if (FmpCapsuleSize < sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
+ DEBUG ((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
+ if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
+ DEBUG ((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+ // No overflow
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+
+ if ((FmpCapsuleSize - sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof (UINT64) < ItemNum) {
+ DEBUG ((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FmpCapsuleHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof (UINT64)*ItemNum;
+
+ // Check ItemOffsetList
+ for (Index = 0; Index < ItemNum; Index++) {
+ if (ItemOffsetList[Index] >= FmpCapsuleSize) {
+ DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
+ DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // All the address in ItemOffsetList must be stored in ascending order
+ //
+ if (Index > 0) {
+ if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
+ DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index - 1, ItemOffsetList[Index - 1]));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+ if (Index == ItemNum - 1) {
+ EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
+ } else {
+ EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
+ }
+
+ FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
+
+ FmpImageHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
+ if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
+ (ImageHeader->Version < 1))
+ {
+ DEBUG ((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ImageHeader->Version == 1) {
+ FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
+ } else if (ImageHeader->Version == 2) {
+ FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
+ }
+
+ if (FmpImageSize < FmpImageHeaderSize) {
+ DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) < FmpImageHeaderSize(0x%x)\n", FmpImageSize, FmpImageHeaderSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // No overflow
+ if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
+ DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (ItemNum == 0) {
+ //
+ // No driver & payload element in FMP
+ //
+ EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
+ if (EndOfPayload != EndOfCapsule) {
+ DEBUG ((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_UNSUPPORTED;
+ }
+
+ if (EmbeddedDriverCount != NULL) {
+ *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Those capsules supported by the firmwares.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+
+ @retval EFI_SUCESS Input capsule is supported by firmware.
+ @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
+**/
+EFI_STATUS
+DisplayCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ DISPLAY_DISPLAY_PAYLOAD *ImagePayload;
+ UINTN PayloadSize;
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ UINTN BltSize;
+ UINTN Height;
+ UINTN Width;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+
+ //
+ // UX capsule doesn't have extended header entries.
+ //
+ if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize);
+ //
+ // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().
+ //
+ PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
+
+ //
+ // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.
+ // Further size check is performed by the logic translating BMP to GOP BLT.
+ //
+ if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ImagePayload->Version != 1) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (CalculateCheckSum8 ((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Only Support Bitmap by now
+ //
+ if (ImagePayload->ImageType != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Try to open GOP
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
+ if (EFI_ERROR (Status)) {
+ Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Blt = NULL;
+ Width = 0;
+ Height = 0;
+ Status = TranslateBmpToGopBlt (
+ ImagePayload + 1,
+ PayloadSize - sizeof (DISPLAY_DISPLAY_PAYLOAD),
+ &Blt,
+ &BltSize,
+ &Height,
+ &Width
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ Blt,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ (UINTN)ImagePayload->OffsetX,
+ (UINTN)ImagePayload->OffsetY,
+ Width,
+ Height,
+ Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+
+ FreePool (Blt);
+
+ return Status;
+}
+
+/**
+ Dump FMP information.
+
+ @param[in] ImageInfoSize The size of ImageInfo, in bytes.
+ @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
+ @param[in] PackageVersion The version of package.
+ @param[in] PackageVersionName The version name of package.
+**/
+VOID
+DumpFmpImageInfo (
+ IN UINTN ImageInfoSize,
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ IN UINT32 DescriptorVersion,
+ IN UINT8 DescriptorCount,
+ IN UINTN DescriptorSize,
+ IN UINT32 PackageVersion,
+ IN CHAR16 *PackageVersionName
+ )
+{
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;
+ UINTN Index;
+
+ DEBUG ((DEBUG_VERBOSE, " DescriptorVersion - 0x%x\n", DescriptorVersion));
+ DEBUG ((DEBUG_VERBOSE, " DescriptorCount - 0x%x\n", DescriptorCount));
+ DEBUG ((DEBUG_VERBOSE, " DescriptorSize - 0x%x\n", DescriptorSize));
+ DEBUG ((DEBUG_VERBOSE, " PackageVersion - 0x%x\n", PackageVersion));
+ DEBUG ((DEBUG_VERBOSE, " PackageVersionName - %s\n\n", PackageVersionName));
+ CurrentImageInfo = ImageInfo;
+ for (Index = 0; Index < DescriptorCount; Index++) {
+ DEBUG ((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));
+ DEBUG ((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex));
+ DEBUG ((DEBUG_VERBOSE, " ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId));
+ DEBUG ((DEBUG_VERBOSE, " ImageId - 0x%lx\n", CurrentImageInfo->ImageId));
+ DEBUG ((DEBUG_VERBOSE, " ImageIdName - %s\n", CurrentImageInfo->ImageIdName));
+ DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", CurrentImageInfo->Version));
+ DEBUG ((DEBUG_VERBOSE, " VersionName - %s\n", CurrentImageInfo->VersionName));
+ DEBUG ((DEBUG_VERBOSE, " Size - 0x%x\n", CurrentImageInfo->Size));
+ DEBUG ((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported));
+ DEBUG ((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting));
+ DEBUG ((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities));
+ if (DescriptorVersion > 1) {
+ DEBUG ((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));
+ if (DescriptorVersion > 2) {
+ DEBUG ((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion));
+ DEBUG ((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", CurrentImageInfo->LastAttemptStatus));
+ DEBUG ((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance));
+ }
+ }
+
+ //
+ // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
+ //
+ CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);
+ }
+}
+
+/**
+ Dump a non-nested FMP capsule.
+
+ @param[in] CapsuleHeader A pointer to CapsuleHeader
+**/
+VOID
+DumpFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINTN Index;
+ UINT64 *ItemOffsetList;
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+
+ DEBUG ((DEBUG_VERBOSE, "FmpCapsule:\n"));
+ DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", FmpCapsuleHeader->Version));
+ DEBUG ((DEBUG_VERBOSE, " EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));
+ DEBUG ((DEBUG_VERBOSE, " PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));
+
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+ for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
+ DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
+ }
+
+ for ( ; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {
+ DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+
+ DEBUG ((DEBUG_VERBOSE, " ImageHeader:\n"));
+ DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", ImageHeader->Version));
+ DEBUG ((DEBUG_VERBOSE, " UpdateImageTypeId - %g\n", &ImageHeader->UpdateImageTypeId));
+ DEBUG ((DEBUG_VERBOSE, " UpdateImageIndex - 0x%x\n", ImageHeader->UpdateImageIndex));
+ DEBUG ((DEBUG_VERBOSE, " UpdateImageSize - 0x%x\n", ImageHeader->UpdateImageSize));
+ DEBUG ((DEBUG_VERBOSE, " UpdateVendorCodeSize - 0x%x\n", ImageHeader->UpdateVendorCodeSize));
+ if (ImageHeader->Version >= 2) {
+ DEBUG ((DEBUG_VERBOSE, " UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ DEBUG ((DEBUG_VERBOSE, " ImageCapsuleSupport - 0x%lx\n", ImageHeader->ImageCapsuleSupport));
+ }
+ }
+ }
+}
+
+/**
+ Dump all FMP information.
+**/
+VOID
+DumpAllFmpInfo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINTN Index;
+ UINTN ImageInfoSize;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareManagementProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareManagementProtocolGuid,
+ (VOID **)&Fmp
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ ImageInfoSize = 0;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ continue;
+ }
+
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ continue;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ &FmpImageInfoDescriptorVer, // DescriptorVersion
+ &FmpImageInfoCount, // DescriptorCount
+ &DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FmpImageInfoBuf);
+ continue;
+ }
+
+ DEBUG ((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));
+ DumpFmpImageInfo (
+ ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ FmpImageInfoDescriptorVer, // DescriptorVersion
+ FmpImageInfoCount, // DescriptorCount
+ DescriptorSize, // DescriptorSize
+ PackageVersion, // PackageVersion
+ PackageVersionName // PackageVersionName
+ );
+
+ if (PackageVersionName != NULL) {
+ FreePool (PackageVersionName);
+ }
+
+ FreePool (FmpImageInfoBuf);
+ }
+
+ FreePool (HandleBuffer);
+
+ return;
+}
+
+/**
+ Get FMP handle by ImageTypeId and HardwareInstance.
+
+ @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update.
+ @param[in] UpdateHardwareInstance The HardwareInstance to target with this update.
+ @param[out] NoHandles The number of handles returned in HandleBuf.
+ @param[out] HandleBuf A pointer to the buffer to return the requested array of handles.
+ @param[out] ResetRequiredBuf A pointer to the buffer to return reset required flag for
+ the requested array of handles.
+
+ @retval EFI_SUCCESS The array of handles and their reset required flag were returned in
+ HandleBuf and ResetRequiredBuf, and the number of handles in HandleBuf
+ was returned in NoHandles.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+**/
+EFI_STATUS
+GetFmpHandleBufferByType (
+ IN EFI_GUID *UpdateImageTypeId,
+ IN UINT64 UpdateHardwareInstance,
+ OUT UINTN *NoHandles OPTIONAL,
+ OUT EFI_HANDLE **HandleBuf OPTIONAL,
+ OUT BOOLEAN **ResetRequiredBuf OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_HANDLE *MatchedHandleBuffer;
+ BOOLEAN *MatchedResetRequiredBuffer;
+ UINTN MatchedNumberOfHandles;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINTN Index;
+ UINTN ImageInfoSize;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+ UINTN Index2;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
+
+ if (NoHandles != NULL) {
+ *NoHandles = 0;
+ }
+
+ if (HandleBuf != NULL) {
+ *HandleBuf = NULL;
+ }
+
+ if (ResetRequiredBuf != NULL) {
+ *ResetRequiredBuf = NULL;
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareManagementProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MatchedNumberOfHandles = 0;
+
+ MatchedHandleBuffer = NULL;
+ if (HandleBuf != NULL) {
+ MatchedHandleBuffer = AllocateZeroPool (sizeof (EFI_HANDLE) * NumberOfHandles);
+ if (MatchedHandleBuffer == NULL) {
+ FreePool (HandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ MatchedResetRequiredBuffer = NULL;
+ if (ResetRequiredBuf != NULL) {
+ MatchedResetRequiredBuffer = AllocateZeroPool (sizeof (BOOLEAN) * NumberOfHandles);
+ if (MatchedResetRequiredBuffer == NULL) {
+ if (MatchedHandleBuffer != NULL) {
+ FreePool (MatchedHandleBuffer);
+ }
+
+ FreePool (HandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ for (Index = 0; Index < NumberOfHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareManagementProtocolGuid,
+ (VOID **)&Fmp
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ ImageInfoSize = 0;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ continue;
+ }
+
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ continue;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ &FmpImageInfoDescriptorVer, // DescriptorVersion
+ &FmpImageInfoCount, // DescriptorCount
+ &DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FmpImageInfoBuf);
+ continue;
+ }
+
+ if (PackageVersionName != NULL) {
+ FreePool (PackageVersionName);
+ }
+
+ TempFmpImageInfo = FmpImageInfoBuf;
+ for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
+ //
+ // Check if this FMP instance matches
+ //
+ if (CompareGuid (UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {
+ if ((UpdateHardwareInstance == 0) ||
+ ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&
+ (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance)))
+ {
+ if (MatchedHandleBuffer != NULL) {
+ MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];
+ }
+
+ if (MatchedResetRequiredBuffer != NULL) {
+ MatchedResetRequiredBuffer[MatchedNumberOfHandles] = (((TempFmpImageInfo->AttributesSupported &
+ IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) &&
+ ((TempFmpImageInfo->AttributesSetting &
+ IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0));
+ }
+
+ MatchedNumberOfHandles++;
+ break;
+ }
+ }
+
+ TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
+ }
+
+ FreePool (FmpImageInfoBuf);
+ }
+
+ FreePool (HandleBuffer);
+
+ if (MatchedNumberOfHandles == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (NoHandles != NULL) {
+ *NoHandles = MatchedNumberOfHandles;
+ }
+
+ if (HandleBuf != NULL) {
+ *HandleBuf = MatchedHandleBuffer;
+ }
+
+ if (ResetRequiredBuf != NULL) {
+ *ResetRequiredBuf = MatchedResetRequiredBuffer;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return FmpImageInfoDescriptorVer by an FMP handle.
+
+ @param[in] Handle A FMP handle.
+
+ @return FmpImageInfoDescriptorVer associated with the FMP.
+**/
+UINT32
+GetFmpImageInfoDescriptorVer (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINTN ImageInfoSize;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiFirmwareManagementProtocolGuid,
+ (VOID **)&Fmp
+ );
+ if (EFI_ERROR (Status)) {
+ return 0;
+ }
+
+ ImageInfoSize = 0;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return 0;
+ }
+
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ return 0;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ &FmpImageInfoDescriptorVer, // DescriptorVersion
+ &FmpImageInfoCount, // DescriptorCount
+ &DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FmpImageInfoBuf);
+ return 0;
+ }
+
+ return FmpImageInfoDescriptorVer;
+}
+
+/**
+ Set FMP image data.
+
+ @param[in] Handle A FMP handle.
+ @param[in] ImageHeader The payload image header.
+ @param[in] PayloadIndex The index of the payload.
+
+ @return The status of FMP->SetImage.
+**/
+EFI_STATUS
+SetFmpImageData (
+ IN EFI_HANDLE Handle,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN UINTN PayloadIndex
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINT8 *Image;
+ VOID *VendorCode;
+ CHAR16 *AbortReason;
+ EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS ProgressCallback;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiFirmwareManagementProtocolGuid,
+ (VOID **)&Fmp
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Lookup Firmware Management Progress Protocol before SetImage() is called
+ // This is an optional protocol that may not be present on Handle.
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEdkiiFirmwareManagementProgressProtocolGuid,
+ (VOID **)&mFmpProgress
+ );
+ if (EFI_ERROR (Status)) {
+ mFmpProgress = NULL;
+ }
+
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ Image = (UINT8 *)(ImageHeader + 1);
+ } else {
+ //
+ // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,
+ // Header should exclude UpdateHardwareInstance field, and
+ // ImageCapsuleSupport field if version is 2.
+ //
+ if (ImageHeader->Version == 1) {
+ Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
+ } else {
+ Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
+ }
+ }
+
+ if (ImageHeader->UpdateVendorCodeSize == 0) {
+ VendorCode = NULL;
+ } else {
+ VendorCode = Image + ImageHeader->UpdateImageSize;
+ }
+
+ AbortReason = NULL;
+ DEBUG ((DEBUG_INFO, "Fmp->SetImage ...\n"));
+ DEBUG ((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));
+ DEBUG ((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));
+ DEBUG ((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));
+ if (ImageHeader->Version >= 2) {
+ DEBUG ((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ DEBUG ((DEBUG_INFO, "(ImageCapsuleSupport - 0x%x)", ImageHeader->ImageCapsuleSupport));
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ //
+ // Before calling SetImage(), reset the progress bar to 0%
+ //
+ ProgressCallback = UpdateImageProgress;
+ Status = UpdateImageProgress (0);
+ if (EFI_ERROR (Status)) {
+ ProgressCallback = NULL;
+ }
+
+ Status = Fmp->SetImage (
+ Fmp,
+ ImageHeader->UpdateImageIndex, // ImageIndex
+ Image, // Image
+ ImageHeader->UpdateImageSize, // ImageSize
+ VendorCode, // VendorCode
+ ProgressCallback, // Progress
+ &AbortReason // AbortReason
+ );
+ //
+ // Set the progress bar to 100% after returning from SetImage()
+ //
+ if (ProgressCallback != NULL) {
+ UpdateImageProgress (100);
+ }
+
+ DEBUG ((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));
+ if (AbortReason != NULL) {
+ DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));
+ FreePool (AbortReason);
+ }
+
+ //
+ // Clear mFmpProgress after SetImage() returns
+ //
+ mFmpProgress = NULL;
+
+ return Status;
+}
+
+/**
+ Start a UEFI image in the FMP payload.
+
+ @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded..
+ @param[in] ImageSize The size in bytes of ImageBuffer.
+
+ @return The status of gBS->LoadImage and gBS->StartImage.
+**/
+EFI_STATUS
+StartFmpImage (
+ IN VOID *ImageBuffer,
+ IN UINTN ImageSize
+ )
+{
+ MEMMAP_DEVICE_PATH MemMapNode;
+ EFI_STATUS Status;
+ EFI_HANDLE ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
+ UINTN ExitDataSize;
+
+ SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
+ MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;
+ MemMapNode.Header.SubType = HW_MEMMAP_DP;
+ MemMapNode.MemoryType = EfiBootServicesCode;
+ MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;
+ MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);
+
+ DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
+ if (DriverDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));
+ Status = gBS->LoadImage (
+ FALSE,
+ gImageHandle,
+ DriverDevicePath,
+ ImageBuffer,
+ ImageSize,
+ &ImageHandle
+ );
+ DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ //
+ // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
+ // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
+ // If the caller doesn't have the option to defer the execution of an image, we should
+ // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
+ //
+ if (Status == EFI_SECURITY_VIOLATION) {
+ gBS->UnloadImage (ImageHandle);
+ }
+
+ FreePool (DriverDevicePath);
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));
+ Status = gBS->StartImage (
+ ImageHandle,
+ &ExitDataSize,
+ NULL
+ );
+ DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
+ }
+
+ FreePool (DriverDevicePath);
+ return Status;
+}
+
+/**
+ Record FMP capsule status.
+
+ @param[in] Handle A FMP handle.
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+ @param[in] PayloadIndex FMP payload index
+ @param[in] ImageHeader FMP image header
+ @param[in] CapFileName Capsule file name
+**/
+VOID
+RecordFmpCapsuleStatus (
+ IN EFI_HANDLE Handle OPTIONAL,
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus,
+ IN UINTN PayloadIndex,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN CHAR16 *CapFileName OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;
+ UINT32 FmpImageInfoDescriptorVer;
+ EFI_STATUS StatusEsrt;
+ ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
+ EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;
+
+ FmpDevicePath = NULL;
+ if (Handle != NULL) {
+ gBS->HandleProtocol (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&FmpDevicePath
+ );
+ }
+
+ RecordFmpCapsuleStatusVariable (
+ CapsuleHeader,
+ CapsuleStatus,
+ PayloadIndex,
+ ImageHeader,
+ FmpDevicePath,
+ CapFileName
+ );
+
+ //
+ // Update corresponding ESRT entry LastAttemp Status
+ //
+ Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (Handle == NULL) {
+ return;
+ }
+
+ //
+ // Update EsrtEntry For V1, V2 FMP instance.
+ // V3 FMP ESRT cache will be synced up through SyncEsrtFmp interface
+ //
+ FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);
+ if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {
+ StatusEsrt = EsrtProtocol->GetEsrtEntry (&ImageHeader->UpdateImageTypeId, &EsrtEntry);
+ if (!EFI_ERROR (StatusEsrt)) {
+ if (!EFI_ERROR (CapsuleStatus)) {
+ EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+ } else {
+ EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
+ }
+
+ EsrtEntry.LastAttemptVersion = 0;
+ EsrtProtocol->UpdateEsrtEntry (&EsrtEntry);
+ }
+ }
+}
+
+/**
+ Process Firmware management protocol data capsule.
+
+ This function assumes the caller validated the capsule by using
+ ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
+
+ This function need support nested FMP capsule.
+
+ @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.
+ @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule.
+**/
+EFI_STATUS
+ProcessFmpCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN CHAR16 *CapFileName OPTIONAL,
+ OUT BOOLEAN *ResetRequired OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINT64 *ItemOffsetList;
+ UINT32 ItemNum;
+ UINTN Index;
+ EFI_HANDLE *HandleBuffer;
+ BOOLEAN *ResetRequiredBuffer;
+ UINTN NumberOfHandles;
+ UINTN DriverLen;
+ UINT64 UpdateHardwareInstance;
+ UINTN Index2;
+ BOOLEAN NotReady;
+ BOOLEAN Abort;
+
+ if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
+ return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), CapFileName, ResetRequired);
+ }
+
+ NotReady = FALSE;
+ Abort = FALSE;
+
+ DumpFmpCapsule (CapsuleHeader);
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+
+ if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+
+ //
+ // capsule in which driver count and payload count are both zero is not processed.
+ //
+ if (ItemNum == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 1. Try to load & start all the drivers within capsule
+ //
+ for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
+ if ((FmpCapsuleHeader->PayloadItemCount == 0) &&
+ (Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1))
+ {
+ //
+ // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
+ //
+ DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
+ } else {
+ DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
+ }
+
+ Status = StartFmpImage (
+ (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
+ DriverLen
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // 2. Route payload to right FMP instance
+ //
+ DEBUG ((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));
+
+ DumpAllFmpInfo ();
+
+ //
+ // Check all the payload entry in capsule payload list
+ //
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+
+ UpdateHardwareInstance = 0;
+ ///
+ /// UpdateHardwareInstance field was added in Version 2
+ ///
+ if (ImageHeader->Version >= 2) {
+ UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;
+ }
+
+ Status = GetFmpHandleBufferByType (
+ &ImageHeader->UpdateImageTypeId,
+ UpdateHardwareInstance,
+ &NumberOfHandles,
+ &HandleBuffer,
+ &ResetRequiredBuffer
+ );
+ if (EFI_ERROR (Status) ||
+ (HandleBuffer == NULL) ||
+ (ResetRequiredBuffer == NULL))
+ {
+ NotReady = TRUE;
+ RecordFmpCapsuleStatus (
+ NULL,
+ CapsuleHeader,
+ EFI_NOT_READY,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount,
+ ImageHeader,
+ CapFileName
+ );
+ continue;
+ }
+
+ for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
+ if (Abort) {
+ RecordFmpCapsuleStatus (
+ HandleBuffer[Index2],
+ CapsuleHeader,
+ EFI_ABORTED,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount,
+ ImageHeader,
+ CapFileName
+ );
+ continue;
+ }
+
+ Status = SetFmpImageData (
+ HandleBuffer[Index2],
+ ImageHeader,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount
+ );
+ if (Status != EFI_SUCCESS) {
+ Abort = TRUE;
+ } else {
+ if (ResetRequired != NULL) {
+ *ResetRequired |= ResetRequiredBuffer[Index2];
+ }
+ }
+
+ RecordFmpCapsuleStatus (
+ HandleBuffer[Index2],
+ CapsuleHeader,
+ Status,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount,
+ ImageHeader,
+ CapFileName
+ );
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ if (ResetRequiredBuffer != NULL) {
+ FreePool (ResetRequiredBuffer);
+ }
+ }
+
+ if (NotReady) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // always return SUCCESS to indicate this capsule is processed.
+ // The status of SetImage is recorded in capsule result variable.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Return if there is a FMP header below capsule header.
+
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+ @retval TRUE There is a FMP header below capsule header.
+ @retval FALSE There is not a FMP header below capsule header
+**/
+BOOLEAN
+IsNestedFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
+ UINTN Index;
+ BOOLEAN EsrtGuidFound;
+ EFI_CAPSULE_HEADER *NestedCapsuleHeader;
+ UINTN NestedCapsuleSize;
+ ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
+ EFI_SYSTEM_RESOURCE_ENTRY Entry;
+
+ EsrtGuidFound = FALSE;
+ if (mEsrtTable != NULL) {
+ EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);
+ for (Index = 0; Index < mEsrtTable->FwResourceCount; Index++, EsrtEntry++) {
+ if (CompareGuid (&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
+ EsrtGuidFound = TRUE;
+ break;
+ }
+ }
+ } else {
+ //
+ // Check ESRT protocol
+ //
+ Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
+ if (!EFI_ERROR (Status)) {
+ Status = EsrtProtocol->GetEsrtEntry (&CapsuleHeader->CapsuleGuid, &Entry);
+ if (!EFI_ERROR (Status)) {
+ EsrtGuidFound = TRUE;
+ }
+ }
+
+ //
+ // Check Firmware Management Protocols
+ //
+ if (!EsrtGuidFound) {
+ Status = GetFmpHandleBufferByType (
+ &CapsuleHeader->CapsuleGuid,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ EsrtGuidFound = TRUE;
+ }
+ }
+ }
+
+ if (!EsrtGuidFound) {
+ return FALSE;
+ }
+
+ //
+ // Check nested capsule header
+ // FMP GUID after ESRT one
+ //
+ NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+ NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize - (UINTN)NestedCapsuleHeader;
+ if (NestedCapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {
+ return FALSE;
+ }
+
+ if (!IsValidCapsuleHeader (NestedCapsuleHeader, NestedCapsuleSize)) {
+ return FALSE;
+ }
+
+ if (!IsFmpCapsuleGuid (&NestedCapsuleHeader->CapsuleGuid)) {
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));
+ return TRUE;
+}
+
+/**
+ 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
+ )
+{
+ if (IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
+ return TRUE;
+ }
+
+ if (IsNestedFmpCapsule (CapsuleHeader)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Those capsules supported by the firmwares.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+
+ @retval EFI_SUCESS Input capsule is supported by firmware.
+ @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
+ @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
+**/
+EFI_STATUS
+EFIAPI
+SupportCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ //
+ // check Display Capsule Guid
+ //
+ if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check capsule file name capsule
+ //
+ if (IsCapsuleNameCapsule (CapsuleHeader)) {
+ return EFI_SUCCESS;
+ }
+
+ if (IsFmpCapsule (CapsuleHeader)) {
+ //
+ // Fake capsule header is valid case in QueryCapsuleCpapbilities().
+ //
+ if (CapsuleHeader->HeaderSize == CapsuleHeader->CapsuleImageSize) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check layout of FMP capsule
+ //
+ return ValidateFmpCapsule (CapsuleHeader, NULL);
+ }
+
+ DEBUG ((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ 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
+ )
+{
+ EFI_STATUS Status;
+
+ if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
+ RecordCapsuleStatusVariable (CapsuleHeader, EFI_UNSUPPORTED);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Display image in firmware update display capsule
+ //
+ if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+ DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));
+ Status = DisplayCapsuleImage (CapsuleHeader);
+ RecordCapsuleStatusVariable (CapsuleHeader, Status);
+ return Status;
+ }
+
+ //
+ // Check FMP capsule layout
+ //
+ if (IsFmpCapsule (CapsuleHeader)) {
+ DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
+ DEBUG ((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
+ Status = ValidateFmpCapsule (CapsuleHeader, NULL);
+ DEBUG ((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ RecordCapsuleStatusVariable (CapsuleHeader, Status);
+ return Status;
+ }
+
+ //
+ // Process EFI FMP Capsule
+ //
+ DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
+ Status = ProcessFmpCapsuleImage (CapsuleHeader, CapFileName, ResetRequired);
+ DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
+
+ return Status;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The firmware implements to process the capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+
+ @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
+ProcessCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ return ProcessThisCapsuleImage (CapsuleHeader, NULL, NULL);
+}
+
+/**
+ Callback function executed when the EndOfDxe event group is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+DxeCapsuleLibEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mDxeCapsuleLibEndOfDxe = TRUE;
+}
+
+/**
+ The constructor function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor successfully .
+**/
+EFI_STATUS
+EFIAPI
+DxeCapsuleLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DxeCapsuleLibEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &mDxeCapsuleLibEndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ InitCapsuleVariable ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function closes the End of DXE event.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+DxeCapsuleLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Close the End of DXE event.
+ //
+ Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
index 095e062a6e..1dd8b9a6fe 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
@@ -1,102 +1,102 @@
-## @file
-# Capsule library instance for DXE_DRIVER.
-#
-# Capsule library instance for DXE_DRIVER module types.
-#
-# Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DxeCapsuleLib
- MODULE_UNI_FILE = DxeCapsuleLib.uni
- FILE_GUID = 534E35DE-8EB3-47b3-A4E0-72A571E50733
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
- LIBRARY_CLASS = CapsuleLib|DXE_DRIVER UEFI_APPLICATION
- CONSTRUCTOR = DxeCapsuleLibConstructor
- DESTRUCTOR = DxeCapsuleLibDestructor
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64 EBC
-#
-
-[Sources]
- DxeCapsuleLib.c
- DxeCapsuleProcessLib.c
- DxeCapsuleReportLib.c
- CapsuleOnDisk.c
- CapsuleOnDisk.h
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
-
-[LibraryClasses]
- BaseLib
- BaseMemoryLib
- DebugLib
- MemoryAllocationLib
- DxeServicesTableLib
- UefiBootServicesTableLib
- DevicePathLib
- ReportStatusCodeLib
- PrintLib
- HobLib
- BmpSupportLib
- DisplayUpdateProgressLib
- FileHandleLib
- UefiBootManagerLib
- VariablePolicyHelperLib
-
-[Pcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES
-
- gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleInRamSupport ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleOnDiskSupport ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCodRelocationDevPath ## SOMETIMES_CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdCoDRelocationFileName ## CONSUMES
-
-[FeaturePcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset ## CONSUMES
-
-[Protocols]
- gEsrtManagementProtocolGuid ## CONSUMES
- gEfiFirmwareManagementProtocolGuid ## CONSUMES
- gEdkiiFirmwareManagementProgressProtocolGuid ## SOMETIMES_CONSUMES
- gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
- gEfiBlockIoProtocolGuid ## CONSUMES
- gEfiDiskIoProtocolGuid ## CONSUMES
- gEdkiiVariablePolicyProtocolGuid ## CONSUMES
-
-[Guids]
- gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
- gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
- ## SOMETIMES_CONSUMES ## Variable:L"CapsuleMax"
- ## SOMETIMES_PRODUCES ## Variable:L"CapsuleMax"
- gEfiCapsuleReportGuid
- gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData"
- gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
- gEfiPartTypeSystemPartGuid ## SOMETIMES_CONSUMES
- gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CodRelocationInfo"
- ## SOMETIMES_CONSUMES ## Variable:L"OsIndications"
- ## SOMETIMES_PRODUCES ## Variable:L"OsIndications"
- ## SOMETIMES_CONSUMES ## Variable:L"BootNext"
- ## SOMETIMES_PRODUCES ## Variable:L"BootNext"
- gEfiGlobalVariableGuid
- gEdkiiCapsuleOnDiskNameGuid ## SOMETIMES_CONSUMES ## GUID
-
-[Depex]
- gEfiVariableWriteArchProtocolGuid
+## @file
+# Capsule library instance for DXE_DRIVER.
+#
+# Capsule library instance for DXE_DRIVER module types.
+#
+# Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCapsuleLib
+ MODULE_UNI_FILE = DxeCapsuleLib.uni
+ FILE_GUID = 534E35DE-8EB3-47b3-A4E0-72A571E50733
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CapsuleLib|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = DxeCapsuleLibConstructor
+ DESTRUCTOR = DxeCapsuleLibDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeCapsuleLib.c
+ DxeCapsuleProcessLib.c
+ DxeCapsuleReportLib.c
+ CapsuleOnDisk.c
+ CapsuleOnDisk.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ DxeServicesTableLib
+ UefiBootServicesTableLib
+ DevicePathLib
+ ReportStatusCodeLib
+ PrintLib
+ HobLib
+ BmpSupportLib
+ DisplayUpdateProgressLib
+ FileHandleLib
+ UefiBootManagerLib
+ VariablePolicyHelperLib
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag ## CONSUMES
+
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleInRamSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleOnDiskSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCodRelocationDevPath ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCoDRelocationFileName ## CONSUMES
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset ## CONSUMES
+
+[Protocols]
+ gEsrtManagementProtocolGuid ## CONSUMES
+ gEfiFirmwareManagementProtocolGuid ## CONSUMES
+ gEdkiiFirmwareManagementProgressProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## CONSUMES
+ gEfiDiskIoProtocolGuid ## CONSUMES
+ gEdkiiVariablePolicyProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
+ gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## Variable:L"CapsuleMax"
+ ## SOMETIMES_PRODUCES ## Variable:L"CapsuleMax"
+ gEfiCapsuleReportGuid
+ gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData"
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEfiPartTypeSystemPartGuid ## SOMETIMES_CONSUMES
+ gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CodRelocationInfo"
+ ## SOMETIMES_CONSUMES ## Variable:L"OsIndications"
+ ## SOMETIMES_PRODUCES ## Variable:L"OsIndications"
+ ## SOMETIMES_CONSUMES ## Variable:L"BootNext"
+ ## SOMETIMES_PRODUCES ## Variable:L"BootNext"
+ gEfiGlobalVariableGuid
+ gEdkiiCapsuleOnDiskNameGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Depex]
+ gEfiVariableWriteArchProtocolGuid
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni
index 03c61c55c6..cf82e3b306 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni
@@ -1,16 +1,16 @@
-// /** @file
-// Capsule library instance for DXE_DRIVER.
-//
-// Capsule library instance for DXE_DRIVER module types.
-//
-// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Capsule Support Library"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Capsule library instance for DXE_DRIVER module types."
-
+// /** @file
+// Capsule library instance for DXE_DRIVER.
+//
+// Capsule library instance for DXE_DRIVER module types.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Capsule Support Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Capsule library instance for DXE_DRIVER module types."
+
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;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c
index 9054ae446e..33f99e7433 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c
@@ -1,70 +1,70 @@
-/** @file
- DXE capsule process.
- Dummy function for runtime module, because CapsuleDxeRuntime
- does not need call ProcessCapsules().
-
- Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-#include <Library/CapsuleLib.h>
-
-/**
- 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
- )
-{
- return EFI_SUCCESS;
-}
-
-/**
-
- 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, this routine does nothing.
-
- 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
- )
-{
- return EFI_UNSUPPORTED;
-}
+/** @file
+ DXE capsule process.
+ Dummy function for runtime module, because CapsuleDxeRuntime
+ does not need call ProcessCapsules().
+
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/CapsuleLib.h>
+
+/**
+ 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
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+
+ 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, this routine does nothing.
+
+ 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
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
index a1523428cd..74b6726cef 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
@@ -1,518 +1,518 @@
-/** @file
- DXE capsule report related function.
-
- Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-#include <Protocol/FirmwareManagement.h>
-#include <Guid/CapsuleReport.h>
-#include <Guid/FmpCapsule.h>
-#include <Guid/CapsuleVendor.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/PrintLib.h>
-#include <Library/ReportStatusCodeLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/CapsuleLib.h>
-#include <Library/VariablePolicyHelperLib.h>
-
-#include <IndustryStandard/WindowsUxCapsule.h>
-
-/**
- This routine is called to clear CapsuleOnDisk Relocation Info variable.
- Total Capsule On Disk length is recorded in this variable
-
- @retval EFI_SUCCESS Capsule On Disk flags are cleared
-
-**/
-EFI_STATUS
-CoDClearCapsuleRelocationInfo (
- VOID
- );
-
-/**
- Get current capsule last variable index.
-
- @return Current capsule last variable index.
- @retval -1 No current capsule last variable.
-**/
-INTN
-GetCurrentCapsuleLastIndex (
- VOID
- )
-{
- UINTN Size;
- CHAR16 CapsuleLastStr[sizeof ("Capsule####")];
- EFI_STATUS Status;
- UINT16 CurrentIndex;
-
- Size = sizeof (L"Capsule####") - sizeof (CHAR16); // no zero terminator
- Status = gRT->GetVariable (
- L"CapsuleLast",
- &gEfiCapsuleReportGuid,
- NULL,
- &Size,
- CapsuleLastStr
- );
- if (EFI_ERROR (Status)) {
- return -1;
- }
-
- CurrentIndex = (UINT16)StrHexToUintn (&CapsuleLastStr[sizeof ("Capsule") - 1]);
- return CurrentIndex;
-}
-
-/**
- Get a new capsule status variable index.
-
- @return A new capsule status variable index.
- @retval 0 No new capsule status variable index. Rolling over.
-**/
-INTN
-GetNewCapsuleResultIndex (
- VOID
- )
-{
- INTN CurrentIndex;
-
- CurrentIndex = GetCurrentCapsuleLastIndex ();
- if (CurrentIndex >= PcdGet16 (PcdCapsuleMax)) {
- DEBUG ((DEBUG_INFO, " CapsuleResult variable Rolling Over!\n"));
- return 0;
- }
-
- return CurrentIndex + 1;
-}
-
-/**
- Lock Variable by variable policy.
-
- @param[in] VariableGuid The Guid of the variable to be locked
- @param[in] VariableName The name of the variable to be locked
- @param[in] VariablePolicy The pointer of variable lock policy
-**/
-VOID
-LockVariable (
- IN CONST EFI_GUID VariableGuid,
- IN CHAR16 *VariableName,
- IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy
- )
-{
- EFI_STATUS Status;
-
- // Set the policies to protect the target variables
- Status = RegisterBasicVariablePolicy (
- VariablePolicy,
- &VariableGuid,
- VariableName,
- VARIABLE_POLICY_NO_MIN_SIZE,
- VARIABLE_POLICY_NO_MAX_SIZE,
- VARIABLE_POLICY_NO_MUST_ATTR,
- VARIABLE_POLICY_NO_CANT_ATTR,
- VARIABLE_POLICY_TYPE_LOCK_NOW
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "DxeCapsuleLibFmp: Failed to lock variable %g %s. Status = %r\n",
- &VariableGuid,
- VariableName,
- Status
- ));
- ASSERT_EFI_ERROR (Status);
- }
-}
-
-/**
- Write a new capsule status variable.
-
- @param[in] CapsuleResult The capsule status variable
- @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
-
- @retval EFI_SUCCESS The capsule status variable is recorded.
- @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
-**/
-EFI_STATUS
-WriteNewCapsuleResultVariable (
- IN VOID *CapsuleResult,
- IN UINTN CapsuleResultSize
- )
-{
- INTN CapsuleResultIndex;
- CHAR16 CapsuleResultStr[sizeof ("Capsule####")];
- UINTN Size;
- EFI_STATUS Status;
-
- CapsuleResultIndex = GetNewCapsuleResultIndex ();
- DEBUG ((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex));
-
- UnicodeSPrint (
- CapsuleResultStr,
- sizeof (CapsuleResultStr),
- L"Capsule%04x",
- CapsuleResultIndex
- );
-
- Status = gRT->SetVariable (
- CapsuleResultStr,
- &gEfiCapsuleReportGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- CapsuleResultSize,
- CapsuleResult
- );
- if (!EFI_ERROR (Status)) {
- Size = sizeof (L"Capsule####") - sizeof (CHAR16); // no zero terminator
- DEBUG ((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));
- Status = gRT->SetVariable (
- L"CapsuleLast",
- &gEfiCapsuleReportGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- Size,
- CapsuleResultStr
- );
- }
-
- return Status;
-}
-
-/**
- Record capsule status variable and to local cache.
-
- @param[in] CapsuleHeader The capsule image header
- @param[in] CapsuleStatus The capsule process stauts
-
- @retval EFI_SUCCESS The capsule status variable is recorded.
- @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
-**/
-EFI_STATUS
-RecordCapsuleStatusVariable (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN EFI_STATUS CapsuleStatus
- )
-{
- EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable;
- EFI_STATUS Status;
-
- CapsuleResultVariable.VariableTotalSize = sizeof (CapsuleResultVariable);
- CapsuleResultVariable.Reserved = 0;
- CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);
- ZeroMem (&CapsuleResultVariable.CapsuleProcessed, sizeof (CapsuleResultVariable.CapsuleProcessed));
- gRT->GetTime (&CapsuleResultVariable.CapsuleProcessed, NULL);
- CapsuleResultVariable.CapsuleStatus = CapsuleStatus;
-
- Status = EFI_SUCCESS;
- if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
- Status = WriteNewCapsuleResultVariable (&CapsuleResultVariable, sizeof (CapsuleResultVariable));
- }
-
- return Status;
-}
-
-/**
- Record FMP capsule status variable and to local cache.
-
- @param[in] CapsuleHeader The capsule image header
- @param[in] CapsuleStatus The capsule process stauts
- @param[in] PayloadIndex FMP payload index
- @param[in] ImageHeader FMP image header
- @param[in] FmpDevicePath DevicePath associated with the FMP producer
- @param[in] CapFileName Capsule file name
-
- @retval EFI_SUCCESS The capsule status variable is recorded.
- @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
-**/
-EFI_STATUS
-RecordFmpCapsuleStatusVariable (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN EFI_STATUS CapsuleStatus,
- IN UINTN PayloadIndex,
- IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
- IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL,
- IN CHAR16 *CapFileName OPTIONAL
- )
-{
- EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader;
- EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;
- EFI_STATUS Status;
- UINT8 *CapsuleResultVariable;
- UINTN CapsuleResultVariableSize;
- CHAR16 *DevicePathStr;
- UINTN DevicePathStrSize;
- UINTN CapFileNameSize;
-
- DevicePathStr = NULL;
- CapFileNameSize = sizeof (CHAR16);
-
- if (FmpDevicePath != NULL) {
- DevicePathStr = ConvertDevicePathToText (FmpDevicePath, FALSE, FALSE);
- }
-
- if (DevicePathStr != NULL) {
- DevicePathStrSize = StrSize (DevicePathStr);
- } else {
- DevicePathStrSize = sizeof (CHAR16);
- }
-
- if (CapFileName != NULL) {
- CapFileNameSize = StrSize (CapFileName);
- }
-
- //
- // Allocate room for CapsuleFileName.
- //
- CapsuleResultVariableSize = sizeof (EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof (EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize + DevicePathStrSize;
-
- CapsuleResultVariable = AllocateZeroPool (CapsuleResultVariableSize);
- if (CapsuleResultVariable == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- CapsuleResultVariableHeader = (VOID *)CapsuleResultVariable;
- CapsuleResultVariableHeader->VariableTotalSize = (UINT32)CapsuleResultVariableSize;
- CapsuleResultVariableHeader->Reserved = 0;
- CopyGuid (&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);
- ZeroMem (&CapsuleResultVariableHeader->CapsuleProcessed, sizeof (CapsuleResultVariableHeader->CapsuleProcessed));
- gRT->GetTime (&CapsuleResultVariableHeader->CapsuleProcessed, NULL);
- CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;
-
- CapsuleResultVariableFmp = (VOID *)(CapsuleResultVariable + sizeof (EFI_CAPSULE_RESULT_VARIABLE_HEADER));
- CapsuleResultVariableFmp->Version = 0x1;
- CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;
- CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;
- CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);
-
- if (CapFileName != NULL) {
- CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof (EFI_CAPSULE_RESULT_VARIABLE_FMP), CapFileName, CapFileNameSize);
- }
-
- if (DevicePathStr != NULL) {
- CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof (EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize, DevicePathStr, DevicePathStrSize);
- FreePool (DevicePathStr);
- DevicePathStr = NULL;
- }
-
- Status = EFI_SUCCESS;
- if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
- Status = WriteNewCapsuleResultVariable (CapsuleResultVariable, CapsuleResultVariableSize);
- }
-
- FreePool (CapsuleResultVariable);
- return Status;
-}
-
-/**
- Initialize CapsuleMax variables.
-
- @param[in] VariablePolicy The pointer of variable lock policy
-**/
-VOID
-InitCapsuleMaxVariable (
- EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy
- )
-{
- EFI_STATUS Status;
- UINTN Size;
- CHAR16 CapsuleMaxStr[sizeof ("Capsule####")];
-
- UnicodeSPrint (
- CapsuleMaxStr,
- sizeof (CapsuleMaxStr),
- L"Capsule%04x",
- PcdGet16 (PcdCapsuleMax)
- );
-
- Size = sizeof (L"Capsule####") - sizeof (CHAR16); // no zero terminator
- Status = gRT->SetVariable (
- L"CapsuleMax",
- &gEfiCapsuleReportGuid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- Size,
- CapsuleMaxStr
- );
- if (!EFI_ERROR (Status)) {
- // Lock it per UEFI spec.
- LockVariable (gEfiCapsuleReportGuid, L"CapsuleMax", VariablePolicy);
- }
-}
-
-/**
- Initialize CapsuleLast variables.
-
- @param[in] VariablePolicy The pointer of variable lock policy
-**/
-VOID
-InitCapsuleLastVariable (
- EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy
- )
-{
- EFI_STATUS Status;
- EFI_BOOT_MODE BootMode;
- VOID *CapsuleResult;
- UINTN Size;
- CHAR16 CapsuleLastStr[sizeof ("Capsule####")];
-
- BootMode = GetBootModeHob ();
- if (BootMode == BOOT_ON_FLASH_UPDATE) {
- Status = gRT->SetVariable (
- L"CapsuleLast",
- &gEfiCapsuleReportGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- 0,
- NULL
- );
- // Do not lock it because it will be updated later.
- } else {
- //
- // Check if OS/APP cleared L"Capsule####"
- //
- ZeroMem (CapsuleLastStr, sizeof (CapsuleLastStr));
- Size = sizeof (L"Capsule####") - sizeof (CHAR16); // no zero terminator
- Status = gRT->GetVariable (
- L"CapsuleLast",
- &gEfiCapsuleReportGuid,
- NULL,
- &Size,
- CapsuleLastStr
- );
- if (!EFI_ERROR (Status)) {
- //
- // L"CapsuleLast" is got, check if data is there.
- //
- Status = GetVariable2 (
- CapsuleLastStr,
- &gEfiCapsuleReportGuid,
- (VOID **)&CapsuleResult,
- NULL
- );
- if (EFI_ERROR (Status)) {
- //
- // If no data, delete L"CapsuleLast"
- //
- Status = gRT->SetVariable (
- L"CapsuleLast",
- &gEfiCapsuleReportGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- 0,
- NULL
- );
- } else {
- if (CapsuleResult != NULL) {
- FreePool (CapsuleResult);
- }
- }
- }
-
- // Lock it in normal boot path per UEFI spec.
- LockVariable (gEfiCapsuleReportGuid, L"CapsuleLast", VariablePolicy);
- }
-}
-
-/**
- Initialize capsule update variables.
-**/
-VOID
-InitCapsuleUpdateVariable (
- VOID
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- CHAR16 CapsuleVarName[30];
- CHAR16 *TempVarName;
-
- //
- // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
- // as early as possible which will avoid the next time boot after the capsule update
- // will still into the capsule loop
- //
- StrCpyS (CapsuleVarName, sizeof (CapsuleVarName)/sizeof (CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);
- TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
- Index = 0;
- while (TRUE) {
- if (Index > 0) {
- UnicodeValueToStringS (
- TempVarName,
- sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),
- 0,
- Index,
- 0
- );
- }
-
- Status = gRT->SetVariable (
- CapsuleVarName,
- &gEfiCapsuleVendorGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
- 0,
- (VOID *)NULL
- );
- if (EFI_ERROR (Status)) {
- //
- // There is no capsule variables, quit
- //
- break;
- }
-
- Index++;
- }
-}
-
-/**
- Initialize capsule relocation info variable.
-
- @param[in] VariablePolicy The pointer of variable lock policy
-**/
-VOID
-InitCapsuleRelocationInfo (
- EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy
- )
-{
- CoDClearCapsuleRelocationInfo ();
-
- //
- // Unlock Capsule On Disk relocation Info variable only when Capsule On Disk flag is enabled
- //
- if (!CoDCheckCapsuleOnDiskFlag ()) {
- LockVariable (gEfiCapsuleVendorGuid, COD_RELOCATION_INFO_VAR_NAME, VariablePolicy);
- }
-}
-
-/**
- Initialize capsule related variables.
-**/
-VOID
-InitCapsuleVariable (
- VOID
- )
-{
- EFI_STATUS Status;
- EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy;
-
- // Locate the VariablePolicy protocol
- Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID **)&VariablePolicy);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "DxeCapsuleReportLib %a - Could not locate VariablePolicy protocol! %r\n", __func__, Status));
- ASSERT_EFI_ERROR (Status);
- }
-
- InitCapsuleUpdateVariable ();
- InitCapsuleMaxVariable (VariablePolicy);
- InitCapsuleLastVariable (VariablePolicy);
- InitCapsuleRelocationInfo (VariablePolicy);
-
- //
- // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
- // to check status and delete them.
- //
-}
+/** @file
+ DXE capsule report related function.
+
+ Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/CapsuleReport.h>
+#include <Guid/FmpCapsule.h>
+#include <Guid/CapsuleVendor.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/PrintLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/VariablePolicyHelperLib.h>
+
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+/**
+ This routine is called to clear CapsuleOnDisk Relocation Info variable.
+ Total Capsule On Disk length is recorded in this variable
+
+ @retval EFI_SUCCESS Capsule On Disk flags are cleared
+
+**/
+EFI_STATUS
+CoDClearCapsuleRelocationInfo (
+ VOID
+ );
+
+/**
+ Get current capsule last variable index.
+
+ @return Current capsule last variable index.
+ @retval -1 No current capsule last variable.
+**/
+INTN
+GetCurrentCapsuleLastIndex (
+ VOID
+ )
+{
+ UINTN Size;
+ CHAR16 CapsuleLastStr[sizeof ("Capsule####")];
+ EFI_STATUS Status;
+ UINT16 CurrentIndex;
+
+ Size = sizeof (L"Capsule####") - sizeof (CHAR16); // no zero terminator
+ Status = gRT->GetVariable (
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ NULL,
+ &Size,
+ CapsuleLastStr
+ );
+ if (EFI_ERROR (Status)) {
+ return -1;
+ }
+
+ CurrentIndex = (UINT16)StrHexToUintn (&CapsuleLastStr[sizeof ("Capsule") - 1]);
+ return CurrentIndex;
+}
+
+/**
+ Get a new capsule status variable index.
+
+ @return A new capsule status variable index.
+ @retval 0 No new capsule status variable index. Rolling over.
+**/
+INTN
+GetNewCapsuleResultIndex (
+ VOID
+ )
+{
+ INTN CurrentIndex;
+
+ CurrentIndex = GetCurrentCapsuleLastIndex ();
+ if (CurrentIndex >= PcdGet16 (PcdCapsuleMax)) {
+ DEBUG ((DEBUG_INFO, " CapsuleResult variable Rolling Over!\n"));
+ return 0;
+ }
+
+ return CurrentIndex + 1;
+}
+
+/**
+ Lock Variable by variable policy.
+
+ @param[in] VariableGuid The Guid of the variable to be locked
+ @param[in] VariableName The name of the variable to be locked
+ @param[in] VariablePolicy The pointer of variable lock policy
+**/
+VOID
+LockVariable (
+ IN CONST EFI_GUID VariableGuid,
+ IN CHAR16 *VariableName,
+ IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy
+ )
+{
+ EFI_STATUS Status;
+
+ // Set the policies to protect the target variables
+ Status = RegisterBasicVariablePolicy (
+ VariablePolicy,
+ &VariableGuid,
+ VariableName,
+ VARIABLE_POLICY_NO_MIN_SIZE,
+ VARIABLE_POLICY_NO_MAX_SIZE,
+ VARIABLE_POLICY_NO_MUST_ATTR,
+ VARIABLE_POLICY_NO_CANT_ATTR,
+ VARIABLE_POLICY_TYPE_LOCK_NOW
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "DxeCapsuleLibFmp: Failed to lock variable %g %s. Status = %r\n",
+ &VariableGuid,
+ VariableName,
+ Status
+ ));
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Write a new capsule status variable.
+
+ @param[in] CapsuleResult The capsule status variable
+ @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+WriteNewCapsuleResultVariable (
+ IN VOID *CapsuleResult,
+ IN UINTN CapsuleResultSize
+ )
+{
+ INTN CapsuleResultIndex;
+ CHAR16 CapsuleResultStr[sizeof ("Capsule####")];
+ UINTN Size;
+ EFI_STATUS Status;
+
+ CapsuleResultIndex = GetNewCapsuleResultIndex ();
+ DEBUG ((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex));
+
+ UnicodeSPrint (
+ CapsuleResultStr,
+ sizeof (CapsuleResultStr),
+ L"Capsule%04x",
+ CapsuleResultIndex
+ );
+
+ Status = gRT->SetVariable (
+ CapsuleResultStr,
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ CapsuleResultSize,
+ CapsuleResult
+ );
+ if (!EFI_ERROR (Status)) {
+ Size = sizeof (L"Capsule####") - sizeof (CHAR16); // no zero terminator
+ DEBUG ((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));
+ Status = gRT->SetVariable (
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ CapsuleResultStr
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Record capsule status variable and to local cache.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus
+ )
+{
+ EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable;
+ EFI_STATUS Status;
+
+ CapsuleResultVariable.VariableTotalSize = sizeof (CapsuleResultVariable);
+ CapsuleResultVariable.Reserved = 0;
+ CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);
+ ZeroMem (&CapsuleResultVariable.CapsuleProcessed, sizeof (CapsuleResultVariable.CapsuleProcessed));
+ gRT->GetTime (&CapsuleResultVariable.CapsuleProcessed, NULL);
+ CapsuleResultVariable.CapsuleStatus = CapsuleStatus;
+
+ Status = EFI_SUCCESS;
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+ Status = WriteNewCapsuleResultVariable (&CapsuleResultVariable, sizeof (CapsuleResultVariable));
+ }
+
+ return Status;
+}
+
+/**
+ Record FMP capsule status variable and to local cache.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+ @param[in] PayloadIndex FMP payload index
+ @param[in] ImageHeader FMP image header
+ @param[in] FmpDevicePath DevicePath associated with the FMP producer
+ @param[in] CapFileName Capsule file name
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordFmpCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus,
+ IN UINTN PayloadIndex,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL,
+ IN CHAR16 *CapFileName OPTIONAL
+ )
+{
+ EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader;
+ EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;
+ EFI_STATUS Status;
+ UINT8 *CapsuleResultVariable;
+ UINTN CapsuleResultVariableSize;
+ CHAR16 *DevicePathStr;
+ UINTN DevicePathStrSize;
+ UINTN CapFileNameSize;
+
+ DevicePathStr = NULL;
+ CapFileNameSize = sizeof (CHAR16);
+
+ if (FmpDevicePath != NULL) {
+ DevicePathStr = ConvertDevicePathToText (FmpDevicePath, FALSE, FALSE);
+ }
+
+ if (DevicePathStr != NULL) {
+ DevicePathStrSize = StrSize (DevicePathStr);
+ } else {
+ DevicePathStrSize = sizeof (CHAR16);
+ }
+
+ if (CapFileName != NULL) {
+ CapFileNameSize = StrSize (CapFileName);
+ }
+
+ //
+ // Allocate room for CapsuleFileName.
+ //
+ CapsuleResultVariableSize = sizeof (EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof (EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize + DevicePathStrSize;
+
+ CapsuleResultVariable = AllocateZeroPool (CapsuleResultVariableSize);
+ if (CapsuleResultVariable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CapsuleResultVariableHeader = (VOID *)CapsuleResultVariable;
+ CapsuleResultVariableHeader->VariableTotalSize = (UINT32)CapsuleResultVariableSize;
+ CapsuleResultVariableHeader->Reserved = 0;
+ CopyGuid (&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);
+ ZeroMem (&CapsuleResultVariableHeader->CapsuleProcessed, sizeof (CapsuleResultVariableHeader->CapsuleProcessed));
+ gRT->GetTime (&CapsuleResultVariableHeader->CapsuleProcessed, NULL);
+ CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;
+
+ CapsuleResultVariableFmp = (VOID *)(CapsuleResultVariable + sizeof (EFI_CAPSULE_RESULT_VARIABLE_HEADER));
+ CapsuleResultVariableFmp->Version = 0x1;
+ CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;
+ CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;
+ CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);
+
+ if (CapFileName != NULL) {
+ CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof (EFI_CAPSULE_RESULT_VARIABLE_FMP), CapFileName, CapFileNameSize);
+ }
+
+ if (DevicePathStr != NULL) {
+ CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof (EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize, DevicePathStr, DevicePathStrSize);
+ FreePool (DevicePathStr);
+ DevicePathStr = NULL;
+ }
+
+ Status = EFI_SUCCESS;
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+ Status = WriteNewCapsuleResultVariable (CapsuleResultVariable, CapsuleResultVariableSize);
+ }
+
+ FreePool (CapsuleResultVariable);
+ return Status;
+}
+
+/**
+ Initialize CapsuleMax variables.
+
+ @param[in] VariablePolicy The pointer of variable lock policy
+**/
+VOID
+InitCapsuleMaxVariable (
+ EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ CHAR16 CapsuleMaxStr[sizeof ("Capsule####")];
+
+ UnicodeSPrint (
+ CapsuleMaxStr,
+ sizeof (CapsuleMaxStr),
+ L"Capsule%04x",
+ PcdGet16 (PcdCapsuleMax)
+ );
+
+ Size = sizeof (L"Capsule####") - sizeof (CHAR16); // no zero terminator
+ Status = gRT->SetVariable (
+ L"CapsuleMax",
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ Size,
+ CapsuleMaxStr
+ );
+ if (!EFI_ERROR (Status)) {
+ // Lock it per UEFI spec.
+ LockVariable (gEfiCapsuleReportGuid, L"CapsuleMax", VariablePolicy);
+ }
+}
+
+/**
+ Initialize CapsuleLast variables.
+
+ @param[in] VariablePolicy The pointer of variable lock policy
+**/
+VOID
+InitCapsuleLastVariable (
+ EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ VOID *CapsuleResult;
+ UINTN Size;
+ CHAR16 CapsuleLastStr[sizeof ("Capsule####")];
+
+ BootMode = GetBootModeHob ();
+ if (BootMode == BOOT_ON_FLASH_UPDATE) {
+ Status = gRT->SetVariable (
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 0,
+ NULL
+ );
+ // Do not lock it because it will be updated later.
+ } else {
+ //
+ // Check if OS/APP cleared L"Capsule####"
+ //
+ ZeroMem (CapsuleLastStr, sizeof (CapsuleLastStr));
+ Size = sizeof (L"Capsule####") - sizeof (CHAR16); // no zero terminator
+ Status = gRT->GetVariable (
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ NULL,
+ &Size,
+ CapsuleLastStr
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // L"CapsuleLast" is got, check if data is there.
+ //
+ Status = GetVariable2 (
+ CapsuleLastStr,
+ &gEfiCapsuleReportGuid,
+ (VOID **)&CapsuleResult,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no data, delete L"CapsuleLast"
+ //
+ Status = gRT->SetVariable (
+ L"CapsuleLast",
+ &gEfiCapsuleReportGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 0,
+ NULL
+ );
+ } else {
+ if (CapsuleResult != NULL) {
+ FreePool (CapsuleResult);
+ }
+ }
+ }
+
+ // Lock it in normal boot path per UEFI spec.
+ LockVariable (gEfiCapsuleReportGuid, L"CapsuleLast", VariablePolicy);
+ }
+}
+
+/**
+ Initialize capsule update variables.
+**/
+VOID
+InitCapsuleUpdateVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ CHAR16 CapsuleVarName[30];
+ CHAR16 *TempVarName;
+
+ //
+ // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
+ // as early as possible which will avoid the next time boot after the capsule update
+ // will still into the capsule loop
+ //
+ StrCpyS (CapsuleVarName, sizeof (CapsuleVarName)/sizeof (CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+ Index = 0;
+ while (TRUE) {
+ if (Index > 0) {
+ UnicodeValueToStringS (
+ TempVarName,
+ sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),
+ 0,
+ Index,
+ 0
+ );
+ }
+
+ Status = gRT->SetVariable (
+ CapsuleVarName,
+ &gEfiCapsuleVendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ (VOID *)NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // There is no capsule variables, quit
+ //
+ break;
+ }
+
+ Index++;
+ }
+}
+
+/**
+ Initialize capsule relocation info variable.
+
+ @param[in] VariablePolicy The pointer of variable lock policy
+**/
+VOID
+InitCapsuleRelocationInfo (
+ EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy
+ )
+{
+ CoDClearCapsuleRelocationInfo ();
+
+ //
+ // Unlock Capsule On Disk relocation Info variable only when Capsule On Disk flag is enabled
+ //
+ if (!CoDCheckCapsuleOnDiskFlag ()) {
+ LockVariable (gEfiCapsuleVendorGuid, COD_RELOCATION_INFO_VAR_NAME, VariablePolicy);
+ }
+}
+
+/**
+ Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy;
+
+ // Locate the VariablePolicy protocol
+ Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID **)&VariablePolicy);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "DxeCapsuleReportLib %a - Could not locate VariablePolicy protocol! %r\n", __func__, Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ InitCapsuleUpdateVariable ();
+ InitCapsuleMaxVariable (VariablePolicy);
+ InitCapsuleLastVariable (VariablePolicy);
+ InitCapsuleRelocationInfo (VariablePolicy);
+
+ //
+ // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
+ // to check status and delete them.
+ //
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
index b425e99e67..7a94afbbbd 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
@@ -1,69 +1,69 @@
-/** @file
- DXE capsule report related function.
- Dummy function for runtime module, because CapsuleDxeRuntime
- does not need record capsule status variable.
-
- Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-#include <Protocol/FirmwareManagement.h>
-#include <Guid/FmpCapsule.h>
-#include <Library/CapsuleLib.h>
-
-/**
- Record capsule status variable and to local cache.
-
- @param[in] CapsuleHeader The capsule image header
- @param[in] CapsuleStatus The capsule process stauts
-
- @retval EFI_SUCCESS The capsule status variable is recorded.
- @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
-**/
-EFI_STATUS
-RecordCapsuleStatusVariable (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN EFI_STATUS CapsuleStatus
- )
-{
- return EFI_UNSUPPORTED;
-}
-
-/**
- Record FMP capsule status variable and to local cache.
-
- @param[in] CapsuleHeader The capsule image header
- @param[in] CapsuleStatus The capsule process stauts
- @param[in] PayloadIndex FMP payload index
- @param[in] ImageHeader FMP image header
- @param[in] FmpDevicePath DevicePath associated with the FMP producer
- @param[in] CapFileName Capsule file name
-
- @retval EFI_SUCCESS The capsule status variable is recorded.
- @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
-**/
-EFI_STATUS
-RecordFmpCapsuleStatusVariable (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN EFI_STATUS CapsuleStatus,
- IN UINTN PayloadIndex,
- IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
- IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL,
- IN CHAR16 *CapFileName OPTIONAL
- )
-{
- return EFI_UNSUPPORTED;
-}
-
-/**
- Initialize capsule related variables.
-**/
-VOID
-InitCapsuleVariable (
- VOID
- )
-{
- return;
-}
+/** @file
+ DXE capsule report related function.
+ Dummy function for runtime module, because CapsuleDxeRuntime
+ does not need record capsule status variable.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/FmpCapsule.h>
+#include <Library/CapsuleLib.h>
+
+/**
+ Record capsule status variable and to local cache.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Record FMP capsule status variable and to local cache.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+ @param[in] PayloadIndex FMP payload index
+ @param[in] ImageHeader FMP image header
+ @param[in] FmpDevicePath DevicePath associated with the FMP producer
+ @param[in] CapFileName Capsule file name
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordFmpCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus,
+ IN UINTN PayloadIndex,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL,
+ IN CHAR16 *CapFileName OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable (
+ VOID
+ )
+{
+ return;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c
index 44f30c16c2..6b847a5c44 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c
@@ -1,174 +1,174 @@
-/** @file
- Capsule library runtime support.
-
- Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-
-#include <Guid/FmpCapsule.h>
-#include <Guid/SystemResourceTable.h>
-#include <Guid/EventGroup.h>
-
-#include <Library/BaseLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/DxeServicesTableLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiRuntimeServicesTableLib.h>
-#include <Library/MemoryAllocationLib.h>
-
-extern EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable;
-EFI_EVENT mDxeRuntimeCapsuleLibVirtualAddressChangeEvent = NULL;
-EFI_EVENT mDxeRuntimeCapsuleLibReadyToBootEvent = NULL;
-
-/**
- Convert EsrtTable physical address to virtual address.
-
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context The pointer to the notification function's context, which
- is implementation-dependent.
-**/
-VOID
-EFIAPI
-DxeCapsuleLibVirtualAddressChangeEvent (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- gRT->ConvertPointer (EFI_OPTIONAL_PTR, (VOID **)&mEsrtTable);
-}
-
-/**
- Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT.
-
- @param[in] Event The Event that is being processed.
- @param[in] Context The Event Context.
-
-**/
-STATIC
-VOID
-EFIAPI
-DxeCapsuleLibReadyToBootEventNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- UINTN Index;
- EFI_CONFIGURATION_TABLE *ConfigEntry;
- EFI_SYSTEM_RESOURCE_TABLE *EsrtTable;
-
- //
- // Get Esrt table first
- //
- ConfigEntry = gST->ConfigurationTable;
- for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
- if (CompareGuid (&gEfiSystemResourceTableGuid, &ConfigEntry->VendorGuid)) {
- break;
- }
-
- ConfigEntry++;
- }
-
- //
- // If no Esrt table installed in Configure Table
- //
- if (Index < gST->NumberOfTableEntries) {
- //
- // Search Esrt to check given capsule is qualified
- //
- EsrtTable = (EFI_SYSTEM_RESOURCE_TABLE *)ConfigEntry->VendorTable;
-
- mEsrtTable = AllocateRuntimeCopyPool (
- sizeof (EFI_SYSTEM_RESOURCE_TABLE) +
- EsrtTable->FwResourceCount * sizeof (EFI_SYSTEM_RESOURCE_ENTRY),
- EsrtTable
- );
- ASSERT (mEsrtTable != NULL);
-
- //
- // Set FwResourceCountMax to a sane value.
- //
- mEsrtTable->FwResourceCountMax = mEsrtTable->FwResourceCount;
- }
-}
-
-/**
- The constructor function hook VirtualAddressChange event to use ESRT table as capsule routing table.
-
- @param ImageHandle The firmware allocated handle for the EFI image.
- @param SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The constructor successfully .
-**/
-EFI_STATUS
-EFIAPI
-DxeRuntimeCapsuleLibConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- //
- // Make sure we can handle virtual address changes.
- //
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- DxeCapsuleLibVirtualAddressChangeEvent,
- NULL,
- &gEfiEventVirtualAddressChangeGuid,
- &mDxeRuntimeCapsuleLibVirtualAddressChangeEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register notify function to cache the FMP capsule GUIDs at ReadyToBoot.
- //
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- DxeCapsuleLibReadyToBootEventNotify,
- NULL,
- &gEfiEventReadyToBootGuid,
- &mDxeRuntimeCapsuleLibReadyToBootEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- return EFI_SUCCESS;
-}
-
-/**
- The destructor function closes the VirtualAddressChange event.
-
- @param ImageHandle The firmware allocated handle for the EFI image.
- @param SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The destructor completed successfully.
-**/
-EFI_STATUS
-EFIAPI
-DxeRuntimeCapsuleLibDestructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- //
- // Close the VirtualAddressChange event.
- //
- Status = gBS->CloseEvent (mDxeRuntimeCapsuleLibVirtualAddressChangeEvent);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Close the ReadyToBoot event.
- //
- Status = gBS->CloseEvent (mDxeRuntimeCapsuleLibReadyToBootEvent);
- ASSERT_EFI_ERROR (Status);
-
- return EFI_SUCCESS;
-}
+/** @file
+ Capsule library runtime support.
+
+ Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/FmpCapsule.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+extern EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable;
+EFI_EVENT mDxeRuntimeCapsuleLibVirtualAddressChangeEvent = NULL;
+EFI_EVENT mDxeRuntimeCapsuleLibReadyToBootEvent = NULL;
+
+/**
+ Convert EsrtTable physical address to virtual address.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+DxeCapsuleLibVirtualAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ gRT->ConvertPointer (EFI_OPTIONAL_PTR, (VOID **)&mEsrtTable);
+}
+
+/**
+ Notify function for event group EFI_EVENT_GROUP_READY_TO_BOOT.
+
+ @param[in] Event The Event that is being processed.
+ @param[in] Context The Event Context.
+
+**/
+STATIC
+VOID
+EFIAPI
+DxeCapsuleLibReadyToBootEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+ EFI_CONFIGURATION_TABLE *ConfigEntry;
+ EFI_SYSTEM_RESOURCE_TABLE *EsrtTable;
+
+ //
+ // Get Esrt table first
+ //
+ ConfigEntry = gST->ConfigurationTable;
+ for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&gEfiSystemResourceTableGuid, &ConfigEntry->VendorGuid)) {
+ break;
+ }
+
+ ConfigEntry++;
+ }
+
+ //
+ // If no Esrt table installed in Configure Table
+ //
+ if (Index < gST->NumberOfTableEntries) {
+ //
+ // Search Esrt to check given capsule is qualified
+ //
+ EsrtTable = (EFI_SYSTEM_RESOURCE_TABLE *)ConfigEntry->VendorTable;
+
+ mEsrtTable = AllocateRuntimeCopyPool (
+ sizeof (EFI_SYSTEM_RESOURCE_TABLE) +
+ EsrtTable->FwResourceCount * sizeof (EFI_SYSTEM_RESOURCE_ENTRY),
+ EsrtTable
+ );
+ ASSERT (mEsrtTable != NULL);
+
+ //
+ // Set FwResourceCountMax to a sane value.
+ //
+ mEsrtTable->FwResourceCountMax = mEsrtTable->FwResourceCount;
+ }
+}
+
+/**
+ The constructor function hook VirtualAddressChange event to use ESRT table as capsule routing table.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor successfully .
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimeCapsuleLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Make sure we can handle virtual address changes.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ DxeCapsuleLibVirtualAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mDxeRuntimeCapsuleLibVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register notify function to cache the FMP capsule GUIDs at ReadyToBoot.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DxeCapsuleLibReadyToBootEventNotify,
+ NULL,
+ &gEfiEventReadyToBootGuid,
+ &mDxeRuntimeCapsuleLibReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function closes the VirtualAddressChange event.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimeCapsuleLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Close the VirtualAddressChange event.
+ //
+ Status = gBS->CloseEvent (mDxeRuntimeCapsuleLibVirtualAddressChangeEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Close the ReadyToBoot event.
+ //
+ Status = gBS->CloseEvent (mDxeRuntimeCapsuleLibReadyToBootEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
index bf56f4623f..f9e0a97b57 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
@@ -1,74 +1,74 @@
-## @file
-# Capsule library instance for DXE_RUNTIME_DRIVER.
-#
-# Capsule library instance for DXE_RUNTIME_DRIVER module types.
-#
-# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-[Defines]
- INF_VERSION = 0x00010005
- BASE_NAME = DxeRuntimeCapsuleLib
- MODULE_UNI_FILE = DxeRuntimeCapsuleLib.uni
- FILE_GUID = 19BE1E4B-1A9A-44c1-8F12-32DD0470516A
- MODULE_TYPE = DXE_RUNTIME_DRIVER
- VERSION_STRING = 1.0
- LIBRARY_CLASS = CapsuleLib|DXE_RUNTIME_DRIVER
- CONSTRUCTOR = DxeCapsuleLibConstructor
- CONSTRUCTOR = DxeRuntimeCapsuleLibConstructor
- DESTRUCTOR = DxeCapsuleLibDestructor
- DESTRUCTOR = DxeRuntimeCapsuleLibDestructor
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-# VALID_ARCHITECTURES = IA32 X64 EBC
-#
-
-[Sources]
- DxeCapsuleLib.c
- DxeCapsuleProcessLibNull.c
- DxeCapsuleReportLibNull.c
- DxeCapsuleRuntime.c
-
-[Packages]
- MdePkg/MdePkg.dec
- MdeModulePkg/MdeModulePkg.dec
-
-[LibraryClasses]
- BaseLib
- BaseMemoryLib
- DebugLib
- MemoryAllocationLib
- DxeServicesTableLib
- UefiBootServicesTableLib
- DevicePathLib
- ReportStatusCodeLib
- PrintLib
- HobLib
- BmpSupportLib
-
-
-[Protocols]
- gEsrtManagementProtocolGuid ## CONSUMES
- gEfiFirmwareManagementProtocolGuid ## CONSUMES
- gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
- gEdkiiFirmwareManagementProgressProtocolGuid ## SOMETIMES_CONSUMES
-
-[Guids]
- gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
- gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
- gEfiSystemResourceTableGuid ## SOMETIMES_CONSUMES ## GUID
- ## SOMETIMES_CONSUMES ## Variable:L"CapsuleMax"
- ## SOMETIMES_PRODUCES ## Variable:L"CapsuleMax"
- gEfiCapsuleReportGuid
- gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData"
- gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
- gEfiEventReadyToBootGuid ## CONSUMES ## Event
- gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
- gEdkiiCapsuleOnDiskNameGuid ## SOMETIMES_CONSUMES ## GUID
-
-[Depex]
- gEfiVariableWriteArchProtocolGuid
+## @file
+# Capsule library instance for DXE_RUNTIME_DRIVER.
+#
+# Capsule library instance for DXE_RUNTIME_DRIVER module types.
+#
+# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeRuntimeCapsuleLib
+ MODULE_UNI_FILE = DxeRuntimeCapsuleLib.uni
+ FILE_GUID = 19BE1E4B-1A9A-44c1-8F12-32DD0470516A
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CapsuleLib|DXE_RUNTIME_DRIVER
+ CONSTRUCTOR = DxeCapsuleLibConstructor
+ CONSTRUCTOR = DxeRuntimeCapsuleLibConstructor
+ DESTRUCTOR = DxeCapsuleLibDestructor
+ DESTRUCTOR = DxeRuntimeCapsuleLibDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeCapsuleLib.c
+ DxeCapsuleProcessLibNull.c
+ DxeCapsuleReportLibNull.c
+ DxeCapsuleRuntime.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ DxeServicesTableLib
+ UefiBootServicesTableLib
+ DevicePathLib
+ ReportStatusCodeLib
+ PrintLib
+ HobLib
+ BmpSupportLib
+
+
+[Protocols]
+ gEsrtManagementProtocolGuid ## CONSUMES
+ gEfiFirmwareManagementProtocolGuid ## CONSUMES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiFirmwareManagementProgressProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
+ gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiSystemResourceTableGuid ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## Variable:L"CapsuleMax"
+ ## SOMETIMES_PRODUCES ## Variable:L"CapsuleMax"
+ gEfiCapsuleReportGuid
+ gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData"
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEfiEventReadyToBootGuid ## CONSUMES ## Event
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEdkiiCapsuleOnDiskNameGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Depex]
+ gEfiVariableWriteArchProtocolGuid
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni
index 0e90cc3d0e..dac12f1878 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni
@@ -1,16 +1,16 @@
-// /** @file
-// Capsule library instance for DXE_RUNTIME_DRIVER.
-//
-// Capsule library instance for DXE_RUNTIME_DRIVER module types.
-//
-// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
-//
-// SPDX-License-Identifier: BSD-2-Clause-Patent
-//
-// **/
-
-
-#string STR_MODULE_ABSTRACT #language en-US "Capsule Support Library"
-
-#string STR_MODULE_DESCRIPTION #language en-US "Capsule library instance for DXE_RUNTIME_DRIVER module types."
-
+// /** @file
+// Capsule library instance for DXE_RUNTIME_DRIVER.
+//
+// Capsule library instance for DXE_RUNTIME_DRIVER module types.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Capsule Support Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Capsule library instance for DXE_RUNTIME_DRIVER module types."
+