Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.5:Update
shim.12337
shim-bsc1092000-fallback-menu.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File shim-bsc1092000-fallback-menu.patch of Package shim.12337
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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor