summaryrefslogtreecommitdiff
path: root/fallback.c
diff options
context:
space:
mode:
authorSteve McIntyre <steve@einval.com>2021-03-23 23:49:46 +0000
committerSteve McIntyre <steve@einval.com>2021-03-23 23:49:46 +0000
commit031e5cce385d3f96b1caa1d53495332a7eb03749 (patch)
treeb4988dfbd191b2242b9294e24075b39a608b1155 /fallback.c
parent7bf7a6d0852382bb645119b18df3ff461aaba247 (diff)
downloadefi-boot-shim-upstream/15.3.tar.gz
efi-boot-shim-upstream/15.3.zip
New upstream version 15.3upstream/15.3
Diffstat (limited to 'fallback.c')
-rw-r--r--fallback.c194
1 files changed, 151 insertions, 43 deletions
diff --git a/fallback.c b/fallback.c
index c3f5583c..8d89917a 100644
--- a/fallback.c
+++ b/fallback.c
@@ -1,22 +1,20 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
- * Copyright 2012-2013 Red Hat, Inc.
- * All rights reserved.
- *
- * See "COPYING" for license terms.
- *
- * Author(s): Peter Jones <pjones@redhat.com>
+ * Copyright Red Hat, Inc.
+ * Copyright Peter Jones <pjones@redhat.com>
*/
-
-#include <efi.h>
-#include <efilib.h>
-
#include "shim.h"
+#define NO_REBOOT L"FB_NO_REBOOT"
+
EFI_LOADED_IMAGE *this_image = NULL;
int
get_fallback_verbose(void)
{
+#ifdef FALLBACK_VERBOSE
+ return 1;
+#else
UINT8 *data = NULL;
UINTN dataSize = 0;
EFI_STATUS efi_status;
@@ -44,6 +42,7 @@ get_fallback_verbose(void)
if (data)
FreePool(data);
return state;
+#endif
}
#define VerbosePrintUnprefixed(fmt, ...) \
@@ -54,14 +53,15 @@ get_fallback_verbose(void)
ret_; \
})
-#define VerbosePrint(fmt, ...) \
- ({ UINTN line_ = __LINE__; \
- UINTN ret_ = 0; \
- if (get_fallback_verbose()) { \
- console_print(L"%a:%d: ", __func__, line_); \
- ret_ = console_print((fmt), ##__VA_ARGS__); \
- } \
- ret_; \
+#define VerbosePrint(fmt, ...) \
+ ({ \
+ UINTN line_ = __LINE__ - 2; \
+ UINTN ret_ = 0; \
+ if (get_fallback_verbose()) { \
+ console_print(L"%a:%d: ", __func__, line_); \
+ ret_ = console_print((fmt), ##__VA_ARGS__); \
+ } \
+ ret_; \
})
static EFI_STATUS
@@ -242,9 +242,9 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
cursor += DevicePathSize(hddp);
StrCpy((CHAR16 *)cursor, arguments);
- console_print(L"Creating boot entry \"%s\" with label \"%s\" "
- L"for file \"%s\"\n",
- varname, label, filename);
+ VerbosePrint(L"Creating boot entry \"%s\" with label \"%s\" "
+ L"for file \"%s\"\n",
+ varname, label, filename);
if (!first_new_option) {
first_new_option = DuplicateDevicePath(fulldp);
@@ -280,13 +280,11 @@ add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
}
bootorder = newbootorder;
nbootorder += 1;
-#ifdef DEBUG_FALLBACK
- console_print(L"nbootorder: %d\nBootOrder: ",
+ VerbosePrint(L"nbootorder: %d\nBootOrder: ",
nbootorder);
for (j = 0 ; j < nbootorder ; j++)
- console_print(L"%04x ", bootorder[j]);
- console_print(L"\n");
-#endif
+ VerbosePrintUnprefixed(L"%04x ", bootorder[j]);
+ VerbosePrintUnprefixed(L"\n");
return EFI_SUCCESS;
}
@@ -398,8 +396,9 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
CHAR16 *filename, CHAR16 *label, CHAR16 *arguments,
UINT16 *optnum)
{
+ unsigned int label_size = StrLen(label)*2 + 2;
unsigned int size = sizeof(UINT32) + sizeof (UINT16) +
- StrLen(label)*2 + 2 + DevicePathSize(dp) +
+ label_size + DevicePathSize(dp) +
StrLen(arguments) * 2;
CHAR8 *data = AllocateZeroPool(size + 2);
@@ -411,15 +410,14 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
*(UINT16 *)cursor = DevicePathSize(dp);
cursor += sizeof (UINT16);
StrCpy((CHAR16 *)cursor, label);
- cursor += StrLen(label)*2 + 2;
+ cursor += label_size;
CopyMem(cursor, dp, DevicePathSize(dp));
cursor += DevicePathSize(dp);
StrCpy((CHAR16 *)cursor, arguments);
- int i = 0;
- CHAR16 varname[] = L"Boot0000";
- CHAR16 hexmap[] = L"0123456789ABCDEF";
+ CHAR16 varname[256];
EFI_STATUS efi_status;
+ EFI_GUID vendor_guid = NullGuid;
UINTN max_candidate_size = calc_masked_boot_option_size(size);
CHAR8 *candidate = AllocateZeroPool(max_candidate_size);
@@ -428,11 +426,18 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
return EFI_OUT_OF_RESOURCES;
}
- for(i = 0; i < nbootorder && i < 0x10000; i++) {
- varname[4] = hexmap[(bootorder[i] & 0xf000) >> 12];
- varname[5] = hexmap[(bootorder[i] & 0x0f00) >> 8];
- varname[6] = hexmap[(bootorder[i] & 0x00f0) >> 4];
- varname[7] = hexmap[(bootorder[i] & 0x000f) >> 0];
+ varname[0] = 0;
+ while (1) {
+ UINTN varname_size = sizeof(varname);
+ efi_status = gRT->GetNextVariableName(&varname_size, varname,
+ &vendor_guid);
+ if (EFI_ERROR(efi_status))
+ break;
+
+ if (StrLen(varname) != 8 || StrnCmp(varname, L"Boot", 4) ||
+ !isxdigit(varname[4]) || !isxdigit(varname[5]) ||
+ !isxdigit(varname[6]) || !isxdigit(varname[7]))
+ continue;
UINTN candidate_size = max_candidate_size;
efi_status = gRT->GetVariable(varname, &GV_GUID, NULL,
@@ -457,7 +462,7 @@ find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
}
- *optnum = i;
+ *optnum = xtoi(varname + 4);
FreePool(candidate);
FreePool(data);
return EFI_SUCCESS;
@@ -475,8 +480,15 @@ set_boot_order(void)
oldbootorder = LibGetVariableAndSize(L"BootOrder", &GV_GUID, &size);
if (oldbootorder) {
+ int i;
nbootorder = size / sizeof (CHAR16);
bootorder = oldbootorder;
+
+ VerbosePrint(L"Original nbootorder: %d\nOriginal BootOrder: ",
+ nbootorder);
+ for (i = 0 ; i < nbootorder ; i++)
+ VerbosePrintUnprefixed(L"%04x ", bootorder[i]);
+ VerbosePrintUnprefixed(L"\n");
}
return EFI_SUCCESS;
@@ -500,7 +512,7 @@ update_boot_order(void)
UINTN j;
for (j = 0 ; j < size / sizeof (CHAR16); j++)
VerbosePrintUnprefixed(L"%04x ", newbootorder[j]);
- console_print(L"\n");
+ VerbosePrintUnprefixed(L"\n");
efi_status = gRT->GetVariable(L"BootOrder", &GV_GUID, NULL, &len, NULL);
if (efi_status == EFI_BUFFER_TOO_SMALL)
LibDeleteVariable(L"BootOrder", &GV_GUID);
@@ -600,7 +612,7 @@ err:
}
EFI_STATUS
-populate_stanza(CHAR16 *dirname, CHAR16 *filename, CHAR16 *csv)
+populate_stanza(CHAR16 *dirname, CHAR16 *filename UNUSED, CHAR16 *csv)
{
CHAR16 *file = csv;
VerbosePrint(L"CSV data: \"%s\"\n", csv);
@@ -933,6 +945,17 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
EFI_STATUS efi_status;
EFI_HANDLE image_handle;
+ if (get_fallback_verbose()) {
+ int fallback_verbose_wait = 500000; /* default to 0.5s */
+#ifdef FALLBACK_VERBOSE_WAIT
+ fallback_verbose_wait = FALLBACK_VERBOSE_WAIT;
+#endif
+ console_print(L"Verbose enabled, sleeping for %d mseconds... "
+ L"Press the Pause key now to hold for longer.\n",
+ fallback_verbose_wait);
+ msleep(fallback_verbose_wait);
+ }
+
if (!first_new_option) {
return EFI_SUCCESS;
}
@@ -973,6 +996,65 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
return efi_status;
}
+static UINT32
+get_fallback_no_reboot(void)
+{
+ EFI_STATUS efi_status;
+ UINT32 no_reboot;
+ UINTN size = sizeof(UINT32);
+
+ efi_status = gRT->GetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
+ NULL, &size, &no_reboot);
+ if (!EFI_ERROR(efi_status)) {
+ return no_reboot;
+ }
+ return 0;
+}
+
+static EFI_STATUS
+set_fallback_no_reboot(void)
+{
+ EFI_STATUS efi_status;
+ UINT32 no_reboot = 1;
+ efi_status = gRT->SetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
+ EFI_VARIABLE_NON_VOLATILE
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(UINT32), &no_reboot);
+ return efi_status;
+}
+
+static int
+draw_countdown(void)
+{
+ CHAR16 *title = L"Boot Option Restoration";
+ CHAR16 *message = L"Press any key to stop system reset";
+ int timeout;
+
+ timeout = console_countdown(title, message, 5);
+
+ return timeout;
+}
+
+static int
+get_user_choice(void)
+{
+ int choice;
+ CHAR16 *title[] = {L"Boot Option Restored", NULL};
+ CHAR16 *menu_strings[] = {
+ L"Reset system",
+ L"Continue boot",
+ L"Always continue boot",
+ NULL
+ };
+
+ do {
+ choice = console_select(title, menu_strings, 0);
+ } while (choice < 0 || choice > 2);
+
+ return choice;
+}
+
extern EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
@@ -983,7 +1065,7 @@ debug_hook(void)
UINT8 *data = NULL;
UINTN dataSize = 0;
EFI_STATUS efi_status;
- volatile register int x = 0;
+ register volatile int x = 0;
extern char _etext, _edata;
efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize,
@@ -1023,7 +1105,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
return efi_status;
}
- console_print(L"System BootOrder not found. Initializing defaults.\n");
+ VerbosePrint(L"System BootOrder not found. Initializing defaults.\n");
set_boot_order();
@@ -1039,14 +1121,40 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
VerbosePrint(L"tpm not present, starting the first image\n");
try_start_first_option(image);
} else {
+ if (get_fallback_no_reboot() == 1) {
+ VerbosePrint(L"NO_REBOOT is set, starting the first image\n");
+ try_start_first_option(image);
+ }
+
+ int timeout = draw_countdown();
+ if (timeout == 0)
+ goto reset;
+
+ int choice = get_user_choice();
+ if (choice == 0) {
+ goto reset;
+ } else if (choice == 2) {
+ efi_status = set_fallback_no_reboot();
+ if (EFI_ERROR(efi_status))
+ goto reset;
+ }
+ VerbosePrint(L"tpm present, starting the first image\n");
+ try_start_first_option(image);
+reset:
VerbosePrint(L"tpm present, resetting system\n");
}
console_print(L"Reset System\n");
if (get_fallback_verbose()) {
- console_print(L"Verbose enabled, sleeping for half a second\n");
- msleep(500000);
+ int fallback_verbose_wait = 500000; /* default to 0.5s */
+#ifdef FALLBACK_VERBOSE_WAIT
+ fallback_verbose_wait = FALLBACK_VERBOSE_WAIT;
+#endif
+ console_print(L"Verbose enabled, sleeping for %d mseconds... "
+ L"Press the Pause key now to hold for longer.\n",
+ fallback_verbose_wait);
+ msleep(fallback_verbose_wait);
}
gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);