+++ /dev/null
-/** @file\r
- The implementation supports Capusle on Disk.\r
-\r
- Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "CapsuleOnDisk.h"\r
-\r
-/**\r
- Return if this capsule is a capsule name capsule, based upon CapsuleHeader.\r
-\r
- @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
-\r
- @retval TRUE It is a capsule name capsule.\r
- @retval FALSE It is not a capsule name capsule.\r
-**/\r
-BOOLEAN\r
-IsCapsuleNameCapsule (\r
- IN EFI_CAPSULE_HEADER *CapsuleHeader\r
- );\r
-\r
-/**\r
- Check the integrity of the capsule name capsule.\r
- If the capsule is vaild, return the physical address of each capsule name string.\r
-\r
- @param[in] CapsuleHeader Pointer to the capsule header of a capsule name capsule.\r
- @param[out] CapsuleNameNum Number of capsule name.\r
-\r
- @retval NULL Capsule name capsule is not valid.\r
- @retval CapsuleNameBuf Array of capsule name physical address.\r
-\r
-**/\r
-EFI_PHYSICAL_ADDRESS *\r
-ValidateCapsuleNameCapsuleIntegrity (\r
- IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
- OUT UINTN *CapsuleNameNum\r
- )\r
-{\r
- UINT8 *CapsuleNamePtr;\r
- UINT8 *CapsuleNameBufStart;\r
- UINT8 *CapsuleNameBufEnd;\r
- UINTN Index;\r
- UINTN StringSize;\r
- EFI_PHYSICAL_ADDRESS *CapsuleNameBuf;\r
-\r
- if (!IsCapsuleNameCapsule (CapsuleHeader)) {\r
- return NULL;\r
- }\r
-\r
- //\r
- // Total string size must be even.\r
- //\r
- if (((CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize) & BIT0) != 0) {\r
- return NULL;\r
- }\r
-\r
- *CapsuleNameNum = 0;\r
- Index = 0;\r
- CapsuleNameBufStart = (UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize;\r
-\r
- //\r
- // If strings are not aligned on a 16-bit boundary, reallocate memory for it.\r
- //\r
- if (((UINTN) CapsuleNameBufStart & BIT0) != 0) {\r
- CapsuleNameBufStart = AllocateCopyPool (CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize, CapsuleNameBufStart);\r
- }\r
-\r
- CapsuleNameBufEnd = CapsuleNameBufStart + CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;\r
-\r
- CapsuleNamePtr = CapsuleNameBufStart;\r
- while (CapsuleNamePtr < CapsuleNameBufEnd) {\r
- StringSize= StrnSizeS ((CHAR16 *) CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof(CHAR16));\r
- CapsuleNamePtr += StringSize;\r
- (*CapsuleNameNum) ++;\r
- }\r
-\r
- //\r
- // Integrity check.\r
- //\r
- if (CapsuleNamePtr != CapsuleNameBufEnd) {\r
- if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {\r
- FreePool (CapsuleNameBufStart);\r
- }\r
- return NULL;\r
- }\r
-\r
- CapsuleNameBuf = AllocatePool (*CapsuleNameNum * sizeof (EFI_PHYSICAL_ADDRESS));\r
- if (CapsuleNameBuf == NULL) {\r
- if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize) {\r
- FreePool (CapsuleNameBufStart);\r
- }\r
- return NULL;\r
- }\r
-\r
- CapsuleNamePtr = CapsuleNameBufStart;\r
- while (CapsuleNamePtr < CapsuleNameBufEnd) {\r
- StringSize= StrnSizeS ((CHAR16 *) CapsuleNamePtr, (CapsuleNameBufEnd - CapsuleNamePtr)/sizeof(CHAR16));\r
- CapsuleNameBuf[Index] = (EFI_PHYSICAL_ADDRESS)(UINTN) CapsuleNamePtr;\r
- CapsuleNamePtr += StringSize;\r
- Index ++;\r
- }\r
-\r
- return CapsuleNameBuf;\r
-}\r
-\r
-/**\r
- This routine is called to upper case given unicode string.\r
-\r
- @param[in] Str String to upper case\r
-\r
- @retval upper cased string after process\r
-\r
-**/\r
-static\r
-CHAR16 *\r
-UpperCaseString (\r
- IN CHAR16 *Str\r
- )\r
-{\r
- CHAR16 *Cptr;\r
-\r
- for (Cptr = Str; *Cptr; Cptr++) {\r
- if (L'a' <= *Cptr && *Cptr <= L'z') {\r
- *Cptr = *Cptr - L'a' + L'A';\r
- }\r
- }\r
-\r
- return Str;\r
-}\r
-\r
-/**\r
- This routine is used to return substring before period '.' or '\0'\r
- Caller should respsonsible of substr space allocation & free\r
-\r
- @param[in] Str String to check\r
- @param[out] SubStr First part of string before period or '\0'\r
- @param[out] SubStrLen Length of first part of string\r
-\r
-**/\r
-static\r
-VOID\r
-GetSubStringBeforePeriod (\r
- IN CHAR16 *Str,\r
- OUT CHAR16 *SubStr,\r
- OUT UINTN *SubStrLen\r
- )\r
-{\r
- UINTN Index;\r
- for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {\r
- SubStr[Index] = Str[Index];\r
- }\r
-\r
- SubStr[Index] = L'\0';\r
- *SubStrLen = Index;\r
-}\r
-\r
-/**\r
- This routine pad the string in tail with input character.\r
-\r
- @param[in] StrBuf Str buffer to be padded, should be enough room for\r
- @param[in] PadLen Expected padding length\r
- @param[in] Character Character used to pad\r
-\r
-**/\r
-static\r
-VOID\r
-PadStrInTail (\r
- IN CHAR16 *StrBuf,\r
- IN UINTN PadLen,\r
- IN CHAR16 Character\r
- )\r
-{\r
- UINTN Index;\r
-\r
- for (Index = 0; StrBuf[Index] != L'\0'; Index++);\r
-\r
- while(PadLen != 0) {\r
- StrBuf[Index] = Character;\r
- Index++;\r
- PadLen--;\r
- }\r
-\r
- StrBuf[Index] = L'\0';\r
-}\r
-\r
-/**\r
- This routine find the offset of the last period '.' of string. If No period exists\r
- function FileNameExtension is set to L'\0'\r
-\r
- @param[in] FileName File name to split between last period\r
- @param[out] FileNameFirst First FileName before last period\r
- @param[out] FileNameExtension FileName after last period\r
-\r
-**/\r
-static\r
-VOID\r
-SplitFileNameExtension (\r
- IN CHAR16 *FileName,\r
- OUT CHAR16 *FileNameFirst,\r
- OUT CHAR16 *FileNameExtension\r
- )\r
-{\r
- UINTN Index;\r
- UINTN StringLen;\r
-\r
- StringLen = StrnLenS(FileName, MAX_FILE_NAME_SIZE);\r
- for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--);\r
-\r
- //\r
- // No period exists. No FileName Extension\r
- //\r
- if (Index == 0 && FileName[Index] != L'.') {\r
- FileNameExtension[0] = L'\0';\r
- Index = StringLen;\r
- } else {\r
- StrCpyS(FileNameExtension, MAX_FILE_NAME_SIZE, &FileName[Index+1]);\r
- }\r
-\r
- //\r
- // Copy First file name\r
- //\r
- StrnCpyS(FileNameFirst, MAX_FILE_NAME_SIZE, FileName, Index);\r
- FileNameFirst[Index] = L'\0';\r
-}\r
-\r
-/**\r
- This routine is called to get all boot options in the order determnined by:\r
- 1. "OptionBuf"\r
- 2. "BootOrder"\r
-\r
- @param[out] OptionBuf BootList buffer to all boot options returned\r
- @param[out] OptionCount BootList count of all boot options returned\r
-\r
- @retval EFI_SUCCESS There is no error when processing capsule\r
-\r
-**/\r
-EFI_STATUS\r
-GetBootOptionInOrder(\r
- OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf,\r
- OUT UINTN *OptionCount\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN DataSize;\r
- UINT16 BootNext;\r
- CHAR16 BootOptionName[20];\r
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOrderOptionBuf;\r
- UINTN BootOrderCount;\r
- EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry;\r
- UINTN BootNextCount;\r
- EFI_BOOT_MANAGER_LOAD_OPTION *TempBuf;\r
-\r
- BootOrderOptionBuf = NULL;\r
- TempBuf = NULL;\r
- BootNextCount = 0;\r
- BootOrderCount = 0;\r
- *OptionBuf = NULL;\r
- *OptionCount = 0;\r
-\r
- //\r
- // First Get BootOption from "BootNext"\r
- //\r
- DataSize = sizeof(BootNext);\r
- Status = gRT->GetVariable (\r
- EFI_BOOT_NEXT_VARIABLE_NAME,\r
- &gEfiGlobalVariableGuid,\r
- NULL,\r
- &DataSize,\r
- (VOID *)&BootNext\r
- );\r
- //\r
- // BootNext variable is a single UINT16\r
- //\r
- if (!EFI_ERROR(Status) && DataSize == sizeof(UINT16)) {\r
- //\r
- // Add the boot next boot option\r
- //\r
- UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootNext);\r
- ZeroMem(&BootNextOptionEntry, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION));\r
- Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);\r
-\r
- if (!EFI_ERROR(Status)) {\r
- BootNextCount = 1;\r
- }\r
- }\r
-\r
- //\r
- // Second get BootOption from "BootOrder"\r
- //\r
- BootOrderOptionBuf = EfiBootManagerGetLoadOptions (&BootOrderCount, LoadOptionTypeBoot);\r
- if (BootNextCount == 0 && BootOrderCount == 0) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // At least one BootOption is found\r
- //\r
- TempBuf = AllocatePool(sizeof(EFI_BOOT_MANAGER_LOAD_OPTION) * (BootNextCount + BootOrderCount));\r
- if (TempBuf != NULL) {\r
- if (BootNextCount == 1) {\r
- CopyMem(TempBuf, &BootNextOptionEntry, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION));\r
- }\r
-\r
- if (BootOrderCount > 0) {\r
- CopyMem(TempBuf + BootNextCount, BootOrderOptionBuf, sizeof(EFI_BOOT_MANAGER_LOAD_OPTION) * BootOrderCount);\r
- }\r
-\r
- *OptionBuf = TempBuf;\r
- *OptionCount = BootNextCount + BootOrderCount;\r
- Status = EFI_SUCCESS;\r
- } else {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- FreePool(BootOrderOptionBuf);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- This routine is called to get boot option by OptionNumber.\r
-\r
- @param[in] Number The OptionNumber of boot option\r
- @param[out] OptionBuf BootList buffer to all boot options returned\r
-\r
- @retval EFI_SUCCESS There is no error when getting boot option\r
-\r
-**/\r
-EFI_STATUS\r
-GetBootOptionByNumber(\r
- IN UINT16 Number,\r
- OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf\r
- )\r
-{\r
- EFI_STATUS Status;\r
- CHAR16 BootOptionName[20];\r
- EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
-\r
- UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", Number);\r
- ZeroMem (&BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
- Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootOption);\r
-\r
- if (!EFI_ERROR (Status)) {\r
- *OptionBuf = AllocatePool (sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
- CopyMem (*OptionBuf, &BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
- return EFI_SUCCESS;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Get Active EFI System Partition within GPT based on device path.\r
-\r
- @param[in] DevicePath Device path to find a active EFI System Partition\r
- @param[out] FsHandle BootList points to all boot options returned\r
-\r
- @retval EFI_SUCCESS Active EFI System Partition is succesfully found\r
- @retval EFI_NOT_FOUND No Active EFI System Partition is found\r
-\r
-**/\r
-EFI_STATUS\r
-GetEfiSysPartitionFromDevPath(\r
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
- OUT EFI_HANDLE *FsHandle\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
- HARDDRIVE_DEVICE_PATH *Hd;\r
- EFI_HANDLE Handle;\r
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
-\r
- //\r
- // Check if the device path contains GPT node\r
- //\r
- TempDevicePath = DevicePath;\r
- while (!IsDevicePathEnd (TempDevicePath)) {\r
- if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&\r
- (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) {\r
- Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;\r
- if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {\r
- break;\r
- }\r
- }\r
- TempDevicePath = NextDevicePathNode (TempDevicePath);\r
- }\r
-\r
- if (!IsDevicePathEnd (TempDevicePath)) {\r
- //\r
- // Search for EFI system partition protocol on full device path in Boot Option\r
- //\r
- Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);\r
-\r
- //\r
- // Search for simple file system on this handler\r
- //\r
- if (!EFI_ERROR(Status)) {\r
- Status = gBS->HandleProtocol(Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);\r
- if (!EFI_ERROR(Status)) {\r
- *FsHandle = Handle;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- This routine is called to get Simple File System protocol on the first EFI system partition found in\r
- active boot option. The boot option list is detemined in order by\r
- 1. "BootNext"\r
- 2. "BootOrder"\r
-\r
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
- device like USB can get enumerated.\r
- @param[in, out] LoadOptionNumber On input, specify the boot option to get EFI system partition.\r
- On output, return the OptionNumber of the boot option where EFI\r
- system partition is got from.\r
- @param[out] FsFsHandle Simple File System Protocol found on first active EFI system partition\r
-\r
- @retval EFI_SUCCESS Simple File System protocol found for EFI system partition\r
- @retval EFI_NOT_FOUND No Simple File System protocol found for EFI system partition\r
-\r
-**/\r
-EFI_STATUS\r
-GetEfiSysPartitionFromActiveBootOption(\r
- IN UINTN MaxRetry,\r
- IN OUT UINT16 **LoadOptionNumber,\r
- OUT EFI_HANDLE *FsHandle\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuf;\r
- UINTN BootOptionNum;\r
- UINTN Index;\r
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
- EFI_DEVICE_PATH_PROTOCOL *CurFullPath;\r
- EFI_DEVICE_PATH_PROTOCOL *PreFullPath;\r
-\r
- *FsHandle = NULL;\r
-\r
- if (*LoadOptionNumber != NULL) {\r
- BootOptionNum = 1;\r
- Status = GetBootOptionByNumber(**LoadOptionNumber, &BootOptionBuf);\r
- if (EFI_ERROR(Status)) {\r
- DEBUG ((DEBUG_ERROR, "GetBootOptionByIndex Failed %x! No BootOption available for connection\n", Status));\r
- return Status;\r
- }\r
- } else {\r
- Status = GetBootOptionInOrder(&BootOptionBuf, &BootOptionNum);\r
- if (EFI_ERROR(Status)) {\r
- DEBUG ((DEBUG_ERROR, "GetBootOptionInOrder Failed %x! No BootOption available for connection\n", Status));\r
- return Status;\r
- }\r
- }\r
-\r
- //\r
- // Search BootOptionList to check if it is an active boot option with EFI system partition\r
- // 1. Connect device path\r
- // 2. expend short/plug in devicepath\r
- // 3. LoadImage\r
- //\r
- for (Index = 0; Index < BootOptionNum; Index++) {\r
- //\r
- // Get the boot option from the link list\r
- //\r
- DevicePath = BootOptionBuf[Index].FilePath;\r
-\r
- //\r
- // Skip inactive or legacy boot options\r
- //\r
- if ((BootOptionBuf[Index].Attributes & LOAD_OPTION_ACTIVE) == 0 ||\r
- DevicePathType (DevicePath) == BBS_DEVICE_PATH) {\r
- continue;\r
- }\r
-\r
- DEBUG_CODE (\r
- CHAR16 *DevicePathStr;\r
-\r
- DevicePathStr = ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
- if (DevicePathStr != NULL){\r
- DEBUG((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));\r
- FreePool(DevicePathStr);\r
- } else {\r
- DEBUG((DEBUG_INFO, "DevicePathToStr failed\n"));\r
- }\r
- );\r
-\r
- CurFullPath = NULL;\r
- //\r
- // Try every full device Path generated from bootoption\r
- //\r
- do {\r
- PreFullPath = CurFullPath;\r
- CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath(DevicePath, CurFullPath);\r
-\r
- if (PreFullPath != NULL) {\r
- FreePool (PreFullPath);\r
- }\r
-\r
- if (CurFullPath == NULL) {\r
- //\r
- // No Active EFI system partition is found in BootOption device path\r
- //\r
- Status = EFI_NOT_FOUND;\r
- break;\r
- }\r
-\r
- DEBUG_CODE (\r
- CHAR16 *DevicePathStr1;\r
-\r
- DevicePathStr1 = ConvertDevicePathToText(CurFullPath, TRUE, TRUE);\r
- if (DevicePathStr1 != NULL){\r
- DEBUG((DEBUG_INFO, "Full device path %s\n", DevicePathStr1));\r
- FreePool(DevicePathStr1);\r
- }\r
- );\r
-\r
- //\r
- // Make sure the boot option device path connected.\r
- // Only handle first device in boot option. Other optional device paths are described as OSV specific\r
- // FullDevice could contain extra directory & file info. So don't check connection status here.\r
- //\r
- EfiBootManagerConnectDevicePath (CurFullPath, NULL);\r
- Status = GetEfiSysPartitionFromDevPath(CurFullPath, FsHandle);\r
-\r
- //\r
- // Some relocation device like USB need more time to get enumerated\r
- //\r
- while (EFI_ERROR(Status) && MaxRetry > 0) {\r
- EfiBootManagerConnectDevicePath(CurFullPath, NULL);\r
-\r
- //\r
- // Search for EFI system partition protocol on full device path in Boot Option\r
- //\r
- Status = GetEfiSysPartitionFromDevPath(CurFullPath, FsHandle);\r
- if (!EFI_ERROR(Status)) {\r
- break;\r
- }\r
- DEBUG((DEBUG_ERROR, "GetEfiSysPartitionFromDevPath Loop %x\n", Status));\r
- //\r
- // Stall 100ms if connection failed to ensure USB stack is ready\r
- //\r
- gBS->Stall(100000);\r
- MaxRetry --;\r
- }\r
- } while(EFI_ERROR(Status));\r
-\r
- //\r
- // Find a qualified Simple File System\r
- //\r
- if (!EFI_ERROR(Status)) {\r
- break;\r
- }\r
-\r
- }\r
-\r
- //\r
- // Return the OptionNumber of the boot option where EFI system partition is got from\r
- //\r
- if (*LoadOptionNumber == NULL) {\r
- *LoadOptionNumber = AllocateCopyPool (sizeof(UINT16), (UINT16 *) &BootOptionBuf[Index].OptionNumber);\r
- }\r
-\r
- //\r
- // No qualified EFI system partition found\r
- //\r
- if (*FsHandle == NULL) {\r
- Status = EFI_NOT_FOUND;\r
- }\r
-\r
- DEBUG_CODE (\r
- CHAR16 *DevicePathStr2;\r
- if (*FsHandle != NULL) {\r
- DevicePathStr2 = ConvertDevicePathToText(CurFullPath, TRUE, TRUE);\r
- if (DevicePathStr2 != NULL){\r
- DEBUG((DEBUG_INFO, "Found Active EFI System Partion on %s\n", DevicePathStr2));\r
- FreePool(DevicePathStr2);\r
- }\r
- } else {\r
- DEBUG((DEBUG_INFO, "Failed to found Active EFI System Partion\n"));\r
- }\r
- );\r
-\r
- if (CurFullPath != NULL) {\r
- FreePool(CurFullPath);\r
- }\r
-\r
- //\r
- // Free BootOption Buffer\r
- //\r
- for (Index = 0; Index < BootOptionNum; Index++) {\r
- if (BootOptionBuf[Index].Description != NULL) {\r
- FreePool(BootOptionBuf[Index].Description);\r
- }\r
-\r
- if (BootOptionBuf[Index].FilePath != NULL) {\r
- FreePool(BootOptionBuf[Index].FilePath);\r
- }\r
-\r
- if (BootOptionBuf[Index].OptionalData != NULL) {\r
- FreePool(BootOptionBuf[Index].OptionalData);\r
- }\r
- }\r
-\r
- FreePool(BootOptionBuf);\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- This routine is called to get all file infos with in a given dir & with given file attribute, the file info is listed in\r
- alphabetical order described in UEFI spec.\r
-\r
- @param[in] Dir Directory file handler\r
- @param[in] FileAttr Attribute of file to be red from directory\r
- @param[out] FileInfoList File images info list red from directory\r
- @param[out] FileNum File images number red from directory\r
-\r
- @retval EFI_SUCCESS File FileInfo list in the given\r
-\r
-**/\r
-EFI_STATUS\r
-GetFileInfoListInAlphabetFromDir(\r
- IN EFI_FILE_HANDLE Dir,\r
- IN UINT64 FileAttr,\r
- OUT LIST_ENTRY *FileInfoList,\r
- OUT UINTN *FileNum\r
- )\r
-{\r
- EFI_STATUS Status;\r
- FILE_INFO_ENTRY *NewFileInfoEntry;\r
- FILE_INFO_ENTRY *TempFileInfoEntry;\r
- EFI_FILE_INFO *FileInfo;\r
- CHAR16 *NewFileName;\r
- CHAR16 *ListedFileName;\r
- CHAR16 *NewFileNameExtension;\r
- CHAR16 *ListedFileNameExtension;\r
- CHAR16 *TempNewSubStr;\r
- CHAR16 *TempListedSubStr;\r
- LIST_ENTRY *Link;\r
- BOOLEAN NoFile;\r
- UINTN FileCount;\r
- UINTN IndexNew;\r
- UINTN IndexListed;\r
- UINTN NewSubStrLen;\r
- UINTN ListedSubStrLen;\r
- INTN SubStrCmpResult;\r
-\r
- Status = EFI_SUCCESS;\r
- NewFileName = NULL;\r
- ListedFileName = NULL;\r
- NewFileNameExtension = NULL;\r
- ListedFileNameExtension = NULL;\r
- TempNewSubStr = NULL;\r
- TempListedSubStr = NULL;\r
- NoFile = FALSE;\r
- FileCount = 0;\r
-\r
- InitializeListHead(FileInfoList);\r
-\r
- TempNewSubStr = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);\r
- TempListedSubStr = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);\r
-\r
- if (TempNewSubStr == NULL || TempListedSubStr == NULL ) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto EXIT;\r
- }\r
-\r
- for ( Status = FileHandleFindFirstFile(Dir, &FileInfo)\r
- ; !EFI_ERROR(Status) && !NoFile\r
- ; Status = FileHandleFindNextFile(Dir, FileInfo, &NoFile)\r
- ){\r
-\r
- //\r
- // Skip file with mismatching File attribute\r
- //\r
- if ((FileInfo->Attribute & (FileAttr)) == 0) {\r
- continue;\r
- }\r
-\r
- NewFileInfoEntry = NULL;\r
- NewFileInfoEntry = (FILE_INFO_ENTRY*)AllocateZeroPool(sizeof(FILE_INFO_ENTRY));\r
- if (NewFileInfoEntry == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto EXIT;\r
- }\r
- NewFileInfoEntry->Signature = FILE_INFO_SIGNATURE;\r
- NewFileInfoEntry->FileInfo = AllocateCopyPool((UINTN) FileInfo->Size, FileInfo);\r
- if (NewFileInfoEntry->FileInfo == NULL) {\r
- FreePool(NewFileInfoEntry);\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto EXIT;\r
- }\r
-\r
- NewFileInfoEntry->FileNameFirstPart = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);\r
- if (NewFileInfoEntry->FileNameFirstPart == NULL) {\r
- FreePool(NewFileInfoEntry->FileInfo);\r
- FreePool(NewFileInfoEntry);\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto EXIT;\r
- }\r
- NewFileInfoEntry->FileNameSecondPart = (CHAR16 *) AllocateZeroPool(MAX_FILE_NAME_SIZE);\r
- if (NewFileInfoEntry->FileNameSecondPart == NULL) {\r
- FreePool(NewFileInfoEntry->FileInfo);\r
- FreePool(NewFileInfoEntry->FileNameFirstPart);\r
- FreePool(NewFileInfoEntry);\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Splitter the whole New file name into 2 parts between the last period L'.' into NewFileName NewFileExtension\r
- // If no period in the whole file name. NewFileExtension is set to L'\0'\r
- //\r
- NewFileName = NewFileInfoEntry->FileNameFirstPart;\r
- NewFileNameExtension = NewFileInfoEntry->FileNameSecondPart;\r
- SplitFileNameExtension(FileInfo->FileName, NewFileName, NewFileNameExtension);\r
- UpperCaseString(NewFileName);\r
- UpperCaseString(NewFileNameExtension);\r
-\r
- //\r
- // Insert capsule file in alphabetical ordered list\r
- //\r
- for (Link = FileInfoList->ForwardLink; Link != FileInfoList; Link = Link->ForwardLink) {\r
- //\r
- // Get the FileInfo from the link list\r
- //\r
- TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
- ListedFileName = TempFileInfoEntry->FileNameFirstPart;\r
- ListedFileNameExtension = TempFileInfoEntry->FileNameSecondPart;\r
-\r
- //\r
- // Follow rule in UEFI spec 8.5.5 to compare file name\r
- //\r
- IndexListed = 0;\r
- IndexNew = 0;\r
- while (TRUE){\r
- //\r
- // First compare each substrings in NewFileName & ListedFileName between periods\r
- //\r
- GetSubStringBeforePeriod(&NewFileName[IndexNew], TempNewSubStr, &NewSubStrLen);\r
- GetSubStringBeforePeriod(&ListedFileName[IndexListed], TempListedSubStr, &ListedSubStrLen);\r
- if (NewSubStrLen > ListedSubStrLen) {\r
- //\r
- // Substr in NewFileName is longer. Pad tail with SPACE\r
- //\r
- PadStrInTail(TempListedSubStr, NewSubStrLen - ListedSubStrLen, L' ');\r
- } else if (NewSubStrLen < ListedSubStrLen){\r
- //\r
- // Substr in ListedFileName is longer. Pad tail with SPACE\r
- //\r
- PadStrInTail(TempNewSubStr, ListedSubStrLen - NewSubStrLen, L' ');\r
- }\r
-\r
- SubStrCmpResult = StrnCmp(TempNewSubStr, TempListedSubStr, MAX_FILE_NAME_LEN);\r
- if (SubStrCmpResult != 0) {\r
- break;\r
- }\r
-\r
- //\r
- // Move to skip this substring\r
- //\r
- IndexNew += NewSubStrLen;\r
- IndexListed += ListedSubStrLen;\r
- //\r
- // Reach File First Name end\r
- //\r
- if (NewFileName[IndexNew] == L'\0' || ListedFileName[IndexListed] == L'\0') {\r
- break;\r
- }\r
-\r
- //\r
- // Skip the period L'.'\r
- //\r
- IndexNew++;\r
- IndexListed++;\r
- }\r
-\r
- if (SubStrCmpResult < 0) {\r
- //\r
- // NewFileName is smaller. Find the right place to insert New file\r
- //\r
- break;\r
- } else if (SubStrCmpResult == 0) {\r
- //\r
- // 2 cases whole NewFileName is smaller than ListedFileName\r
- // 1. if NewFileName == ListedFileName. Continue to compare FileNameExtension\r
- // 2. if NewFileName is shorter than ListedFileName\r
- //\r
- if (NewFileName[IndexNew] == L'\0') {\r
- if (ListedFileName[IndexListed] != L'\0' || (StrnCmp(NewFileNameExtension, ListedFileNameExtension, MAX_FILE_NAME_LEN) < 0)) {\r
- break;\r
- }\r
- }\r
- }\r
-\r
- //\r
- // Other case, ListedFileName is smaller. Continue to compare the next file in the list\r
- //\r
- }\r
-\r
- //\r
- // If Find an entry in the list whose name is bigger than new FileInfo in alphabet order\r
- // Insert it before this entry\r
- // else\r
- // Insert at the tail of this list (Link = FileInfoList)\r
- //\r
- InsertTailList(Link, &NewFileInfoEntry->Link);\r
-\r
- FileCount++;\r
- }\r
-\r
- *FileNum = FileCount;\r
-\r
-EXIT:\r
-\r
- if (TempNewSubStr != NULL) {\r
- FreePool(TempNewSubStr);\r
- }\r
-\r
- if (TempListedSubStr != NULL) {\r
- FreePool(TempListedSubStr);\r
- }\r
-\r
- if (EFI_ERROR(Status)) {\r
- while(!IsListEmpty(FileInfoList)) {\r
- Link = FileInfoList->ForwardLink;\r
- RemoveEntryList(Link);\r
-\r
- TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
-\r
- FreePool(TempFileInfoEntry->FileInfo);\r
- FreePool(TempFileInfoEntry->FileNameFirstPart);\r
- FreePool(TempFileInfoEntry->FileNameSecondPart);\r
- FreePool(TempFileInfoEntry);\r
- }\r
- *FileNum = 0;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- This routine is called to get all qualified image from file from an given directory\r
- in alphabetic order. All the file image is copied to allocated boottime memory.\r
- Caller should free these memory\r
-\r
- @param[in] Dir Directory file handler\r
- @param[in] FileAttr Attribute of file to be red from directory\r
- @param[out] FilePtr File images Info buffer red from directory\r
- @param[out] FileNum File images number red from directory\r
-\r
- @retval EFI_SUCCESS Succeed to get all capsules in alphabetic order.\r
-\r
-**/\r
-EFI_STATUS\r
-GetFileImageInAlphabetFromDir(\r
- IN EFI_FILE_HANDLE Dir,\r
- IN UINT64 FileAttr,\r
- OUT IMAGE_INFO **FilePtr,\r
- OUT UINTN *FileNum\r
- )\r
-{\r
- EFI_STATUS Status;\r
- LIST_ENTRY *Link;\r
- EFI_FILE_HANDLE FileHandle;\r
- FILE_INFO_ENTRY *FileInfoEntry;\r
- EFI_FILE_INFO *FileInfo;\r
- UINTN FileCount;\r
- IMAGE_INFO *TempFilePtrBuf;\r
- UINTN Size;\r
- LIST_ENTRY FileInfoList;\r
-\r
- FileHandle = NULL;\r
- FileCount = 0;\r
- TempFilePtrBuf = NULL;\r
- *FilePtr = NULL;\r
-\r
- //\r
- // Get file list in Dir in alphabetical order\r
- //\r
- Status = GetFileInfoListInAlphabetFromDir(\r
- Dir,\r
- FileAttr,\r
- &FileInfoList,\r
- &FileCount\r
- );\r
- if (EFI_ERROR(Status)) {\r
- DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));\r
- goto EXIT;\r
- }\r
-\r
- if (FileCount == 0) {\r
- DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));\r
- Status = EFI_NOT_FOUND;\r
- goto EXIT;\r
- }\r
-\r
- TempFilePtrBuf = (IMAGE_INFO *)AllocateZeroPool(sizeof(IMAGE_INFO) * FileCount);\r
- if (TempFilePtrBuf == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Read all files from FileInfoList to BS memory\r
- //\r
- FileCount = 0;\r
- for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {\r
- //\r
- // Get FileInfo from the link list\r
- //\r
- FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
- FileInfo = FileInfoEntry->FileInfo;\r
-\r
- Status = Dir->Open(\r
- Dir,\r
- &FileHandle,\r
- FileInfo->FileName,\r
- EFI_FILE_MODE_READ,\r
- 0\r
- );\r
- if (EFI_ERROR(Status)){\r
- continue;\r
- }\r
-\r
- Size = (UINTN)FileInfo->FileSize;\r
- TempFilePtrBuf[FileCount].ImageAddress = AllocateZeroPool(Size);\r
- if (TempFilePtrBuf[FileCount].ImageAddress == NULL) {\r
- DEBUG((DEBUG_ERROR, "Fail to allocate memory for capsule. Stop processing the rest.\n"));\r
- break;\r
- }\r
-\r
- Status = FileHandle->Read(\r
- FileHandle,\r
- &Size,\r
- TempFilePtrBuf[FileCount].ImageAddress\r
- );\r
-\r
- FileHandle->Close(FileHandle);\r
-\r
- //\r
- // Skip read error file\r
- //\r
- if (EFI_ERROR(Status) || Size != (UINTN)FileInfo->FileSize) {\r
- //\r
- // Remove this error file info accordingly\r
- // & move Link to BackLink\r
- //\r
- Link = RemoveEntryList(Link);\r
- Link = Link->BackLink;\r
-\r
- FreePool(FileInfoEntry->FileInfo);\r
- FreePool(FileInfoEntry->FileNameFirstPart);\r
- FreePool(FileInfoEntry->FileNameSecondPart);\r
- FreePool(FileInfoEntry);\r
-\r
- FreePool(TempFilePtrBuf[FileCount].ImageAddress);\r
- TempFilePtrBuf[FileCount].ImageAddress = NULL;\r
- TempFilePtrBuf[FileCount].FileInfo = NULL;\r
-\r
- continue;\r
- }\r
- TempFilePtrBuf[FileCount].FileInfo = FileInfo;\r
- FileCount++;\r
- }\r
-\r
- DEBUG_CODE (\r
- for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link->ForwardLink) {\r
- FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
- FileInfo = FileInfoEntry->FileInfo;\r
- DEBUG((DEBUG_INFO, "Successfully read capsule file %s from disk.\n", FileInfo->FileName));\r
- }\r
- );\r
-\r
-EXIT:\r
-\r
- *FilePtr = TempFilePtrBuf;\r
- *FileNum = FileCount;\r
-\r
- //\r
- // FileInfo will be freed by Calller\r
- //\r
- while(!IsListEmpty(&FileInfoList)) {\r
- Link = FileInfoList.ForwardLink;\r
- RemoveEntryList(Link);\r
-\r
- FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
-\r
- FreePool(FileInfoEntry->FileNameFirstPart);\r
- FreePool(FileInfoEntry->FileNameSecondPart);\r
- FreePool(FileInfoEntry);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- This routine is called to remove all qualified image from file from an given directory.\r
-\r
- @param[in] Dir Directory file handler\r
- @param[in] FileAttr Attribute of files to be deleted\r
-\r
- @retval EFI_SUCCESS Succeed to remove all files from an given directory.\r
-\r
-**/\r
-EFI_STATUS\r
-RemoveFileFromDir(\r
- IN EFI_FILE_HANDLE Dir,\r
- IN UINT64 FileAttr\r
- )\r
-{\r
- EFI_STATUS Status;\r
- LIST_ENTRY *Link;\r
- LIST_ENTRY FileInfoList;\r
- EFI_FILE_HANDLE FileHandle;\r
- FILE_INFO_ENTRY *FileInfoEntry;\r
- EFI_FILE_INFO *FileInfo;\r
- UINTN FileCount;\r
-\r
- FileHandle = NULL;\r
-\r
- //\r
- // Get file list in Dir in alphabetical order\r
- //\r
- Status = GetFileInfoListInAlphabetFromDir(\r
- Dir,\r
- FileAttr,\r
- &FileInfoList,\r
- &FileCount\r
- );\r
- if (EFI_ERROR(Status)) {\r
- DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir Failed!\n"));\r
- goto EXIT;\r
- }\r
-\r
- if (FileCount == 0) {\r
- DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));\r
- Status = EFI_NOT_FOUND;\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Delete all files with given attribute in Dir\r
- //\r
- for (Link = FileInfoList.ForwardLink; Link != &(FileInfoList); Link = Link->ForwardLink) {\r
- //\r
- // Get FileInfo from the link list\r
- //\r
- FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
- FileInfo = FileInfoEntry->FileInfo;\r
-\r
- Status = Dir->Open(\r
- Dir,\r
- &FileHandle,\r
- FileInfo->FileName,\r
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,\r
- 0\r
- );\r
- if (EFI_ERROR(Status)){\r
- continue;\r
- }\r
-\r
- Status = FileHandle->Delete(FileHandle);\r
- }\r
-\r
-EXIT:\r
-\r
- while(!IsListEmpty(&FileInfoList)) {\r
- Link = FileInfoList.ForwardLink;\r
- RemoveEntryList(Link);\r
-\r
- FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link, FILE_INFO_SIGNATURE);\r
-\r
- FreePool(FileInfoEntry->FileInfo);\r
- FreePool(FileInfoEntry);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- This routine is called to get all caspules from file. The capsule file image is\r
- copied to BS memory. Caller is responsible to free them.\r
-\r
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
- devices like USB can get enumerated.\r
- @param[out] CapsulePtr Copied Capsule file Image Info buffer\r
- @param[out] CapsuleNum CapsuleNumber\r
- @param[out] FsHandle File system handle\r
- @param[out] LoadOptionNumber OptionNumber of boot option\r
-\r
- @retval EFI_SUCCESS Succeed to get all capsules.\r
-\r
-**/\r
-EFI_STATUS\r
-GetAllCapsuleOnDisk(\r
- IN UINTN MaxRetry,\r
- OUT IMAGE_INFO **CapsulePtr,\r
- OUT UINTN *CapsuleNum,\r
- OUT EFI_HANDLE *FsHandle,\r
- OUT UINT16 *LoadOptionNumber\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
- EFI_FILE_HANDLE RootDir;\r
- EFI_FILE_HANDLE FileDir;\r
- UINT16 *TempOptionNumber;\r
-\r
- Fs = NULL;\r
- RootDir = NULL;\r
- FileDir = NULL;\r
- TempOptionNumber = NULL;\r
- *CapsuleNum = 0;\r
-\r
- Status = GetEfiSysPartitionFromActiveBootOption(MaxRetry, &TempOptionNumber, FsHandle);\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
- }\r
-\r
- Status = gBS->HandleProtocol(*FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
- }\r
-\r
- Status = Fs->OpenVolume(Fs, &RootDir);\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
- }\r
-\r
- Status = RootDir->Open(\r
- RootDir,\r
- &FileDir,\r
- EFI_CAPSULE_FILE_DIRECTORY,\r
- EFI_FILE_MODE_READ,\r
- 0\r
- );\r
- if (EFI_ERROR(Status)) {\r
- DEBUG((DEBUG_ERROR, "CodLibGetAllCapsuleOnDisk fail to open RootDir!\n"));\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Only Load files with EFI_FILE_SYSTEM or EFI_FILE_ARCHIVE attribute\r
- // ignore EFI_FILE_READ_ONLY, EFI_FILE_HIDDEN, EFI_FILE_RESERVED, EFI_FILE_DIRECTORY\r
- //\r
- Status = GetFileImageInAlphabetFromDir(\r
- FileDir,\r
- EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE,\r
- CapsulePtr,\r
- CapsuleNum\r
- );\r
- DEBUG((DEBUG_INFO, "GetFileImageInAlphabetFromDir status %x\n", Status));\r
-\r
- //\r
- // Always remove file to avoid deadloop in capsule process\r
- //\r
- Status = RemoveFileFromDir(FileDir, EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE);\r
- DEBUG((DEBUG_INFO, "RemoveFileFromDir status %x\n", Status));\r
-\r
- if (LoadOptionNumber != NULL) {\r
- *LoadOptionNumber = *TempOptionNumber;\r
- }\r
-\r
-EXIT:\r
-\r
- if (FileDir != NULL) {\r
- FileDir->Close (FileDir);\r
- }\r
-\r
- if (RootDir != NULL) {\r
- RootDir->Close (RootDir);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Build Gather list for a list of capsule images.\r
-\r
- @param[in] CapsuleBuffer An array of pointer to capsule images\r
- @param[in] CapsuleSize An array of UINTN to capsule images size\r
- @param[in] CapsuleNum The count of capsule images\r
- @param[out] BlockDescriptors The block descriptors for the capsule images\r
-\r
- @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.\r
-\r
-**/\r
-EFI_STATUS\r
-BuildGatherList (\r
- IN VOID **CapsuleBuffer,\r
- IN UINTN *CapsuleSize,\r
- IN UINTN CapsuleNum,\r
- OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;\r
- EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;\r
- EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;\r
- UINTN Index;\r
-\r
- BlockDescriptors1 = NULL;\r
- BlockDescriptorPre = NULL;\r
- BlockDescriptorsHeader = NULL;\r
-\r
- for (Index = 0; Index < CapsuleNum; Index++) {\r
- //\r
- // Allocate memory for the descriptors.\r
- //\r
- BlockDescriptors1 = AllocateZeroPool (2 * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR));\r
- if (BlockDescriptors1 == NULL) {\r
- DEBUG ((DEBUG_ERROR, "BuildGatherList: failed to allocate memory for descriptors\n"));\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ERREXIT;\r
- } else {\r
- DEBUG ((DEBUG_INFO, "BuildGatherList: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1));\r
- }\r
-\r
- //\r
- // Record descirptor header\r
- //\r
- if (Index == 0) {\r
- BlockDescriptorsHeader = BlockDescriptors1;\r
- }\r
-\r
- if (BlockDescriptorPre != NULL) {\r
- BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;\r
- BlockDescriptorPre->Length = 0;\r
- }\r
-\r
- BlockDescriptors1->Union.DataBlock = (UINTN) CapsuleBuffer[Index];\r
- BlockDescriptors1->Length = CapsuleSize[Index];\r
-\r
- BlockDescriptorPre = BlockDescriptors1 + 1;\r
- BlockDescriptors1 = NULL;\r
- }\r
-\r
- //\r
- // Null-terminate.\r
- //\r
- if (BlockDescriptorPre != NULL) {\r
- BlockDescriptorPre->Union.ContinuationPointer = (UINTN)NULL;\r
- BlockDescriptorPre->Length = 0;\r
- *BlockDescriptors = BlockDescriptorsHeader;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-\r
-ERREXIT:\r
- if (BlockDescriptors1 != NULL) {\r
- FreePool (BlockDescriptors1);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- This routine is called to check if CapsuleOnDisk flag in OsIndications Variable\r
- is enabled.\r
-\r
- @retval TRUE Flag is enabled\r
- @retval FALSE Flag is not enabled\r
-\r
-**/\r
-BOOLEAN\r
-EFIAPI\r
-CoDCheckCapsuleOnDiskFlag(\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT64 OsIndication;\r
- UINTN DataSize;\r
-\r
- //\r
- // Check File Capsule Delivery Supported Flag in OsIndication variable\r
- //\r
- OsIndication = 0;\r
- DataSize = sizeof(UINT64);\r
- Status = gRT->GetVariable (\r
- EFI_OS_INDICATIONS_VARIABLE_NAME,\r
- &gEfiGlobalVariableGuid,\r
- NULL,\r
- &DataSize,\r
- &OsIndication\r
- );\r
- if (!EFI_ERROR(Status) &&\r
- (OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {\r
- return TRUE;\r
- }\r
-\r
- return FALSE;\r
-}\r
-\r
-\r
-/**\r
- This routine is called to clear CapsuleOnDisk flags including OsIndications and BootNext variable.\r
-\r
- @retval EFI_SUCCESS All Capsule On Disk flags are cleared\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoDClearCapsuleOnDiskFlag(\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT64 OsIndication;\r
- UINTN DataSize;\r
-\r
- //\r
- // Reset File Capsule Delivery Supported Flag in OsIndication variable\r
- //\r
- OsIndication = 0;\r
- DataSize = sizeof(UINT64);\r
- Status = gRT->GetVariable (\r
- EFI_OS_INDICATIONS_VARIABLE_NAME,\r
- &gEfiGlobalVariableGuid,\r
- NULL,\r
- &DataSize,\r
- &OsIndication\r
- );\r
- if (EFI_ERROR(Status) ||\r
- (OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) == 0) {\r
- return Status;\r
- }\r
-\r
- OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);\r
- Status = gRT->SetVariable (\r
- EFI_OS_INDICATIONS_VARIABLE_NAME,\r
- &gEfiGlobalVariableGuid,\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
- sizeof(UINT64),\r
- &OsIndication\r
- );\r
- ASSERT(!EFI_ERROR(Status));\r
-\r
- //\r
- // Delete BootNext variable. Capsule Process may reset system, so can't rely on Bds to clear this variable\r
- //\r
- Status = gRT->SetVariable (\r
- EFI_BOOT_NEXT_VARIABLE_NAME,\r
- &gEfiGlobalVariableGuid,\r
- 0,\r
- 0,\r
- NULL\r
- );\r
- ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This routine is called to clear CapsuleOnDisk Relocation Info variable.\r
- Total Capsule On Disk length is recorded in this variable\r
-\r
- @retval EFI_SUCCESS Capsule On Disk flags are cleared\r
-\r
-**/\r
-EFI_STATUS\r
-CoDClearCapsuleRelocationInfo(\r
- VOID\r
- )\r
-{\r
- return gRT->SetVariable (\r
- COD_RELOCATION_INFO_VAR_NAME,\r
- &gEfiCapsuleVendorGuid,\r
- 0,\r
- 0,\r
- NULL\r
- );\r
-}\r
-\r
-/**\r
- Relocate Capsule on Disk from EFI system partition to a platform-specific NV storage device\r
- with BlockIo protocol. Relocation device path, identified by PcdCodRelocationDevPath, must\r
- be a full device path.\r
- Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.\r
- Function will stall 100ms between each retry.\r
-\r
- Side Effects:\r
- Content corruption. Block IO write directly touches low level write. Orignal partitions, file systems\r
- of the relocation device will be corrupted.\r
-\r
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
- devices like USB can get enumerated.\r
-\r
- @retval EFI_SUCCESS Capsule on Disk images are sucessfully relocated to the platform-specific device.\r
-\r
-**/\r
-EFI_STATUS\r
-RelocateCapsuleToDisk(\r
- UINTN MaxRetry\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN CapsuleOnDiskNum;\r
- UINTN Index;\r
- UINTN DataSize;\r
- UINT64 TotalImageSize;\r
- UINT64 TotalImageNameSize;\r
- IMAGE_INFO *CapsuleOnDiskBuf;\r
- EFI_HANDLE Handle;\r
- EFI_HANDLE TempHandle;\r
- EFI_HANDLE *HandleBuffer;\r
- UINTN NumberOfHandles;\r
- EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
- UINT8 *CapsuleDataBuf;\r
- UINT8 *CapsulePtr;\r
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
- EFI_FILE_HANDLE RootDir;\r
- EFI_FILE_HANDLE TempCodFile;\r
- UINT64 TempCodFileSize;\r
- EFI_DEVICE_PATH *TempDevicePath;\r
- BOOLEAN RelocationInfo;\r
- UINT16 LoadOptionNumber;\r
- EFI_CAPSULE_HEADER FileNameCapsuleHeader;\r
-\r
- RootDir = NULL;\r
- TempCodFile = NULL;\r
- HandleBuffer = NULL;\r
- CapsuleDataBuf = NULL;\r
- CapsuleOnDiskBuf = NULL;\r
- NumberOfHandles = 0;\r
-\r
- DEBUG ((DEBUG_INFO, "CapsuleOnDisk RelocateCapsule Enter\n"));\r
-\r
- //\r
- // 1. Load all Capsule On Disks in to memory\r
- //\r
- Status = GetAllCapsuleOnDisk(MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, &LoadOptionNumber);\r
- if (EFI_ERROR(Status) || CapsuleOnDiskNum == 0) {\r
- DEBUG ((DEBUG_INFO, "RelocateCapsule: GetAllCapsuleOnDisk Status - 0x%x\n", Status));\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // 2. Connect platform special device path as relocation device.\r
- // If no platform special device path specified or the device path is invalid, use the EFI system partition where\r
- // stores the capsules as relocation device.\r
- //\r
- if (IsDevicePathValid ((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath), PcdGetSize(PcdCodRelocationDevPath))) {\r
- Status = EfiBootManagerConnectDevicePath ((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath), &TempHandle);\r
- if (EFI_ERROR(Status)) {\r
- DEBUG ((DEBUG_ERROR, "RelocateCapsule: EfiBootManagerConnectDevicePath Status - 0x%x\n", Status));\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Connect all the child handle. Partition & FAT drivers are allowed in this case\r
- //\r
- gBS->ConnectController (TempHandle, NULL, NULL, TRUE);\r
- Status = gBS->LocateHandleBuffer(\r
- ByProtocol,\r
- &gEfiSimpleFileSystemProtocolGuid,\r
- NULL,\r
- &NumberOfHandles,\r
- &HandleBuffer\r
- );\r
- if (EFI_ERROR(Status)) {\r
- DEBUG ((DEBUG_ERROR, "RelocateCapsule: LocateHandleBuffer Status - 0x%x\n", Status));\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Find first Simple File System Handle which can match PcdCodRelocationDevPath\r
- //\r
- for (Index = 0; Index < NumberOfHandles; Index++) {\r
- Status = gBS->HandleProtocol(HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&TempDevicePath);\r
- if (EFI_ERROR(Status)) {\r
- continue;\r
- }\r
-\r
- DataSize = GetDevicePathSize((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath)) - sizeof(EFI_DEVICE_PATH);\r
- if (0 == CompareMem((EFI_DEVICE_PATH *)PcdGetPtr(PcdCodRelocationDevPath), TempDevicePath, DataSize)) {\r
- Handle = HandleBuffer[Index];\r
- break;\r
- }\r
- }\r
-\r
- FreePool(HandleBuffer);\r
-\r
- if (Index == NumberOfHandles) {\r
- DEBUG ((DEBUG_ERROR, "RelocateCapsule: No simple file system protocol found.\n"));\r
- Status = EFI_NOT_FOUND;\r
- }\r
- }\r
-\r
- Status = gBS->HandleProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);\r
- if (EFI_ERROR(Status) || BlockIo->Media->ReadOnly) {\r
- DEBUG((DEBUG_ERROR, "Fail to find Capsule on Disk relocation BlockIo device or device is ReadOnly!\n"));\r
- goto EXIT;\r
- }\r
-\r
- Status = gBS->HandleProtocol(Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);\r
- if (EFI_ERROR(Status)) {\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Check if device used to relocate Capsule On Disk is big enough\r
- //\r
- TotalImageSize = 0;\r
- TotalImageNameSize = 0;\r
- for (Index = 0; Index < CapsuleOnDiskNum; Index++) {\r
- //\r
- // Overflow check\r
- //\r
- if (MAX_ADDRESS - (UINTN)TotalImageSize <= CapsuleOnDiskBuf[Index].FileInfo->FileSize) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto EXIT;\r
- }\r
-\r
- if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName)) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto EXIT;\r
- }\r
-\r
- TotalImageSize += CapsuleOnDiskBuf[Index].FileInfo->FileSize;\r
- TotalImageNameSize += StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName);\r
- DEBUG((DEBUG_INFO, "RelocateCapsule: %x Size %x\n",CapsuleOnDiskBuf[Index].FileInfo->FileName, CapsuleOnDiskBuf[Index].FileInfo->FileSize));\r
- }\r
-\r
- DEBUG((DEBUG_INFO, "RelocateCapsule: TotalImageSize %x\n", TotalImageSize));\r
- DEBUG((DEBUG_INFO, "RelocateCapsule: TotalImageNameSize %x\n", TotalImageNameSize));\r
-\r
- if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= sizeof(UINT64) * 2 ||\r
- MAX_ADDRESS - (UINTN)TotalImageSize <= (UINTN)TotalImageNameSize + sizeof(UINT64) * 2) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto EXIT;\r
- }\r
-\r
- TempCodFileSize = sizeof(UINT64) + TotalImageSize + sizeof(EFI_CAPSULE_HEADER) + TotalImageNameSize;\r
-\r
- //\r
- // Check if CapsuleTotalSize. There could be reminder, so use LastBlock number directly\r
- //\r
- if (DivU64x32(TempCodFileSize, BlockIo->Media->BlockSize) > BlockIo->Media->LastBlock) {\r
- DEBUG((DEBUG_ERROR, "RelocateCapsule: Relocation device isn't big enough to hold all Capsule on Disk!\n"));\r
- DEBUG((DEBUG_ERROR, "TotalImageSize = %x\n", TotalImageSize));\r
- DEBUG((DEBUG_ERROR, "TotalImageNameSize = %x\n", TotalImageNameSize));\r
- DEBUG((DEBUG_ERROR, "RelocationDev BlockSize = %x LastBlock = %x\n", BlockIo->Media->BlockSize, BlockIo->Media->LastBlock));\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto EXIT;\r
- }\r
-\r
- CapsuleDataBuf = AllocatePool((UINTN) TempCodFileSize);\r
- if (CapsuleDataBuf == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // First UINT64 reserved for total image size, including capsule name capsule.\r
- //\r
- *(UINT64 *) CapsuleDataBuf = TotalImageSize + sizeof(EFI_CAPSULE_HEADER) + TotalImageNameSize;\r
-\r
- //\r
- // Line up all the Capsule on Disk and write to relocation disk at one time. It could save some time in disk write\r
- //\r
- for (Index = 0, CapsulePtr = CapsuleDataBuf + sizeof(UINT64); Index < CapsuleOnDiskNum; Index++) {\r
- CopyMem(CapsulePtr, CapsuleOnDiskBuf[Index].ImageAddress, (UINTN) CapsuleOnDiskBuf[Index].FileInfo->FileSize);\r
- CapsulePtr += CapsuleOnDiskBuf[Index].FileInfo->FileSize;\r
- }\r
-\r
- //\r
- // Line the capsule header for capsule name capsule.\r
- //\r
- CopyGuid(&FileNameCapsuleHeader.CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);\r
- FileNameCapsuleHeader.CapsuleImageSize = (UINT32) TotalImageNameSize + sizeof(EFI_CAPSULE_HEADER);\r
- FileNameCapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
- FileNameCapsuleHeader.HeaderSize = sizeof(EFI_CAPSULE_HEADER);\r
- CopyMem(CapsulePtr, &FileNameCapsuleHeader, FileNameCapsuleHeader.HeaderSize);\r
- CapsulePtr += FileNameCapsuleHeader.HeaderSize;\r
-\r
- //\r
- // Line up all the Capsule file names.\r
- //\r
- for (Index = 0; Index < CapsuleOnDiskNum; Index++) {\r
- CopyMem(CapsulePtr, CapsuleOnDiskBuf[Index].FileInfo->FileName, StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName));\r
- CapsulePtr += StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName);\r
- }\r
-\r
- //\r
- // 5. Flash all Capsules on Disk to TempCoD.tmp under RootDir\r
- //\r
- Status = Fs->OpenVolume(Fs, &RootDir);\r
- if (EFI_ERROR(Status)) {\r
- DEBUG((DEBUG_ERROR, "RelocateCapsule: OpenVolume error. %x\n", Status));\r
- goto EXIT;\r
- }\r
-\r
- Status = RootDir->Open(\r
- RootDir,\r
- &TempCodFile,\r
- (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),\r
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,\r
- 0\r
- );\r
- if (!EFI_ERROR(Status)) {\r
- //\r
- // Error handling code to prevent malicious code to hold this file to block capsule on disk\r
- //\r
- TempCodFile->Delete(TempCodFile);\r
- }\r
- Status = RootDir->Open(\r
- RootDir,\r
- &TempCodFile,\r
- (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),\r
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,\r
- 0\r
- );\r
- if (EFI_ERROR(Status)) {\r
- DEBUG((DEBUG_ERROR, "RelocateCapsule: Open TemCoD.tmp error. %x\n", Status));\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Always write at the begining of TempCap file\r
- //\r
- DataSize = (UINTN) TempCodFileSize;\r
- Status = TempCodFile->Write(\r
- TempCodFile,\r
- &DataSize,\r
- CapsuleDataBuf\r
- );\r
- if (EFI_ERROR(Status)) {\r
- DEBUG((DEBUG_ERROR, "RelocateCapsule: Write TemCoD.tmp error. %x\n", Status));\r
- goto EXIT;\r
- }\r
-\r
- if (DataSize != TempCodFileSize) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Save Capsule On Disk relocation info to "CodRelocationInfo" Var\r
- // It is used in next reboot by TCB\r
- //\r
- RelocationInfo = TRUE;\r
- Status = gRT->SetVariable(\r
- COD_RELOCATION_INFO_VAR_NAME,\r
- &gEfiCapsuleVendorGuid,\r
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
- sizeof (BOOLEAN),\r
- &RelocationInfo\r
- );\r
- //\r
- // Save the LoadOptionNumber of the boot option, where the capsule is relocated,\r
- // into "CodRelocationLoadOption" var. It is used in next reboot after capsule is\r
- // updated out of TCB to remove the TempCoDFile.\r
- //\r
- Status = gRT->SetVariable(\r
- COD_RELOCATION_LOAD_OPTION_VAR_NAME,\r
- &gEfiCapsuleVendorGuid,\r
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
- sizeof (UINT16),\r
- &LoadOptionNumber\r
- );\r
-\r
-EXIT:\r
-\r
- if (CapsuleDataBuf != NULL) {\r
- FreePool(CapsuleDataBuf);\r
- }\r
-\r
- if (CapsuleOnDiskBuf != NULL) {\r
- //\r
- // Free resources allocated by CodLibGetAllCapsuleOnDisk\r
- //\r
- for (Index = 0; Index < CapsuleOnDiskNum; Index++ ) {\r
- FreePool(CapsuleOnDiskBuf[Index].ImageAddress);\r
- FreePool(CapsuleOnDiskBuf[Index].FileInfo);\r
- }\r
- FreePool(CapsuleOnDiskBuf);\r
- }\r
-\r
- if (TempCodFile != NULL) {\r
- if (EFI_ERROR(Status)) {\r
- TempCodFile->Delete (TempCodFile);\r
- } else {\r
- TempCodFile->Close (TempCodFile);\r
- }\r
- }\r
-\r
- if (RootDir != NULL) {\r
- RootDir->Close (RootDir);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- For the platforms that support Capsule In Ram, reuse the Capsule In Ram to deliver capsule.\r
- Relocate Capsule On Disk to memory and call UpdateCapsule().\r
- Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.\r
- Function will stall 100ms between each retry.\r
-\r
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
- devices like USB can get enumerated.\r
-\r
- @retval EFI_SUCCESS Deliver capsule through Capsule In Ram successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-RelocateCapsuleToRam (\r
- UINTN MaxRetry\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN CapsuleOnDiskNum;\r
- IMAGE_INFO *CapsuleOnDiskBuf;\r
- EFI_HANDLE Handle;\r
- EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;\r
- VOID **CapsuleBuffer;\r
- UINTN *CapsuleSize;\r
- EFI_CAPSULE_HEADER *FileNameCapsule;\r
- UINTN Index;\r
- UINT8 *StringBuf;\r
- UINTN StringSize;\r
- UINTN TotalStringSize;\r
-\r
- CapsuleOnDiskBuf = NULL;\r
- BlockDescriptors = NULL;\r
- CapsuleBuffer = NULL;\r
- CapsuleSize = NULL;\r
- FileNameCapsule = NULL;\r
- TotalStringSize = 0;\r
-\r
- //\r
- // 1. Load all Capsule On Disks into memory\r
- //\r
- Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf, &CapsuleOnDiskNum, &Handle, NULL);\r
- if (EFI_ERROR (Status) || CapsuleOnDiskNum == 0) {\r
- DEBUG ((DEBUG_ERROR, "GetAllCapsuleOnDisk Status - 0x%x\n", Status));\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- //\r
- // 2. Add a capsule for Capsule file name strings\r
- //\r
- CapsuleBuffer = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (VOID *));\r
- if (CapsuleBuffer == NULL) {\r
- DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- CapsuleSize = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof (UINTN));\r
- if (CapsuleSize == NULL) {\r
- DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));\r
- FreePool (CapsuleBuffer);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- for (Index = 0; Index < CapsuleOnDiskNum; Index++) {\r
- CapsuleBuffer[Index] = (VOID *)(UINTN) CapsuleOnDiskBuf[Index].ImageAddress;\r
- CapsuleSize[Index] = (UINTN) CapsuleOnDiskBuf[Index].FileInfo->FileSize;\r
- TotalStringSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);\r
- }\r
-\r
- FileNameCapsule = AllocateZeroPool (sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);\r
- if (FileNameCapsule == NULL) {\r
- DEBUG ((DEBUG_ERROR, "Fail to allocate memory for name capsule.\n"));\r
- FreePool (CapsuleBuffer);\r
- FreePool (CapsuleSize);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- FileNameCapsule->CapsuleImageSize = (UINT32) (sizeof (EFI_CAPSULE_HEADER) + TotalStringSize);\r
- FileNameCapsule->Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
- FileNameCapsule->HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
- CopyGuid (&(FileNameCapsule->CapsuleGuid), &gEdkiiCapsuleOnDiskNameGuid);\r
-\r
- StringBuf = (UINT8 *)FileNameCapsule + FileNameCapsule->HeaderSize;\r
- for (Index = 0; Index < CapsuleOnDiskNum; Index ++) {\r
- StringSize = StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);\r
- CopyMem (StringBuf, CapsuleOnDiskBuf[Index].FileInfo->FileName, StringSize);\r
- StringBuf += StringSize;\r
- }\r
-\r
- CapsuleBuffer[CapsuleOnDiskNum] = FileNameCapsule;\r
- CapsuleSize[CapsuleOnDiskNum] = TotalStringSize + sizeof (EFI_CAPSULE_HEADER);\r
-\r
- //\r
- // 3. Build Gather list for the capsules\r
- //\r
- Status = BuildGatherList (CapsuleBuffer, CapsuleSize, CapsuleOnDiskNum + 1, &BlockDescriptors);\r
- if (EFI_ERROR (Status) || BlockDescriptors == NULL) {\r
- FreePool (CapsuleBuffer);\r
- FreePool (CapsuleSize);\r
- FreePool (FileNameCapsule);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- //\r
- // 4. Call UpdateCapsule() service\r
- //\r
- Status = gRT->UpdateCapsule((EFI_CAPSULE_HEADER **) CapsuleBuffer, CapsuleOnDiskNum + 1, (UINTN) BlockDescriptors);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Relocate Capsule on Disk from EFI system partition.\r
-\r
- Two solution to deliver Capsule On Disk:\r
- Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On Disk to memory and call UpdateCapsule().\r
- Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On Disk to a platform-specific NV storage\r
- device with BlockIo protocol.\r
-\r
- Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.\r
- Function will stall 100ms between each retry.\r
-\r
- Side Effects:\r
- Capsule Delivery Supported Flag in OsIndication variable and BootNext variable will be cleared.\r
- Solution B: Content corruption. Block IO write directly touches low level write. Orignal partitions, file\r
- systems of the relocation device will be corrupted.\r
-\r
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
- devices like USB can get enumerated. Input 0 means no retry.\r
-\r
- @retval EFI_SUCCESS Capsule on Disk images are successfully relocated.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoDRelocateCapsule(\r
- UINTN MaxRetry\r
- )\r
-{\r
- if (!PcdGetBool (PcdCapsuleOnDiskSupport)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- //\r
- // Clear CapsuleOnDisk Flag firstly.\r
- //\r
- CoDClearCapsuleOnDiskFlag ();\r
-\r
- //\r
- // If Capsule In Ram is supported, delivery capsules through memory\r
- //\r
- if (PcdGetBool (PcdCapsuleInRamSupport)) {\r
- DEBUG ((DEBUG_INFO, "Capsule In Ram is supported, call gRT->UpdateCapsule().\n"));\r
- return RelocateCapsuleToRam (MaxRetry);\r
- } else {\r
- DEBUG ((DEBUG_INFO, "Reallcoate all Capsule on Disks to %s in RootDir.\n", (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName)));\r
- return RelocateCapsuleToDisk (MaxRetry);\r
- }\r
-}\r
-\r
-/**\r
- Remove the temp file from the root of EFI System Partition.\r
- Device enumeration like USB costs time, user can input MaxRetry to tell function to retry.\r
- Function will stall 100ms between each retry.\r
-\r
- @param[in] MaxRetry Max Connection Retry. Stall 100ms between each connection try to ensure\r
- devices like USB can get enumerated. Input 0 means no retry.\r
-\r
- @retval EFI_SUCCESS Remove the temp file successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoDRemoveTempFile (\r
- UINTN MaxRetry\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN DataSize;\r
- UINT16 *LoadOptionNumber;\r
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
- EFI_HANDLE FsHandle;\r
- EFI_FILE_HANDLE RootDir;\r
- EFI_FILE_HANDLE TempCodFile;\r
-\r
- RootDir = NULL;\r
- TempCodFile = NULL;\r
- DataSize = sizeof(UINT16);\r
-\r
- LoadOptionNumber = AllocatePool (sizeof(UINT16));\r
- if (LoadOptionNumber == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- //\r
- // Check if capsule files are relocated\r
- //\r
- Status = gRT->GetVariable (\r
- COD_RELOCATION_LOAD_OPTION_VAR_NAME,\r
- &gEfiCapsuleVendorGuid,\r
- NULL,\r
- &DataSize,\r
- (VOID *)LoadOptionNumber\r
- );\r
- if (EFI_ERROR(Status) || DataSize != sizeof(UINT16)) {\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Get the EFI file system from the boot option where the capsules are relocated\r
- //\r
- Status = GetEfiSysPartitionFromActiveBootOption(MaxRetry, &LoadOptionNumber, &FsHandle);\r
- if (EFI_ERROR(Status)) {\r
- goto EXIT;\r
- }\r
-\r
- Status = gBS->HandleProtocol(FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);\r
- if (EFI_ERROR(Status)) {\r
- goto EXIT;\r
- }\r
-\r
- Status = Fs->OpenVolume(Fs, &RootDir);\r
- if (EFI_ERROR(Status)) {\r
- goto EXIT;\r
- }\r
-\r
- //\r
- // Delete the TempCoDFile\r
- //\r
- Status = RootDir->Open(\r
- RootDir,\r
- &TempCodFile,\r
- (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),\r
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,\r
- 0\r
- );\r
- if (EFI_ERROR(Status)) {\r
- goto EXIT;\r
- }\r
-\r
- TempCodFile->Delete(TempCodFile);\r
-\r
- //\r
- // Clear "CoDRelocationLoadOption" variable\r
- //\r
- Status = gRT->SetVariable (\r
- COD_RELOCATION_LOAD_OPTION_VAR_NAME,\r
- &gEfiCapsuleVendorGuid,\r
- 0,\r
- 0,\r
- NULL\r
- );\r
-\r
-EXIT:\r
- if (LoadOptionNumber != NULL) {\r
- FreePool (LoadOptionNumber);\r
- }\r
-\r
- if (RootDir != NULL) {\r
- RootDir->Close(RootDir);\r
- }\r
-\r
- return Status;\r
-}\r