blob: 5ce5a50f7b96f7153cc6147d280f43c7a6ea92a4 [file] [log] [blame]
/** @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;
}