From eb9f7f1c23e682040240aaa399efa33488875fe9 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 30 Apr 2013 09:46:22 -0400 Subject: Add a fallback loader for when shim is invoked as BOOTX64.EFI If shim is invoked as \EFI\BOOT\BOOT*.EFI and a file exists named \EFI\BOOT\FALLBACK.EFI, try it instead of our second stage. So don't put fallback.efi on your install media in \EFI\BOOT, because that won't do whatever it is you're hoping for, unless you're hoping not to start the installer. So here's the process for using this: in /EFI/fedora/ (or whichever directory you happen to own), you put: shim.efi grub.efi boot.csv - format is: shim.efi,Nice Label,cmdline arguments,comments - filenames refer only to files in this directory, with no leading characters such as L"./" or L"/EFI/fedora/" - note that while this is CSV, the character encoding is UCS-2 and if /EFI/BOOT/BOOTX64.EFI doesn't already exist, then in /EFI/BOOT: shim.efi as BOOTX64.EFI fallback.efi Signed-off-by: Peter Jones --- fallback.c | 619 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 619 insertions(+) create mode 100644 fallback.c (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c new file mode 100644 index 00000000..8f9bcbe9 --- /dev/null +++ b/fallback.c @@ -0,0 +1,619 @@ +/* + * Copyright 2012-2013 Red Hat, Inc. + * All rights reserved. + * + * See "COPYING" for license terms. + * + * Author(s): Peter Jones + */ + +#include +#include + +#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); + 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)); + CopyMem(newbootorder, bootorder, nbootorder * sizeof (CHAR16)); + CopyMem(newbootorder + nbootorder, oldbootorder, size); + size = n * sizeof (CHAR16); + } else { + size = nbootorder * sizeof(CHAR16); + newbootorder = AllocateZeroPool(size); + CopyMem(newbootorder, bootorder, size); + } + if (!newbootorder) + return EFI_OUT_OF_RESOURCES; + +#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); + FreePool(fullpath); + +err: + if (dph) + FreePool(dph); + 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++; + continue; + } + 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; + } + + return EFI_SUCCESS; +} -- cgit v1.2.3 From e172354b7ebe7850565208260e9ffff6bf679283 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 30 Apr 2013 09:46:22 -0400 Subject: Fix error checking on AllocateZeroPool() in update_boot_order() Signed-off-by: Peter Jones --- fallback.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c index 8f9bcbe9..7f4f8836 100644 --- a/fallback.c +++ b/fallback.c @@ -203,16 +203,18 @@ update_boot_order(void) 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); } - if (!newbootorder) - return EFI_OUT_OF_RESOURCES; #ifdef DEBUG_FALLBACK Print(L"nbootorder: %d\nBootOrder: ", size / sizeof (CHAR16)); -- cgit v1.2.3 From 404e12634438db526db3cebbff2e1899a2e3431a Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 30 Apr 2013 09:46:22 -0400 Subject: Get rid of extra "continue". It's confusing, and it doesn't actually accomplish anything when applied to *either* loop. Signed-off-by: Peter Jones --- fallback.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c index 7f4f8836..00017225 100644 --- a/fallback.c +++ b/fallback.c @@ -375,10 +375,8 @@ try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename) if (*start == 0xfeff) start++; while (*start) { - while (*start == L'\r' || *start == L'\n') { + while (*start == L'\r' || *start == L'\n') start++; - continue; - } UINTN l = StrCSpn(start, L"\r\n"); if (l == 0) { if (start[l] == L'\0') -- cgit v1.2.3 From 17266fd0578e36dc9da0d5b52b017605d93554b0 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Tue, 30 Apr 2013 09:46:23 -0400 Subject: Fix crash due to memory allocation --- fallback.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c index 00017225..5ba0b797 100644 --- a/fallback.c +++ b/fallback.c @@ -95,7 +95,7 @@ make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen) len = StrLen(dirname) + StrLen(filename) + StrLen(L"\\EFI\\\\") + 2; - CHAR16 *fullpath = AllocateZeroPool(len); + CHAR16 *fullpath = AllocateZeroPool(len*sizeof(CHAR16)); if (!fullpath) { Print(L"Could not allocate memory\n"); return EFI_OUT_OF_RESOURCES; @@ -286,11 +286,8 @@ add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 * #endif add_boot_option(dp, fullpath, label, arguments); - FreePool(fullpath); err: - if (dph) - FreePool(dph); if (dpf) FreePool(dpf); if (dp) -- cgit v1.2.3 From 117b1214d84392675f537ddfc126cd6e3d41facf Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Tue, 30 Apr 2013 09:46:23 -0400 Subject: Reset the system after restoring the boot entries --- fallback.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c index 5ba0b797..6cc59aa6 100644 --- a/fallback.c +++ b/fallback.c @@ -612,5 +612,9 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) return rc; } + Print(L"Reset System\n"); + uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, + EFI_SUCCESS, 0, NULL); + return EFI_SUCCESS; } -- cgit v1.2.3 From 39baf6dff76ac3ab16d8831144a382f1ea6e9085 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Tue, 30 Apr 2013 09:46:23 -0400 Subject: Don't update BootOrder until all csv files are processed --- fallback.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c index 6cc59aa6..d3179b6c 100644 --- a/fallback.c +++ b/fallback.c @@ -475,8 +475,6 @@ find_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname) } while (bs != 0); rc = EFI_SUCCESS; - if (nbootorder > 0) - rc = update_boot_order(); return rc; } @@ -587,9 +585,12 @@ find_boot_options(EFI_HANDLE device) } while (1); + if (rc == EFI_SUCCESS && nbootorder > 0) + rc = update_boot_order(); + uefi_call_wrapper(fh2->Close, 1, fh2); uefi_call_wrapper(fh->Close, 1, fh); - return EFI_SUCCESS; + return rc; } EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) -- cgit v1.2.3 From 4f80140b53ba290f3fb2dd4cf9af4637b28f24ed Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 30 Apr 2013 14:21:41 -0400 Subject: Explain byte order handling better. Signed-off-by: Peter Jones --- fallback.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c index d3179b6c..dab3d3dc 100644 --- a/fallback.c +++ b/fallback.c @@ -365,9 +365,13 @@ try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename) #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... + /* The file may or may not start with the Unicode byte order marker. + * Sadness ensues. Since UEFI is defined as LE, I'm going to decree + * that these files must also be LE. + * + * IT IS THUS SO. + * + * But if we find the LE byte order marker, just skip it. */ if (*start == 0xfeff) start++; -- cgit v1.2.3 From 8807e36aaecfa2c4c67b33480cf44182518e313c Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 2 May 2013 14:58:44 -0400 Subject: [fallback] Try to execute the first new boot option. I'm told rebooting is sometimes unreliable when called here, and we'll get bootx64.efi loaded anyway. I'll just assume that's true and try to load the first option, since it's clearly what we'd prefer happens next. Signed-off-by: Peter Jones --- fallback.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c index dab3d3dc..387c84a8 100644 --- a/fallback.c +++ b/fallback.c @@ -114,6 +114,10 @@ make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen) CHAR16 *bootorder = NULL; int nbootorder = 0; +EFI_DEVICE_PATH *first_new_option = NULL; +VOID *first_new_option_args = NULL; +UINTN first_new_option_size = 0; + EFI_STATUS add_boot_option(EFI_DEVICE_PATH *dp, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments) { @@ -284,6 +288,13 @@ add_to_boot_list(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename, CHAR16 * CHAR16 *dps = DevicePathToStr(dp); Print(L"device path: \"%s\"\n", dps); #endif + if (!first_new_option) { + CHAR16 *dps = DevicePathToStr(dp); + Print(L"device path: \"%s\"\n", dps); + first_new_option = DuplicateDevicePath(dp); + first_new_option_args = arguments; + first_new_option_size = StrLen(arguments) * sizeof (CHAR16); + } add_boot_option(dp, fullpath, label, arguments); @@ -596,6 +607,33 @@ find_boot_options(EFI_HANDLE device) uefi_call_wrapper(fh->Close, 1, fh); return rc; } + +static EFI_STATUS +try_start_first_option(EFI_HANDLE parent_image_handle) +{ + EFI_STATUS rc; + EFI_HANDLE image_handle; + + if (!first_new_option) { + return EFI_SUCCESS; + } + + rc = uefi_call_wrapper(BS->LoadImage, 6, 0, parent_image_handle, + first_new_option, NULL, 0, + &image_handle); + if (EFI_ERROR(rc)) { + Print(L"LoadImage failed: %d\n", rc); + uefi_call_wrapper(BS->Stall, 1, 2000000); + return rc; + } + rc = uefi_call_wrapper(BS->StartImage, 3, image_handle, NULL, NULL); + if (EFI_ERROR(rc)) { + Print(L"StartImage failed: %d\n", rc); + uefi_call_wrapper(BS->Stall, 1, 2000000); + } + return rc; +} + EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) { @@ -617,8 +655,10 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) return rc; } + try_start_first_option(image); + Print(L"Reset System\n"); - uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, + uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold, EFI_SUCCESS, 0, NULL); return EFI_SUCCESS; -- cgit v1.2.3 From 40cf2a423d7a080999cb22d0cb0bae33ab028c62 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Tue, 14 May 2013 13:10:52 -0400 Subject: Pass parameters correctly when booting. Signed-off-by: Peter Jones --- fallback.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c index 387c84a8..cf1ebe46 100644 --- a/fallback.c +++ b/fallback.c @@ -626,6 +626,14 @@ try_start_first_option(EFI_HANDLE parent_image_handle) uefi_call_wrapper(BS->Stall, 1, 2000000); return rc; } + + EFI_LOADED_IMAGE *image; + rc = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle, &LoadedImageProtocol, (void *)&image); + if (!EFI_ERROR(rc)) { + image->LoadOptions = first_new_option_args; + image->LoadOptionsSize = first_new_option_size; + } + rc = uefi_call_wrapper(BS->StartImage, 3, image_handle, NULL, NULL); if (EFI_ERROR(rc)) { Print(L"StartImage failed: %d\n", rc); -- cgit v1.2.3 From 35b0b55b3ee0f6d6771c7992b8fefffc54bda48e Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 15 May 2013 13:37:15 -0400 Subject: Fix some minor type errors. Signed-off-by: Peter Jones --- fallback.c | 2 +- shim.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'fallback.c') diff --git a/fallback.c b/fallback.c index cf1ebe46..82ddbf2f 100644 --- a/fallback.c +++ b/fallback.c @@ -501,7 +501,7 @@ find_boot_options(EFI_HANDLE device) EFI_FILE_IO_INTERFACE *fio = NULL; rc = uefi_call_wrapper(BS->HandleProtocol, 3, device, - &FileSystemProtocol, &fio); + &FileSystemProtocol, (void **)&fio); if (EFI_ERROR(rc)) { Print(L"Couldn't find file system: %d\n", rc); return rc; diff --git a/shim.c b/shim.c index f2b8f1d1..c1cf17ae 100644 --- a/shim.c +++ b/shim.c @@ -910,8 +910,8 @@ should_use_fallback(EFI_HANDLE image_handle) unsigned int pathlen = 0; CHAR16 *bootpath; EFI_FILE_IO_INTERFACE *fio = NULL; - EFI_FILE_HANDLE vh; - EFI_FILE_HANDLE fh; + EFI_FILE *vh; + EFI_FILE *fh; EFI_STATUS rc; rc = uefi_call_wrapper(BS->HandleProtocol, 3, image_handle, @@ -943,7 +943,7 @@ should_use_fallback(EFI_HANDLE image_handle) bootpath[i+1] = '\0'; rc = uefi_call_wrapper(BS->HandleProtocol, 3, li->DeviceHandle, - &FileSystemProtocol, &fio); + &FileSystemProtocol, (void **)&fio); if (EFI_ERROR(rc)) return 0; -- cgit v1.2.3