mirror of
https://git.proxmox.com/git/efi-boot-shim
synced 2025-05-01 05:04:36 +00:00
621 lines
14 KiB
C
621 lines
14 KiB
C
/*
|
|
* Copyright 2012-2013 Red Hat, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* See "COPYING" for license terms.
|
|
*
|
|
* Author(s): Peter Jones <pjones@redhat.com>
|
|
*/
|
|
|
|
#include <efi.h>
|
|
#include <efilib.h>
|
|
|
|
#include "ucs2.h"
|
|
|
|
EFI_LOADED_IMAGE *this_image = NULL;
|
|
|
|
static EFI_STATUS
|
|
get_file_size(EFI_FILE_HANDLE fh, UINT64 *retsize)
|
|
{
|
|
EFI_STATUS rc;
|
|
void *buffer = NULL;
|
|
UINTN bs = 0;
|
|
EFI_GUID finfo = EFI_FILE_INFO_ID;
|
|
|
|
/* The API here is "Call it once with bs=0, it fills in bs,
|
|
* then allocate a buffer and ask again to get it filled. */
|
|
rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo, &bs, NULL);
|
|
if (rc == EFI_BUFFER_TOO_SMALL) {
|
|
buffer = AllocateZeroPool(bs);
|
|
if (!buffer) {
|
|
Print(L"Could not allocate memory\n");
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo,
|
|
&bs, buffer);
|
|
}
|
|
/* This checks *either* the error from the first GetInfo, if it isn't
|
|
* the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo call
|
|
* in *any* case. */
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Could not get file info: %d\n", rc);
|
|
if (buffer)
|
|
FreePool(buffer);
|
|
return rc;
|
|
}
|
|
EFI_FILE_INFO *fi = buffer;
|
|
*retsize = fi->FileSize;
|
|
FreePool(buffer);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
read_file(EFI_FILE_HANDLE fh, CHAR16 *fullpath, CHAR16 **buffer, UINT64 *bs)
|
|
{
|
|
EFI_FILE_HANDLE fh2;
|
|
EFI_STATUS rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2, fullpath,
|
|
EFI_FILE_READ_ONLY, 0);
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Couldn't open \"%s\": %d\n", fullpath, rc);
|
|
return rc;
|
|
}
|
|
|
|
UINT64 len = 0;
|
|
CHAR16 *b = NULL;
|
|
rc = get_file_size(fh2, &len);
|
|
if (EFI_ERROR(rc)) {
|
|
uefi_call_wrapper(fh2->Close, 1, fh2);
|
|
return rc;
|
|
}
|
|
|
|
b = AllocateZeroPool(len + 2);
|
|
if (!buffer) {
|
|
Print(L"Could not allocate memory\n");
|
|
uefi_call_wrapper(fh2->Close, 1, fh2);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
rc = uefi_call_wrapper(fh->Read, 3, fh, &len, b);
|
|
if (EFI_ERROR(rc)) {
|
|
FreePool(buffer);
|
|
uefi_call_wrapper(fh2->Close, 1, fh2);
|
|
Print(L"Could not read file: %d\n", rc);
|
|
return rc;
|
|
}
|
|
*buffer = b;
|
|
*bs = len;
|
|
uefi_call_wrapper(fh2->Close, 1, fh2);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen)
|
|
{
|
|
UINT64 len;
|
|
|
|
len = StrLen(dirname) + StrLen(filename) + StrLen(L"\\EFI\\\\") + 2;
|
|
|
|
CHAR16 *fullpath = AllocateZeroPool(len*sizeof(CHAR16));
|
|
if (!fullpath) {
|
|
Print(L"Could not allocate memory\n");
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
StrCat(fullpath, L"\\EFI\\");
|
|
StrCat(fullpath, dirname);
|
|
StrCat(fullpath, L"\\");
|
|
StrCat(fullpath, filename);
|
|
|
|
*out = fullpath;
|
|
*outlen = len;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
CHAR16 *bootorder = NULL;
|
|
int nbootorder = 0;
|
|
|
|
EFI_STATUS
|
|
add_boot_option(EFI_DEVICE_PATH *dp, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
|
|
{
|
|
static int i = 0;
|
|
CHAR16 varname[] = L"Boot0000";
|
|
CHAR16 hexmap[] = L"0123456789ABCDEF";
|
|
EFI_GUID global = EFI_GLOBAL_VARIABLE;
|
|
EFI_STATUS rc;
|
|
|
|
for(; i <= 0xffff; i++) {
|
|
varname[4] = hexmap[(i & 0xf000) >> 12];
|
|
varname[5] = hexmap[(i & 0x0f00) >> 8];
|
|
varname[6] = hexmap[(i & 0x00f0) >> 4];
|
|
varname[7] = hexmap[(i & 0x000f) >> 0];
|
|
|
|
void *var = LibGetVariable(varname, &global);
|
|
if (!var) {
|
|
int size = sizeof(UINT32) + sizeof (UINT16) +
|
|
StrLen(label)*2 + 2 + DevicePathSize(dp) +
|
|
StrLen(arguments) * 2 + 2;
|
|
|
|
CHAR8 *data = AllocateZeroPool(size);
|
|
CHAR8 *cursor = data;
|
|
*(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
|
|
cursor += sizeof (UINT32);
|
|
*(UINT16 *)cursor = DevicePathSize(dp);
|
|
cursor += sizeof (UINT16);
|
|
StrCpy((CHAR16 *)cursor, label);
|
|
cursor += StrLen(label)*2 + 2;
|
|
CopyMem(cursor, dp, DevicePathSize(dp));
|
|
cursor += DevicePathSize(dp);
|
|
StrCpy((CHAR16 *)cursor, arguments);
|
|
|
|
Print(L"Creating boot entry \"%s\" with label \"%s\" "
|
|
L"for file \"%s\"\n",
|
|
varname, label, filename);
|
|
rc = uefi_call_wrapper(RT->SetVariable, 5, varname,
|
|
&global, EFI_VARIABLE_NON_VOLATILE |
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
EFI_VARIABLE_RUNTIME_ACCESS,
|
|
size, data);
|
|
|
|
FreePool(data);
|
|
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Could not create variable: %d\n", rc);
|
|
return rc;
|
|
}
|
|
|
|
CHAR16 *newbootorder = AllocateZeroPool(sizeof (CHAR16)
|
|
* (nbootorder + 1));
|
|
if (!newbootorder)
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
int j = 0;
|
|
if (nbootorder) {
|
|
for (j = 0; j < nbootorder; j++)
|
|
newbootorder[j] = bootorder[j];
|
|
FreePool(bootorder);
|
|
}
|
|
newbootorder[j] = i & 0xffff;
|
|
bootorder = newbootorder;
|
|
nbootorder += 1;
|
|
#ifdef DEBUG_FALLBACK
|
|
Print(L"nbootorder: %d\nBootOrder: ", nbootorder);
|
|
for (j = 0 ; j < nbootorder ; j++)
|
|
Print(L"%04x ", bootorder[j]);
|
|
Print(L"\n");
|
|
#endif
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
EFI_STATUS
|
|
update_boot_order(void)
|
|
{
|
|
CHAR16 *oldbootorder;
|
|
UINTN size;
|
|
EFI_GUID global = EFI_GLOBAL_VARIABLE;
|
|
CHAR16 *newbootorder = NULL;
|
|
|
|
oldbootorder = LibGetVariableAndSize(L"BootOrder", &global, &size);
|
|
if (oldbootorder) {
|
|
int n = size / sizeof (CHAR16) + nbootorder;
|
|
|
|
newbootorder = AllocateZeroPool(n * sizeof (CHAR16));
|
|
if (!newbootorder)
|
|
return EFI_OUT_OF_RESOURCES;
|
|
CopyMem(newbootorder, bootorder, nbootorder * sizeof (CHAR16));
|
|
CopyMem(newbootorder + nbootorder, oldbootorder, size);
|
|
size = n * sizeof (CHAR16);
|
|
} else {
|
|
size = nbootorder * sizeof(CHAR16);
|
|
newbootorder = AllocateZeroPool(size);
|
|
if (!newbootorder)
|
|
return EFI_OUT_OF_RESOURCES;
|
|
CopyMem(newbootorder, bootorder, size);
|
|
}
|
|
|
|
#ifdef DEBUG_FALLBACK
|
|
Print(L"nbootorder: %d\nBootOrder: ", size / sizeof (CHAR16));
|
|
int j;
|
|
for (j = 0 ; j < size / sizeof (CHAR16); j++)
|
|
Print(L"%04x ", newbootorder[j]);
|
|
Print(L"\n");
|
|
#endif
|
|
|
|
if (oldbootorder) {
|
|
LibDeleteVariable(L"BootOrder", &global);
|
|
FreePool(oldbootorder);
|
|
}
|
|
|
|
EFI_STATUS rc;
|
|
rc = uefi_call_wrapper(RT->SetVariable, 5, L"BootOrder", &global,
|
|
EFI_VARIABLE_NON_VOLATILE |
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
EFI_VARIABLE_RUNTIME_ACCESS,
|
|
size, newbootorder);
|
|
FreePool(newbootorder);
|
|
return rc;
|
|
}
|
|
|
|
EFI_STATUS
|
|
add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
|
|
{
|
|
CHAR16 *fullpath = NULL;
|
|
UINT64 pathlen = 0;
|
|
EFI_STATUS rc = EFI_SUCCESS;
|
|
|
|
rc = make_full_path(dirname, filename, &fullpath, &pathlen);
|
|
if (EFI_ERROR(rc))
|
|
return rc;
|
|
|
|
EFI_DEVICE_PATH *dph = NULL, *dpf = NULL, *dp = NULL;
|
|
|
|
dph = DevicePathFromHandle(this_image->DeviceHandle);
|
|
if (!dph) {
|
|
rc = EFI_OUT_OF_RESOURCES;
|
|
goto err;
|
|
}
|
|
|
|
dpf = FileDevicePath(fh, fullpath);
|
|
if (!dpf) {
|
|
rc = EFI_OUT_OF_RESOURCES;
|
|
goto err;
|
|
}
|
|
|
|
dp = AppendDevicePath(dph, dpf);
|
|
if (!dp) {
|
|
rc = EFI_OUT_OF_RESOURCES;
|
|
goto err;
|
|
}
|
|
|
|
#ifdef DEBUG_FALLBACK
|
|
UINTN s = DevicePathSize(dp);
|
|
int i;
|
|
UINT8 *dpv = (void *)dp;
|
|
for (i = 0; i < s; i++) {
|
|
if (i > 0 && i % 16 == 0)
|
|
Print(L"\n");
|
|
Print(L"%02x ", dpv[i]);
|
|
}
|
|
Print(L"\n");
|
|
|
|
CHAR16 *dps = DevicePathToStr(dp);
|
|
Print(L"device path: \"%s\"\n", dps);
|
|
#endif
|
|
|
|
add_boot_option(dp, fullpath, label, arguments);
|
|
|
|
err:
|
|
if (dpf)
|
|
FreePool(dpf);
|
|
if (dp)
|
|
FreePool(dp);
|
|
if (fullpath)
|
|
FreePool(fullpath);
|
|
return rc;
|
|
}
|
|
|
|
EFI_STATUS
|
|
populate_stanza(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 *csv)
|
|
{
|
|
#ifdef DEBUG_FALLBACK
|
|
Print(L"CSV data: \"%s\"\n", csv);
|
|
#endif
|
|
CHAR16 *file = csv;
|
|
|
|
UINTN comma0 = StrCSpn(csv, L",");
|
|
if (comma0 == 0)
|
|
return EFI_INVALID_PARAMETER;
|
|
file[comma0] = L'\0';
|
|
#ifdef DEBUG_FALLBACK
|
|
Print(L"filename: \"%s\"\n", file);
|
|
#endif
|
|
|
|
CHAR16 *label = csv + comma0 + 1;
|
|
UINTN comma1 = StrCSpn(label, L",");
|
|
if (comma1 == 0)
|
|
return EFI_INVALID_PARAMETER;
|
|
label[comma1] = L'\0';
|
|
#ifdef DEBUG_FALLBACK
|
|
Print(L"label: \"%s\"\n", label);
|
|
#endif
|
|
|
|
CHAR16 *arguments = csv + comma0 +1 + comma1 +1;
|
|
UINTN comma2 = StrCSpn(arguments, L",");
|
|
arguments[comma2] = L'\0';
|
|
/* This one is optional, so don't check if comma2 is 0 */
|
|
#ifdef DEBUG_FALLBACK
|
|
Print(L"arguments: \"%s\"\n", arguments);
|
|
#endif
|
|
|
|
add_to_boot_list(fh, dirname, file, label, arguments);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename)
|
|
{
|
|
CHAR16 *fullpath = NULL;
|
|
UINT64 pathlen = 0;
|
|
EFI_STATUS rc;
|
|
|
|
rc = make_full_path(dirname, filename, &fullpath, &pathlen);
|
|
if (EFI_ERROR(rc))
|
|
return rc;
|
|
|
|
#ifdef DEBUG_FALLBACK
|
|
Print(L"Found file \"%s\"\n", fullpath);
|
|
#endif
|
|
|
|
CHAR16 *buffer;
|
|
UINT64 bs;
|
|
rc = read_file(fh, fullpath, &buffer, &bs);
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Could not read file \"%s\": %d\n", fullpath, rc);
|
|
FreePool(fullpath);
|
|
return rc;
|
|
}
|
|
FreePool(fullpath);
|
|
|
|
#ifdef DEBUG_FALLBACK
|
|
Print(L"File looks like:\n%s\n", buffer);
|
|
#endif
|
|
|
|
CHAR16 *start = buffer;
|
|
/* If I create boot.csv with the efi shell's "edit" command,
|
|
* it starts with 0xfeff. I assume there's some reason for this,
|
|
* but it doesn't matter much to me...
|
|
*/
|
|
if (*start == 0xfeff)
|
|
start++;
|
|
while (*start) {
|
|
while (*start == L'\r' || *start == L'\n')
|
|
start++;
|
|
UINTN l = StrCSpn(start, L"\r\n");
|
|
if (l == 0) {
|
|
if (start[l] == L'\0')
|
|
break;
|
|
start++;
|
|
continue;
|
|
}
|
|
CHAR16 c = start[l];
|
|
start[l] = L'\0';
|
|
|
|
populate_stanza(fh, dirname, filename, start);
|
|
|
|
start[l] = c;
|
|
start += l;
|
|
}
|
|
|
|
FreePool(buffer);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
find_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname)
|
|
{
|
|
EFI_STATUS rc;
|
|
void *buffer = NULL;
|
|
UINTN bs = 0;
|
|
EFI_GUID finfo = EFI_FILE_INFO_ID;
|
|
|
|
/* The API here is "Call it once with bs=0, it fills in bs,
|
|
* then allocate a buffer and ask again to get it filled. */
|
|
rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo, &bs, NULL);
|
|
if (rc == EFI_BUFFER_TOO_SMALL) {
|
|
buffer = AllocateZeroPool(bs);
|
|
if (!buffer) {
|
|
Print(L"Could not allocate memory\n");
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
rc = uefi_call_wrapper(fh->GetInfo, 4, fh, &finfo,
|
|
&bs, buffer);
|
|
}
|
|
/* This checks *either* the error from the first GetInfo, if it isn't
|
|
* the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo call
|
|
* in *any* case. */
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Could not get info for \"%s\": %d\n", dirname, rc);
|
|
if (buffer)
|
|
FreePool(buffer);
|
|
return rc;
|
|
}
|
|
|
|
EFI_FILE_INFO *fi = buffer;
|
|
if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
|
|
FreePool(buffer);
|
|
return EFI_SUCCESS;
|
|
}
|
|
FreePool(buffer);
|
|
|
|
bs = 0;
|
|
do {
|
|
bs = 0;
|
|
rc = uefi_call_wrapper(fh->Read, 3, fh, &bs, NULL);
|
|
if (rc == EFI_BUFFER_TOO_SMALL) {
|
|
buffer = AllocateZeroPool(bs);
|
|
if (!buffer) {
|
|
Print(L"Could not allocate memory\n");
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
rc = uefi_call_wrapper(fh->Read, 3, fh, &bs, buffer);
|
|
}
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Could not read \\EFI\\%s\\: %d\n", dirname, rc);
|
|
FreePool(buffer);
|
|
return rc;
|
|
}
|
|
if (bs == 0)
|
|
break;
|
|
|
|
fi = buffer;
|
|
|
|
if (!StrCaseCmp(fi->FileName, L"boot.csv")) {
|
|
EFI_FILE_HANDLE fh2;
|
|
rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2,
|
|
fi->FileName,
|
|
EFI_FILE_READ_ONLY, 0);
|
|
if (EFI_ERROR(rc) || fh2 == NULL) {
|
|
Print(L"Couldn't open \\EFI\\%s\\%s: %d\n",
|
|
dirname, fi->FileName, rc);
|
|
FreePool(buffer);
|
|
buffer = NULL;
|
|
continue;
|
|
}
|
|
rc = try_boot_csv(fh2, dirname, fi->FileName);
|
|
uefi_call_wrapper(fh2->Close, 1, fh2);
|
|
}
|
|
|
|
FreePool(buffer);
|
|
buffer = NULL;
|
|
} while (bs != 0);
|
|
|
|
rc = EFI_SUCCESS;
|
|
if (nbootorder > 0)
|
|
rc = update_boot_order();
|
|
|
|
return rc;
|
|
}
|
|
|
|
EFI_STATUS
|
|
find_boot_options(EFI_HANDLE device)
|
|
{
|
|
EFI_STATUS rc = EFI_SUCCESS;
|
|
|
|
EFI_FILE_IO_INTERFACE *fio = NULL;
|
|
rc = uefi_call_wrapper(BS->HandleProtocol, 3, device,
|
|
&FileSystemProtocol, &fio);
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Couldn't find file system: %d\n", rc);
|
|
return rc;
|
|
}
|
|
|
|
/* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
|
|
* *no idea* what frees the memory allocated here. Hopefully
|
|
* Close() does. */
|
|
EFI_FILE_HANDLE fh = NULL;
|
|
rc = uefi_call_wrapper(fio->OpenVolume, 2, fio, &fh);
|
|
if (EFI_ERROR(rc) || fh == NULL) {
|
|
Print(L"Couldn't open file system: %d\n", rc);
|
|
return rc;
|
|
}
|
|
|
|
EFI_FILE_HANDLE fh2 = NULL;
|
|
rc = uefi_call_wrapper(fh->Open, 5, fh, &fh2, L"EFI",
|
|
EFI_FILE_READ_ONLY, 0);
|
|
if (EFI_ERROR(rc) || fh2 == NULL) {
|
|
Print(L"Couldn't open EFI: %d\n", rc);
|
|
uefi_call_wrapper(fh->Close, 1, fh);
|
|
return rc;
|
|
}
|
|
rc = uefi_call_wrapper(fh2->SetPosition, 2, fh2, 0);
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Couldn't set file position: %d\n", rc);
|
|
uefi_call_wrapper(fh2->Close, 1, fh2);
|
|
uefi_call_wrapper(fh->Close, 1, fh);
|
|
return rc;
|
|
}
|
|
|
|
void *buffer;
|
|
UINTN bs;
|
|
do {
|
|
bs = 0;
|
|
rc = uefi_call_wrapper(fh2->Read, 3, fh2, &bs, NULL);
|
|
if (rc == EFI_BUFFER_TOO_SMALL ||
|
|
(rc == EFI_SUCCESS && bs != 0)) {
|
|
buffer = AllocateZeroPool(bs);
|
|
if (!buffer) {
|
|
Print(L"Could not allocate memory\n");
|
|
/* sure, this might work, why not? */
|
|
uefi_call_wrapper(fh2->Close, 1, fh2);
|
|
uefi_call_wrapper(fh->Close, 1, fh);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
rc = uefi_call_wrapper(fh2->Read, 3, fh2, &bs, buffer);
|
|
}
|
|
if (bs == 0)
|
|
break;
|
|
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Could not read \\EFI\\: %d\n", rc);
|
|
if (buffer) {
|
|
FreePool(buffer);
|
|
buffer = NULL;
|
|
}
|
|
uefi_call_wrapper(fh2->Close, 1, fh2);
|
|
uefi_call_wrapper(fh->Close, 1, fh);
|
|
return rc;
|
|
}
|
|
EFI_FILE_INFO *fi = buffer;
|
|
|
|
if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
|
|
FreePool(buffer);
|
|
buffer = NULL;
|
|
continue;
|
|
}
|
|
if (!StrCmp(fi->FileName, L".") ||
|
|
!StrCmp(fi->FileName, L"..") ||
|
|
!StrCaseCmp(fi->FileName, L"BOOT")) {
|
|
FreePool(buffer);
|
|
buffer = NULL;
|
|
continue;
|
|
}
|
|
#ifdef DEBUG_FALLBACK
|
|
Print(L"Found directory named \"%s\"\n", fi->FileName);
|
|
#endif
|
|
|
|
EFI_FILE_HANDLE fh3;
|
|
rc = uefi_call_wrapper(fh->Open, 5, fh2, &fh3, fi->FileName,
|
|
EFI_FILE_READ_ONLY, 0);
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"%d Couldn't open %s: %d\n", __LINE__, fi->FileName, rc);
|
|
FreePool(buffer);
|
|
buffer = NULL;
|
|
continue;
|
|
}
|
|
|
|
rc = find_boot_csv(fh3, fi->FileName);
|
|
FreePool(buffer);
|
|
buffer = NULL;
|
|
if (rc == EFI_OUT_OF_RESOURCES)
|
|
break;
|
|
|
|
} while (1);
|
|
|
|
uefi_call_wrapper(fh2->Close, 1, fh2);
|
|
uefi_call_wrapper(fh->Close, 1, fh);
|
|
return EFI_SUCCESS;
|
|
}
|
|
EFI_STATUS
|
|
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
|
|
{
|
|
EFI_STATUS rc;
|
|
|
|
InitializeLib(image, systab);
|
|
|
|
rc = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (void *)&this_image);
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Error: could not find loaded image: %d\n", rc);
|
|
return rc;
|
|
}
|
|
|
|
Print(L"System BootOrder not found. Initializing defaults.\n");
|
|
|
|
rc = find_boot_options(this_image->DeviceHandle);
|
|
if (EFI_ERROR(rc)) {
|
|
Print(L"Error: could not find boot options: %d\n", rc);
|
|
return rc;
|
|
}
|
|
|
|
Print(L"Reset System\n");
|
|
uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
|
|
EFI_SUCCESS, 0, NULL);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|