summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c')
-rw-r--r--MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c1714
1 files changed, 857 insertions, 857 deletions
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c b/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
index 5ce5a50f7b..41e4c21a35 100644
--- a/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
+++ b/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
@@ -1,857 +1,857 @@
-/** @file
- Process Capsule On Disk.
-
- Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "CapsuleApp.h"
-
-EFI_GUID mCapsuleOnDiskBootOptionGuid = {
- 0x4CC29BB7, 0x2413, 0x40A2, { 0xB0, 0x6D, 0x25, 0x3E, 0x37, 0x10, 0xF5, 0x32 }
-};
-
-/**
- Get file name from file path.
-
- @param FilePath File path.
-
- @return Pointer to file name.
-
-**/
-CHAR16 *
-GetFileNameFromPath (
- CHAR16 *FilePath
- )
-{
- EFI_STATUS Status;
- EFI_SHELL_PROTOCOL *ShellProtocol;
- SHELL_FILE_HANDLE Handle;
- EFI_FILE_INFO *FileInfo;
-
- ShellProtocol = GetShellProtocol ();
- if (ShellProtocol == NULL) {
- return NULL;
- }
-
- //
- // Open file by FileName.
- //
- Status = ShellProtocol->OpenFileByName (
- FilePath,
- &Handle,
- EFI_FILE_MODE_READ
- );
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- //
- // Get file name from EFI_FILE_INFO.
- //
- FileInfo = ShellProtocol->GetFileInfo (Handle);
- ShellProtocol->CloseFile (Handle);
- if (FileInfo == NULL) {
- return NULL;
- }
-
- return FileInfo->FileName;
-}
-
-/**
- Check if the device path is EFI system Partition.
-
- @param DevicePath The ESP device path.
-
- @retval TRUE DevicePath is a device path for ESP.
- @retval FALSE DevicePath is not a device path for ESP.
-
-**/
-BOOLEAN
-IsEfiSysPartitionDevicePath (
- EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
- HARDDRIVE_DEVICE_PATH *Hd;
- EFI_HANDLE Handle;
-
- //
- // 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);
- return EFI_ERROR (Status) ? FALSE : TRUE;
- } else {
- return FALSE;
- }
-}
-
-/**
- Dump all EFI System Partition.
-
-**/
-VOID
-DumpAllEfiSysPartition (
- VOID
- )
-{
- EFI_HANDLE *SimpleFileSystemHandles;
- UINTN NumberSimpleFileSystemHandles;
- UINTN Index;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- UINTN NumberEfiSystemPartitions;
- EFI_SHELL_PROTOCOL *ShellProtocol;
-
- NumberEfiSystemPartitions = 0;
-
- ShellProtocol = GetShellProtocol ();
- if (ShellProtocol == NULL) {
- Print (L"Get Shell Protocol Fail\n");
- return;
- }
-
- Print (L"EFI System Partition list:\n");
-
- gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiSimpleFileSystemProtocolGuid,
- NULL,
- &NumberSimpleFileSystemHandles,
- &SimpleFileSystemHandles
- );
-
- for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
- DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
- if (IsEfiSysPartitionDevicePath (DevicePath)) {
- NumberEfiSystemPartitions++;
- Print (L" %s\n %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText (DevicePath, TRUE, TRUE));
- }
- }
-
- if (NumberEfiSystemPartitions == 0) {
- Print (L" No ESP found.\n");
- }
-}
-
-/**
- Check if capsule is provisioned.
-
- @retval TRUE Capsule is provisioned previously.
- @retval FALSE No capsule is provisioned.
-
-**/
-BOOLEAN
-IsCapsuleProvisioned (
- VOID
- )
-{
- EFI_STATUS Status;
- UINT64 OsIndication;
- UINTN DataSize;
-
- OsIndication = 0;
- DataSize = sizeof (UINT64);
- Status = gRT->GetVariable (
- L"OsIndications",
- &gEfiGlobalVariableGuid,
- NULL,
- &DataSize,
- &OsIndication
- );
- if (!EFI_ERROR (Status) &&
- ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0))
- {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Get one active Efi System Partition.
-
- @param[out] FsDevicePath The device path of Fs
- @param[out] Fs The file system within EfiSysPartition
-
- @retval EFI_SUCCESS Get file system successfully
- @retval EFI_NOT_FOUND No valid file system found
-
-**/
-EFI_STATUS
-GetEfiSysPartition (
- OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath,
- OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
- )
-{
- EFI_HANDLE *SimpleFileSystemHandles;
- UINTN NumberSimpleFileSystemHandles;
- UINTN Index;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- EFI_STATUS Status;
-
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiSimpleFileSystemProtocolGuid,
- NULL,
- &NumberSimpleFileSystemHandles,
- &SimpleFileSystemHandles
- );
-
- if (EFI_ERROR (Status)) {
- return EFI_NOT_FOUND;
- }
-
- for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
- DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
- if (IsEfiSysPartitionDevicePath (DevicePath)) {
- Status = gBS->HandleProtocol (SimpleFileSystemHandles[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs);
- if (!EFI_ERROR (Status)) {
- *FsDevicePath = DevicePath;
- return EFI_SUCCESS;
- }
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Check if Active Efi System Partition within GPT is in the device path.
-
- @param[in] DevicePath The device path
- @param[out] FsDevicePath The device path of Fs
- @param[out] Fs The file system within EfiSysPartition
-
- @retval EFI_SUCCESS Get file system successfully
- @retval EFI_NOT_FOUND No valid file system found
- @retval others Get file system failed
-
-**/
-EFI_STATUS
-GetEfiSysPartitionFromDevPath (
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath,
- OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
- HARDDRIVE_DEVICE_PATH *Hd;
- EFI_HANDLE Handle;
-
- //
- // 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)) {
- *FsDevicePath = DevicePathFromHandle (Handle);
- return EFI_SUCCESS;
- }
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Get SimpleFileSystem from boot option file path.
-
- @param[in] DevicePath The file path of boot option
- @param[out] FullPath The full device path of boot device
- @param[out] Fs The file system within EfiSysPartition
-
- @retval EFI_SUCCESS Get file system successfully
- @retval EFI_NOT_FOUND No valid file system found
- @retval others Get file system failed
-
-**/
-EFI_STATUS
-GetEfiSysPartitionFromBootOptionFilePath (
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
- OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
- EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
- EFI_DEVICE_PATH_PROTOCOL *FsFullPath;
-
- CurFullPath = NULL;
- FsFullPath = 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 *DevicePathStr;
-
- DevicePathStr = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
- if (DevicePathStr != NULL) {
- DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr));
- FreePool (DevicePathStr);
- }
-
- DEBUG_CODE_END ();
-
- Status = GetEfiSysPartitionFromDevPath (CurFullPath, &FsFullPath, Fs);
- } while (EFI_ERROR (Status));
-
- if (*Fs != NULL) {
- *FullPath = FsFullPath;
- return EFI_SUCCESS;
- } else {
- return EFI_NOT_FOUND;
- }
-}
-
-/**
- Get a valid SimpleFileSystem within EFI system partition.
-
- @param[in] Map The FS mapping capsule write to
- @param[out] BootNext The value of BootNext Variable
- @param[out] Fs The file system within EfiSysPartition
- @param[out] UpdateBootNext The flag to indicate whether update BootNext Variable
-
- @retval EFI_SUCCESS Get FS successfully
- @retval EFI_NOT_FOUND No valid FS found
- @retval others Get FS failed
-
-**/
-EFI_STATUS
-GetUpdateFileSystem (
- IN CHAR16 *Map,
- OUT UINT16 *BootNext,
- OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs,
- OUT BOOLEAN *UpdateBootNext
- )
-{
- EFI_STATUS Status;
- CHAR16 BootOptionName[20];
- UINTN Index;
- CONST EFI_DEVICE_PATH_PROTOCOL *MappedDevicePath;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- EFI_DEVICE_PATH_PROTOCOL *FullPath;
- UINT16 *BootNextData;
- EFI_BOOT_MANAGER_LOAD_OPTION BootNextOption;
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuffer;
- UINTN BootOptionCount;
- EFI_SHELL_PROTOCOL *ShellProtocol;
- EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
-
- MappedDevicePath = NULL;
- BootOptionBuffer = NULL;
-
- ShellProtocol = GetShellProtocol ();
- if (ShellProtocol == NULL) {
- Print (L"Get Shell Protocol Fail\n");
- return EFI_NOT_FOUND;
- }
-
- //
- // 1. If Fs is not assigned and there are capsule provisioned before,
- // Get EFI system partition from BootNext.
- //
- if (IsCapsuleProvisioned () && (Map == NULL)) {
- Status = GetVariable2 (
- L"BootNext",
- &gEfiGlobalVariableGuid,
- (VOID **)&BootNextData,
- NULL
- );
- if (EFI_ERROR (Status) || (BootNextData == NULL)) {
- Print (L"Get Boot Next Data Fail. Status = %r\n", Status);
- return EFI_NOT_FOUND;
- } else {
- UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNextData);
- Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOption);
- if (!EFI_ERROR (Status)) {
- DevicePath = BootNextOption.FilePath;
- Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
- if (!EFI_ERROR (Status)) {
- *UpdateBootNext = FALSE;
- Print (L"Get EFI system partition from BootNext : %s\n", BootNextOption.Description);
- Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
- return EFI_SUCCESS;
- }
- }
- }
- }
-
- //
- // Check if Map is valid.
- //
- if (Map != NULL) {
- MappedDevicePath = ShellProtocol->GetDevicePathFromMap (Map);
- if (MappedDevicePath == NULL) {
- Print (L"'%s' is not a valid mapping.\n", Map);
- return EFI_INVALID_PARAMETER;
- } else if (!IsEfiSysPartitionDevicePath (DuplicateDevicePath (MappedDevicePath))) {
- Print (L"'%s' is not a EFI System Partition.\n", Map);
- return EFI_INVALID_PARAMETER;
- }
- }
-
- //
- // 2. Get EFI system partition form boot options.
- //
- BootOptionBuffer = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
- if ((BootOptionBuffer == NULL) ||
- ((BootOptionCount == 0) && (Map == NULL))
- )
- {
- return EFI_NOT_FOUND;
- }
-
- for (Index = 0; Index < BootOptionCount; Index++) {
- //
- // Get the boot option from the link list
- //
- DevicePath = BootOptionBuffer[Index].FilePath;
-
- //
- // Skip inactive or legacy boot options
- //
- if (((BootOptionBuffer[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 ();
-
- Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
- if (!EFI_ERROR (Status)) {
- if (Map == NULL) {
- *BootNext = (UINT16)BootOptionBuffer[Index].OptionNumber;
- *UpdateBootNext = TRUE;
- Print (L"Found EFI system partition on Boot%04x: %s\n", *BootNext, BootOptionBuffer[Index].Description);
- Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
- return EFI_SUCCESS;
- }
-
- if (StrnCmp (Map, ShellProtocol->GetMapFromDevicePath (&FullPath), StrLen (Map)) == 0) {
- *BootNext = (UINT16)BootOptionBuffer[Index].OptionNumber;
- *UpdateBootNext = TRUE;
- Print (L"Found Boot Option on %s : %s\n", Map, BootOptionBuffer[Index].Description);
- return EFI_SUCCESS;
- }
- }
- }
-
- //
- // 3. If no ESP is found on boot option, try to find a ESP and create boot option for it.
- //
- if (Map != NULL) {
- //
- // If map is assigned, try to get ESP from mapped Fs.
- //
- DevicePath = DuplicateDevicePath (MappedDevicePath);
- Status = GetEfiSysPartitionFromDevPath (DevicePath, &FullPath, Fs);
- if (EFI_ERROR (Status)) {
- Print (L"Error: Cannot get EFI system partition from '%s' - %r\n", Map, Status);
- return EFI_NOT_FOUND;
- }
-
- Print (L"Warning: Cannot find Boot Option on '%s'!\n", Map);
- } else {
- Status = GetEfiSysPartition (&DevicePath, Fs);
- if (EFI_ERROR (Status)) {
- Print (L"Error: Cannot find a EFI system partition!\n");
- return EFI_NOT_FOUND;
- }
- }
-
- Print (L"Create Boot option for capsule on disk:\n");
- Status = EfiBootManagerInitializeLoadOption (
- &NewOption,
- LoadOptionNumberUnassigned,
- LoadOptionTypeBoot,
- LOAD_OPTION_ACTIVE,
- L"UEFI Capsule On Disk",
- DevicePath,
- (UINT8 *)&mCapsuleOnDiskBootOptionGuid,
- sizeof (EFI_GUID)
- );
- if (!EFI_ERROR (Status)) {
- Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN)-1);
- {
- if (!EFI_ERROR (Status)) {
- *UpdateBootNext = TRUE;
- *BootNext = (UINT16)NewOption.OptionNumber;
- Print (L" Boot%04x: %s\n", *BootNext, ConvertDevicePathToText (DevicePath, TRUE, TRUE));
- return EFI_SUCCESS;
- }
- }
- }
-
- Print (L"ERROR: Cannot create boot option! - %r\n", Status);
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Write files to a given SimpleFileSystem.
-
- @param[in] Buffer The buffer array
- @param[in] BufferSize The buffer size array
- @param[in] FileName The file name array
- @param[in] BufferNum The buffer number
- @param[in] Fs The SimpleFileSystem handle to be written
-
- @retval EFI_SUCCESS Write file successfully
- @retval EFI_NOT_FOUND SFS protocol not found
- @retval others Write file failed
-
-**/
-EFI_STATUS
-WriteUpdateFile (
- IN VOID **Buffer,
- IN UINTN *BufferSize,
- IN CHAR16 **FileName,
- IN UINTN BufferNum,
- IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs
- )
-{
- EFI_STATUS Status;
- EFI_FILE *Root;
- EFI_FILE *FileHandle;
- EFI_FILE_PROTOCOL *DirHandle;
- UINT64 FileInfo;
- VOID *Filebuffer;
- UINTN FileSize;
- UINTN Index;
-
- DirHandle = NULL;
- FileHandle = NULL;
- Index = 0;
-
- //
- // Open Root from SFS
- //
- Status = Fs->OpenVolume (Fs, &Root);
- if (EFI_ERROR (Status)) {
- Print (L"Cannot open volume. Status = %r\n", Status);
- return EFI_NOT_FOUND;
- }
-
- //
- // Ensure that efi and updatecapsule directories exist
- //
- Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
- if (EFI_ERROR (Status)) {
- Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
- if (EFI_ERROR (Status)) {
- Print (L"Unable to create %s directory\n", L"\\EFI");
- return EFI_NOT_FOUND;
- }
- }
-
- Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
- if (EFI_ERROR (Status)) {
- Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
- if (EFI_ERROR (Status)) {
- Print (L"Unable to create %s directory\n", EFI_CAPSULE_FILE_DIRECTORY);
- return EFI_NOT_FOUND;
- }
- }
-
- for (Index = 0; Index < BufferNum; Index++) {
- FileHandle = NULL;
-
- //
- // Open UpdateCapsule file
- //
- Status = DirHandle->Open (DirHandle, &FileHandle, FileName[Index], EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
- if (EFI_ERROR (Status)) {
- Print (L"Unable to create %s file\n", FileName[Index]);
- return EFI_NOT_FOUND;
- }
-
- //
- // Empty the file contents
- //
- Status = FileHandleGetSize (FileHandle, &FileInfo);
- if (EFI_ERROR (Status)) {
- FileHandleClose (FileHandle);
- Print (L"Error Reading %s\n", FileName[Index]);
- return EFI_DEVICE_ERROR;
- }
-
- //
- // If the file size is already 0, then it has been empty.
- //
- if (FileInfo != 0) {
- //
- // Set the file size to 0.
- //
- FileInfo = 0;
- Status = FileHandleSetSize (FileHandle, FileInfo);
- if (EFI_ERROR (Status)) {
- Print (L"Error Deleting %s\n", FileName[Index]);
- FileHandleClose (FileHandle);
- return Status;
- }
- }
-
- //
- // Write Filebuffer to file
- //
- Filebuffer = Buffer[Index];
- FileSize = BufferSize[Index];
- Status = FileHandleWrite (FileHandle, &FileSize, Filebuffer);
- if (EFI_ERROR (Status)) {
- Print (L"Unable to write Capsule Update to %s, Status = %r\n", FileName[Index], Status);
- return EFI_NOT_FOUND;
- }
-
- Print (L"Succeed to write %s\n", FileName[Index]);
- FileHandleClose (FileHandle);
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Set capsule status variable.
-
- @param[in] SetCap Set or clear the capsule flag.
-
- @retval EFI_SUCCESS Succeed to set SetCap variable.
- @retval others Fail to set the variable.
-
-**/
-EFI_STATUS
-SetCapsuleStatusVariable (
- BOOLEAN SetCap
- )
-{
- EFI_STATUS Status;
- UINT64 OsIndication;
- UINTN DataSize;
-
- OsIndication = 0;
- DataSize = sizeof (UINT64);
- Status = gRT->GetVariable (
- L"OsIndications",
- &gEfiGlobalVariableGuid,
- NULL,
- &DataSize,
- &OsIndication
- );
- if (EFI_ERROR (Status)) {
- OsIndication = 0;
- }
-
- if (SetCap) {
- OsIndication |= ((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
- } else {
- OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
- }
-
- Status = gRT->SetVariable (
- L"OsIndications",
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
- sizeof (UINT64),
- &OsIndication
- );
-
- return Status;
-}
-
-/**
- Check if Capsule On Disk is supported.
-
- @retval TRUE Capsule On Disk is supported.
- @retval FALSE Capsule On Disk is not supported.
-
-**/
-BOOLEAN
-IsCapsuleOnDiskSupported (
- VOID
- )
-{
- EFI_STATUS Status;
- UINT64 OsIndicationsSupported;
- UINTN DataSize;
-
- DataSize = sizeof (UINT64);
- Status = gRT->GetVariable (
- L"OsIndicationsSupported",
- &gEfiGlobalVariableGuid,
- NULL,
- &DataSize,
- &OsIndicationsSupported
- );
- if (EFI_ERROR (Status)) {
- return FALSE;
- }
-
- if ((OsIndicationsSupported & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Process Capsule On Disk.
-
- @param[in] CapsuleBuffer An array of pointer to capsule images
- @param[in] CapsuleBufferSize An array of UINTN to capsule images size
- @param[in] FilePath An array of capsule images file path
- @param[in] Map File system mapping string
- @param[in] CapsuleNum The count of capsule images
-
- @retval EFI_SUCCESS Capsule on disk success.
- @retval others Capsule on disk fail.
-
-**/
-EFI_STATUS
-ProcessCapsuleOnDisk (
- IN VOID **CapsuleBuffer,
- IN UINTN *CapsuleBufferSize,
- IN CHAR16 **FilePath,
- IN CHAR16 *Map,
- IN UINTN CapsuleNum
- )
-{
- EFI_STATUS Status;
- UINT16 BootNext;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
- BOOLEAN UpdateBootNext;
- CHAR16 *FileName[MAX_CAPSULE_NUM];
- UINTN Index;
-
- //
- // Check if Capsule On Disk is supported
- //
- if (!IsCapsuleOnDiskSupported ()) {
- Print (L"CapsuleApp: Capsule On Disk is not supported.\n");
- return EFI_UNSUPPORTED;
- }
-
- //
- // Get a valid file system from boot path
- //
- Fs = NULL;
-
- Status = GetUpdateFileSystem (Map, &BootNext, &Fs, &UpdateBootNext);
- if (EFI_ERROR (Status)) {
- Print (L"CapsuleApp: cannot find a valid file system on boot devices. Status = %r\n", Status);
- return Status;
- }
-
- //
- // Get file name from file path
- //
- for (Index = 0; Index < CapsuleNum; Index++) {
- FileName[Index] = GetFileNameFromPath (FilePath[Index]);
- }
-
- //
- // Copy capsule image to '\efi\UpdateCapsule\'
- //
- Status = WriteUpdateFile (CapsuleBuffer, CapsuleBufferSize, FileName, CapsuleNum, Fs);
- if (EFI_ERROR (Status)) {
- Print (L"CapsuleApp: capsule image could not be copied for update.\n");
- return Status;
- }
-
- //
- // Set variable then reset
- //
- Status = SetCapsuleStatusVariable (TRUE);
- if (EFI_ERROR (Status)) {
- Print (L"CapsuleApp: unable to set OSIndication variable.\n");
- return Status;
- }
-
- if (UpdateBootNext) {
- Status = gRT->SetVariable (
- L"BootNext",
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
- sizeof (UINT16),
- &BootNext
- );
- if (EFI_ERROR (Status)) {
- Print (L"CapsuleApp: unable to set BootNext variable.\n");
- return Status;
- }
- }
-
- return EFI_SUCCESS;
-}
+/** @file
+ Process Capsule On Disk.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CapsuleApp.h"
+
+EFI_GUID mCapsuleOnDiskBootOptionGuid = {
+ 0x4CC29BB7, 0x2413, 0x40A2, { 0xB0, 0x6D, 0x25, 0x3E, 0x37, 0x10, 0xF5, 0x32 }
+};
+
+/**
+ Get file name from file path.
+
+ @param FilePath File path.
+
+ @return Pointer to file name.
+
+**/
+CHAR16 *
+GetFileNameFromPath (
+ CHAR16 *FilePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SHELL_PROTOCOL *ShellProtocol;
+ SHELL_FILE_HANDLE Handle;
+ EFI_FILE_INFO *FileInfo;
+
+ ShellProtocol = GetShellProtocol ();
+ if (ShellProtocol == NULL) {
+ return NULL;
+ }
+
+ //
+ // Open file by FileName.
+ //
+ Status = ShellProtocol->OpenFileByName (
+ FilePath,
+ &Handle,
+ EFI_FILE_MODE_READ
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Get file name from EFI_FILE_INFO.
+ //
+ FileInfo = ShellProtocol->GetFileInfo (Handle);
+ ShellProtocol->CloseFile (Handle);
+ if (FileInfo == NULL) {
+ return NULL;
+ }
+
+ return FileInfo->FileName;
+}
+
+/**
+ Check if the device path is EFI system Partition.
+
+ @param DevicePath The ESP device path.
+
+ @retval TRUE DevicePath is a device path for ESP.
+ @retval FALSE DevicePath is not a device path for ESP.
+
+**/
+BOOLEAN
+IsEfiSysPartitionDevicePath (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ HARDDRIVE_DEVICE_PATH *Hd;
+ EFI_HANDLE Handle;
+
+ //
+ // 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);
+ return EFI_ERROR (Status) ? FALSE : TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Dump all EFI System Partition.
+
+**/
+VOID
+DumpAllEfiSysPartition (
+ VOID
+ )
+{
+ EFI_HANDLE *SimpleFileSystemHandles;
+ UINTN NumberSimpleFileSystemHandles;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN NumberEfiSystemPartitions;
+ EFI_SHELL_PROTOCOL *ShellProtocol;
+
+ NumberEfiSystemPartitions = 0;
+
+ ShellProtocol = GetShellProtocol ();
+ if (ShellProtocol == NULL) {
+ Print (L"Get Shell Protocol Fail\n");
+ return;
+ }
+
+ Print (L"EFI System Partition list:\n");
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberSimpleFileSystemHandles,
+ &SimpleFileSystemHandles
+ );
+
+ for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
+ DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
+ if (IsEfiSysPartitionDevicePath (DevicePath)) {
+ NumberEfiSystemPartitions++;
+ Print (L" %s\n %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText (DevicePath, TRUE, TRUE));
+ }
+ }
+
+ if (NumberEfiSystemPartitions == 0) {
+ Print (L" No ESP found.\n");
+ }
+}
+
+/**
+ Check if capsule is provisioned.
+
+ @retval TRUE Capsule is provisioned previously.
+ @retval FALSE No capsule is provisioned.
+
+**/
+BOOLEAN
+IsCapsuleProvisioned (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndication;
+ UINTN DataSize;
+
+ OsIndication = 0;
+ DataSize = sizeof (UINT64);
+ Status = gRT->GetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndication
+ );
+ if (!EFI_ERROR (Status) &&
+ ((OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get one active Efi System Partition.
+
+ @param[out] FsDevicePath The device path of Fs
+ @param[out] Fs The file system within EfiSysPartition
+
+ @retval EFI_SUCCESS Get file system successfully
+ @retval EFI_NOT_FOUND No valid file system found
+
+**/
+EFI_STATUS
+GetEfiSysPartition (
+ OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath,
+ OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
+ )
+{
+ EFI_HANDLE *SimpleFileSystemHandles;
+ UINTN NumberSimpleFileSystemHandles;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_STATUS Status;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberSimpleFileSystemHandles,
+ &SimpleFileSystemHandles
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
+ DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
+ if (IsEfiSysPartitionDevicePath (DevicePath)) {
+ Status = gBS->HandleProtocol (SimpleFileSystemHandles[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs);
+ if (!EFI_ERROR (Status)) {
+ *FsDevicePath = DevicePath;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Check if Active Efi System Partition within GPT is in the device path.
+
+ @param[in] DevicePath The device path
+ @param[out] FsDevicePath The device path of Fs
+ @param[out] Fs The file system within EfiSysPartition
+
+ @retval EFI_SUCCESS Get file system successfully
+ @retval EFI_NOT_FOUND No valid file system found
+ @retval others Get file system failed
+
+**/
+EFI_STATUS
+GetEfiSysPartitionFromDevPath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath,
+ OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ HARDDRIVE_DEVICE_PATH *Hd;
+ EFI_HANDLE Handle;
+
+ //
+ // 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)) {
+ *FsDevicePath = DevicePathFromHandle (Handle);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Get SimpleFileSystem from boot option file path.
+
+ @param[in] DevicePath The file path of boot option
+ @param[out] FullPath The full device path of boot device
+ @param[out] Fs The file system within EfiSysPartition
+
+ @retval EFI_SUCCESS Get file system successfully
+ @retval EFI_NOT_FOUND No valid file system found
+ @retval others Get file system failed
+
+**/
+EFI_STATUS
+GetEfiSysPartitionFromBootOptionFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
+ EFI_DEVICE_PATH_PROTOCOL *FsFullPath;
+
+ CurFullPath = NULL;
+ FsFullPath = 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 *DevicePathStr;
+
+ DevicePathStr = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
+ if (DevicePathStr != NULL) {
+ DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr));
+ FreePool (DevicePathStr);
+ }
+
+ DEBUG_CODE_END ();
+
+ Status = GetEfiSysPartitionFromDevPath (CurFullPath, &FsFullPath, Fs);
+ } while (EFI_ERROR (Status));
+
+ if (*Fs != NULL) {
+ *FullPath = FsFullPath;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ Get a valid SimpleFileSystem within EFI system partition.
+
+ @param[in] Map The FS mapping capsule write to
+ @param[out] BootNext The value of BootNext Variable
+ @param[out] Fs The file system within EfiSysPartition
+ @param[out] UpdateBootNext The flag to indicate whether update BootNext Variable
+
+ @retval EFI_SUCCESS Get FS successfully
+ @retval EFI_NOT_FOUND No valid FS found
+ @retval others Get FS failed
+
+**/
+EFI_STATUS
+GetUpdateFileSystem (
+ IN CHAR16 *Map,
+ OUT UINT16 *BootNext,
+ OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs,
+ OUT BOOLEAN *UpdateBootNext
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 BootOptionName[20];
+ UINTN Index;
+ CONST EFI_DEVICE_PATH_PROTOCOL *MappedDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FullPath;
+ UINT16 *BootNextData;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootNextOption;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuffer;
+ UINTN BootOptionCount;
+ EFI_SHELL_PROTOCOL *ShellProtocol;
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
+
+ MappedDevicePath = NULL;
+ BootOptionBuffer = NULL;
+
+ ShellProtocol = GetShellProtocol ();
+ if (ShellProtocol == NULL) {
+ Print (L"Get Shell Protocol Fail\n");
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // 1. If Fs is not assigned and there are capsule provisioned before,
+ // Get EFI system partition from BootNext.
+ //
+ if (IsCapsuleProvisioned () && (Map == NULL)) {
+ Status = GetVariable2 (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ (VOID **)&BootNextData,
+ NULL
+ );
+ if (EFI_ERROR (Status) || (BootNextData == NULL)) {
+ Print (L"Get Boot Next Data Fail. Status = %r\n", Status);
+ return EFI_NOT_FOUND;
+ } else {
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNextData);
+ Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOption);
+ if (!EFI_ERROR (Status)) {
+ DevicePath = BootNextOption.FilePath;
+ Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
+ if (!EFI_ERROR (Status)) {
+ *UpdateBootNext = FALSE;
+ Print (L"Get EFI system partition from BootNext : %s\n", BootNextOption.Description);
+ Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ //
+ // Check if Map is valid.
+ //
+ if (Map != NULL) {
+ MappedDevicePath = ShellProtocol->GetDevicePathFromMap (Map);
+ if (MappedDevicePath == NULL) {
+ Print (L"'%s' is not a valid mapping.\n", Map);
+ return EFI_INVALID_PARAMETER;
+ } else if (!IsEfiSysPartitionDevicePath (DuplicateDevicePath (MappedDevicePath))) {
+ Print (L"'%s' is not a EFI System Partition.\n", Map);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // 2. Get EFI system partition form boot options.
+ //
+ BootOptionBuffer = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+ if ((BootOptionBuffer == NULL) ||
+ ((BootOptionCount == 0) && (Map == NULL))
+ )
+ {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ //
+ // Get the boot option from the link list
+ //
+ DevicePath = BootOptionBuffer[Index].FilePath;
+
+ //
+ // Skip inactive or legacy boot options
+ //
+ if (((BootOptionBuffer[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 ();
+
+ Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
+ if (!EFI_ERROR (Status)) {
+ if (Map == NULL) {
+ *BootNext = (UINT16)BootOptionBuffer[Index].OptionNumber;
+ *UpdateBootNext = TRUE;
+ Print (L"Found EFI system partition on Boot%04x: %s\n", *BootNext, BootOptionBuffer[Index].Description);
+ Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
+ return EFI_SUCCESS;
+ }
+
+ if (StrnCmp (Map, ShellProtocol->GetMapFromDevicePath (&FullPath), StrLen (Map)) == 0) {
+ *BootNext = (UINT16)BootOptionBuffer[Index].OptionNumber;
+ *UpdateBootNext = TRUE;
+ Print (L"Found Boot Option on %s : %s\n", Map, BootOptionBuffer[Index].Description);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // 3. If no ESP is found on boot option, try to find a ESP and create boot option for it.
+ //
+ if (Map != NULL) {
+ //
+ // If map is assigned, try to get ESP from mapped Fs.
+ //
+ DevicePath = DuplicateDevicePath (MappedDevicePath);
+ Status = GetEfiSysPartitionFromDevPath (DevicePath, &FullPath, Fs);
+ if (EFI_ERROR (Status)) {
+ Print (L"Error: Cannot get EFI system partition from '%s' - %r\n", Map, Status);
+ return EFI_NOT_FOUND;
+ }
+
+ Print (L"Warning: Cannot find Boot Option on '%s'!\n", Map);
+ } else {
+ Status = GetEfiSysPartition (&DevicePath, Fs);
+ if (EFI_ERROR (Status)) {
+ Print (L"Error: Cannot find a EFI system partition!\n");
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Print (L"Create Boot option for capsule on disk:\n");
+ Status = EfiBootManagerInitializeLoadOption (
+ &NewOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ L"UEFI Capsule On Disk",
+ DevicePath,
+ (UINT8 *)&mCapsuleOnDiskBootOptionGuid,
+ sizeof (EFI_GUID)
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN)-1);
+ {
+ if (!EFI_ERROR (Status)) {
+ *UpdateBootNext = TRUE;
+ *BootNext = (UINT16)NewOption.OptionNumber;
+ Print (L" Boot%04x: %s\n", *BootNext, ConvertDevicePathToText (DevicePath, TRUE, TRUE));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ Print (L"ERROR: Cannot create boot option! - %r\n", Status);
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Write files to a given SimpleFileSystem.
+
+ @param[in] Buffer The buffer array
+ @param[in] BufferSize The buffer size array
+ @param[in] FileName The file name array
+ @param[in] BufferNum The buffer number
+ @param[in] Fs The SimpleFileSystem handle to be written
+
+ @retval EFI_SUCCESS Write file successfully
+ @retval EFI_NOT_FOUND SFS protocol not found
+ @retval others Write file failed
+
+**/
+EFI_STATUS
+WriteUpdateFile (
+ IN VOID **Buffer,
+ IN UINTN *BufferSize,
+ IN CHAR16 **FileName,
+ IN UINTN BufferNum,
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE *Root;
+ EFI_FILE *FileHandle;
+ EFI_FILE_PROTOCOL *DirHandle;
+ UINT64 FileInfo;
+ VOID *Filebuffer;
+ UINTN FileSize;
+ UINTN Index;
+
+ DirHandle = NULL;
+ FileHandle = NULL;
+ Index = 0;
+
+ //
+ // Open Root from SFS
+ //
+ Status = Fs->OpenVolume (Fs, &Root);
+ if (EFI_ERROR (Status)) {
+ Print (L"Cannot open volume. Status = %r\n", Status);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Ensure that efi and updatecapsule directories exist
+ //
+ Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
+ if (EFI_ERROR (Status)) {
+ Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
+ if (EFI_ERROR (Status)) {
+ Print (L"Unable to create %s directory\n", L"\\EFI");
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
+ if (EFI_ERROR (Status)) {
+ Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
+ if (EFI_ERROR (Status)) {
+ Print (L"Unable to create %s directory\n", EFI_CAPSULE_FILE_DIRECTORY);
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ for (Index = 0; Index < BufferNum; Index++) {
+ FileHandle = NULL;
+
+ //
+ // Open UpdateCapsule file
+ //
+ Status = DirHandle->Open (DirHandle, &FileHandle, FileName[Index], EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ Print (L"Unable to create %s file\n", FileName[Index]);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Empty the file contents
+ //
+ Status = FileHandleGetSize (FileHandle, &FileInfo);
+ if (EFI_ERROR (Status)) {
+ FileHandleClose (FileHandle);
+ Print (L"Error Reading %s\n", FileName[Index]);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If the file size is already 0, then it has been empty.
+ //
+ if (FileInfo != 0) {
+ //
+ // Set the file size to 0.
+ //
+ FileInfo = 0;
+ Status = FileHandleSetSize (FileHandle, FileInfo);
+ if (EFI_ERROR (Status)) {
+ Print (L"Error Deleting %s\n", FileName[Index]);
+ FileHandleClose (FileHandle);
+ return Status;
+ }
+ }
+
+ //
+ // Write Filebuffer to file
+ //
+ Filebuffer = Buffer[Index];
+ FileSize = BufferSize[Index];
+ Status = FileHandleWrite (FileHandle, &FileSize, Filebuffer);
+ if (EFI_ERROR (Status)) {
+ Print (L"Unable to write Capsule Update to %s, Status = %r\n", FileName[Index], Status);
+ return EFI_NOT_FOUND;
+ }
+
+ Print (L"Succeed to write %s\n", FileName[Index]);
+ FileHandleClose (FileHandle);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set capsule status variable.
+
+ @param[in] SetCap Set or clear the capsule flag.
+
+ @retval EFI_SUCCESS Succeed to set SetCap variable.
+ @retval others Fail to set the variable.
+
+**/
+EFI_STATUS
+SetCapsuleStatusVariable (
+ BOOLEAN SetCap
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndication;
+ UINTN DataSize;
+
+ OsIndication = 0;
+ DataSize = sizeof (UINT64);
+ Status = gRT->GetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndication
+ );
+ if (EFI_ERROR (Status)) {
+ OsIndication = 0;
+ }
+
+ if (SetCap) {
+ OsIndication |= ((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
+ } else {
+ OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
+ }
+
+ Status = gRT->SetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT64),
+ &OsIndication
+ );
+
+ return Status;
+}
+
+/**
+ Check if Capsule On Disk is supported.
+
+ @retval TRUE Capsule On Disk is supported.
+ @retval FALSE Capsule On Disk is not supported.
+
+**/
+BOOLEAN
+IsCapsuleOnDiskSupported (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndicationsSupported;
+ UINTN DataSize;
+
+ DataSize = sizeof (UINT64);
+ Status = gRT->GetVariable (
+ L"OsIndicationsSupported",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndicationsSupported
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((OsIndicationsSupported & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Process Capsule On Disk.
+
+ @param[in] CapsuleBuffer An array of pointer to capsule images
+ @param[in] CapsuleBufferSize An array of UINTN to capsule images size
+ @param[in] FilePath An array of capsule images file path
+ @param[in] Map File system mapping string
+ @param[in] CapsuleNum The count of capsule images
+
+ @retval EFI_SUCCESS Capsule on disk success.
+ @retval others Capsule on disk fail.
+
+**/
+EFI_STATUS
+ProcessCapsuleOnDisk (
+ IN VOID **CapsuleBuffer,
+ IN UINTN *CapsuleBufferSize,
+ IN CHAR16 **FilePath,
+ IN CHAR16 *Map,
+ IN UINTN CapsuleNum
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BootNext;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+ BOOLEAN UpdateBootNext;
+ CHAR16 *FileName[MAX_CAPSULE_NUM];
+ UINTN Index;
+
+ //
+ // Check if Capsule On Disk is supported
+ //
+ if (!IsCapsuleOnDiskSupported ()) {
+ Print (L"CapsuleApp: Capsule On Disk is not supported.\n");
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get a valid file system from boot path
+ //
+ Fs = NULL;
+
+ Status = GetUpdateFileSystem (Map, &BootNext, &Fs, &UpdateBootNext);
+ if (EFI_ERROR (Status)) {
+ Print (L"CapsuleApp: cannot find a valid file system on boot devices. Status = %r\n", Status);
+ return Status;
+ }
+
+ //
+ // Get file name from file path
+ //
+ for (Index = 0; Index < CapsuleNum; Index++) {
+ FileName[Index] = GetFileNameFromPath (FilePath[Index]);
+ }
+
+ //
+ // Copy capsule image to '\efi\UpdateCapsule\'
+ //
+ Status = WriteUpdateFile (CapsuleBuffer, CapsuleBufferSize, FileName, CapsuleNum, Fs);
+ if (EFI_ERROR (Status)) {
+ Print (L"CapsuleApp: capsule image could not be copied for update.\n");
+ return Status;
+ }
+
+ //
+ // Set variable then reset
+ //
+ Status = SetCapsuleStatusVariable (TRUE);
+ if (EFI_ERROR (Status)) {
+ Print (L"CapsuleApp: unable to set OSIndication variable.\n");
+ return Status;
+ }
+
+ if (UpdateBootNext) {
+ Status = gRT->SetVariable (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT16),
+ &BootNext
+ );
+ if (EFI_ERROR (Status)) {
+ Print (L"CapsuleApp: unable to set BootNext variable.\n");
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}