Add shim-bsc1092000-fallback-menu.patch to show a menu before system reset ((bsc#1092000)) OBS-URL: https://build.opensuse.org/request/show/612951 OBS-URL: https://build.opensuse.org/package/show/devel:openSUSE:Factory/shim?expand=0&rev=141
195 lines
5.1 KiB
Diff
195 lines
5.1 KiB
Diff
From 22269728415432718e7757842086785d7daf0cc3 Mon Sep 17 00:00:00 2001
|
|
From: Gary Lin <glin@suse.com>
|
|
Date: Mon, 28 May 2018 10:57:06 +0800
|
|
Subject: [PATCH] fallback: show a countdown menu before reset
|
|
|
|
Some machines with the faulty firmware may keep booting the default boot
|
|
path instead of the boot option we create. To avoid the infinite reset
|
|
loop, this commit introduce a countdown screen before fallback resets the
|
|
system, so the user can interrupt the system reset and choose to boot
|
|
the restored boot option. The "Always continue boot" option creates a
|
|
BS+RT+NV variable, FB_NO_REBOOT, to make fallback boot the first boot
|
|
option afterward without asking. The user can revert the behavior by
|
|
removing the variable.
|
|
|
|
https://github.com/rhboot/shim/issues/128
|
|
https://bugzilla.opensuse.org/show_bug.cgi?id=1092000
|
|
|
|
Signed-off-by: Gary Lin <glin@suse.com>
|
|
---
|
|
fallback.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
1 file changed, 144 insertions(+)
|
|
|
|
diff --git a/fallback.c b/fallback.c
|
|
index 886e052..1f3eb78 100644
|
|
--- a/fallback.c
|
|
+++ b/fallback.c
|
|
@@ -13,6 +13,9 @@
|
|
#include "ucs2.h"
|
|
#include "variables.h"
|
|
#include "tpm.h"
|
|
+#include "console.h"
|
|
+
|
|
+#define NO_REBOOT L"FB_NO_REBOOT"
|
|
|
|
EFI_LOADED_IMAGE *this_image = NULL;
|
|
|
|
@@ -953,6 +956,127 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
|
|
return rc;
|
|
}
|
|
|
|
+static UINT32
|
|
+get_fallback_no_reboot(void)
|
|
+{
|
|
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
|
|
+ EFI_STATUS efi_status;
|
|
+ UINT32 no_reboot;
|
|
+ UINTN size = sizeof(UINT32);
|
|
+
|
|
+ efi_status = uefi_call_wrapper(RT->GetVariable, 5,
|
|
+ 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_GUID shim_lock_guid = SHIM_LOCK_GUID;
|
|
+ EFI_STATUS efi_status;
|
|
+ UINT32 no_reboot = 1;
|
|
+ efi_status = uefi_call_wrapper(RT->SetVariable, 5,
|
|
+ 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 void console_save_and_set_mode (SIMPLE_TEXT_OUTPUT_MODE *SavedMode)
|
|
+{
|
|
+ if (!SavedMode) {
|
|
+ Print(L"Invalid parameter: SavedMode\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ CopyMem(SavedMode, ST->ConOut->Mode, sizeof(SIMPLE_TEXT_OUTPUT_MODE));
|
|
+ uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE);
|
|
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
|
|
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
|
|
+}
|
|
+
|
|
+static void console_restore_mode (SIMPLE_TEXT_OUTPUT_MODE *SavedMode)
|
|
+{
|
|
+ uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut,
|
|
+ SavedMode->CursorVisible);
|
|
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut,
|
|
+ SavedMode->CursorColumn, SavedMode->CursorRow);
|
|
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
|
|
+ SavedMode->Attribute);
|
|
+}
|
|
+
|
|
+static int
|
|
+draw_countdown(void)
|
|
+{
|
|
+ SIMPLE_TEXT_OUTPUT_MODE SavedMode;
|
|
+ EFI_INPUT_KEY key;
|
|
+ EFI_STATUS status;
|
|
+ UINTN cols, rows;
|
|
+ CHAR16 *title[2];
|
|
+ CHAR16 *message = L"Press any key to stop system reset";
|
|
+ int timeout = 5, wait = 10000000;
|
|
+
|
|
+ console_save_and_set_mode (&SavedMode);
|
|
+
|
|
+ title[0] = L"Boot Option Restoration";
|
|
+ title[1] = NULL;
|
|
+
|
|
+ console_print_box_at(title, -1, 0, 0, -1, -1, 1, 1);
|
|
+
|
|
+ uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut,
|
|
+ ST->ConOut->Mode->Mode, &cols, &rows);
|
|
+
|
|
+ PrintAt((cols - StrLen(message))/2, rows/2, message);
|
|
+ while (1) {
|
|
+ if (timeout > 1)
|
|
+ PrintAt(2, rows - 3, L"Booting in %d seconds ", timeout);
|
|
+ else if (timeout)
|
|
+ PrintAt(2, rows - 3, L"Booting in %d second ", timeout);
|
|
+
|
|
+ status = WaitForSingleEvent(ST->ConIn->WaitForKey, wait);
|
|
+
|
|
+ if (status != EFI_TIMEOUT) {
|
|
+ /* Clear the key in the queue */
|
|
+ uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2,
|
|
+ ST->ConIn, &key);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ timeout--;
|
|
+ if (!timeout)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ console_restore_mode(&SavedMode);
|
|
+
|
|
+ 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);
|
|
|
|
@@ -1014,6 +1138,26 @@ 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) {
|
|
+ rc = set_fallback_no_reboot();
|
|
+ if (EFI_ERROR(rc))
|
|
+ goto reset;
|
|
+ }
|
|
+ VerbosePrint(L"tpm present, starting the first image\n");
|
|
+ try_start_first_option(image);
|
|
+reset:
|
|
VerbosePrint(L"tpm present, resetting system\n");
|
|
}
|
|
|
|
--
|
|
2.16.3
|
|
|