/** @file Process Capsule On Disk. Copyright (c) 2019, Intel Corporation. All rights reserved.
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 ( CHAR16 *DevicePathStr; DevicePathStr = ConvertDevicePathToText (CurFullPath, TRUE, TRUE); if (DevicePathStr != NULL){ DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr)); FreePool (DevicePathStr); } ); 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 ( 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")); } ); 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 partiion 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; }