From: Jan Janssen Date: Tue, 28 Sep 2021 08:57:06 +0000 (+0200) Subject: sd-boot: Rearm the watchdog in console_key_read X-Git-Tag: v250-rc1~473^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6ae9a5a0bb064475dc538f79b2714a42a4bb6fd5;p=thirdparty%2Fsystemd.git sd-boot: Rearm the watchdog in console_key_read Let's not disable the watchdog at all and instead rearm it inside of console_key_read(). This way, we are covered by the watchdog everywhere. --- diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 71e645a6080..4c64d1c7e80 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -449,7 +449,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { Print(L"OsIndicationsSupported: %d\n", get_os_indications_supported()); Print(L"\n--- press key ---\n\n"); - console_key_read(&key, 0); + console_key_read(&key, UINT64_MAX); Print(L"timeout: %u s\n", config->timeout_sec); if (config->timeout_sec_efivar != TIMEOUT_UNSET) @@ -495,7 +495,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { Print(L"LoaderEntryDefault: %s\n", defaultstr); Print(L"\n--- press key ---\n\n"); - console_key_read(&key, 0); + console_key_read(&key, UINT64_MAX); for (UINTN i = 0; i < config->entry_count; i++) { ConfigEntry *entry; @@ -547,7 +547,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { entry->path, entry->next_name); Print(L"\n--- press key ---\n\n"); - console_key_read(&key, 0); + console_key_read(&key, UINT64_MAX); } } @@ -724,7 +724,7 @@ static BOOLEAN menu_run( uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1 + x + len); } - err = console_key_read(&key, timeout_remain > 0 ? 1000 * 1000 : 0); + err = console_key_read(&key, timeout_remain > 0 ? 1000 * 1000 : UINT64_MAX); if (err == EFI_TIMEOUT) { timeout_remain--; if (timeout_remain == 0) { @@ -2413,7 +2413,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { entry = config.entries[config.idx_default]; if (menu) { efivar_set_time_usec(LOADER_GUID, L"LoaderTimeMenuUSec", 0); - uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x10000, 0, NULL); if (!menu_run(&config, &entry, loaded_image_path)) break; } @@ -2432,7 +2431,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { /* Optionally, read a random seed off the ESP and pass it to the OS */ (VOID) process_random_seed(root_dir, config.random_seed_mode); - uefi_call_wrapper(BS->SetWatchdogTimer, 4, 5 * 60, 0x10000, 0, NULL); err = image_start(root_dir, image, &config, entry); if (EFI_ERROR(err)) { graphics_mode(FALSE); diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c index b581c21bdab..42e3af614bf 100644 --- a/src/boot/efi/console.c +++ b/src/boot/efi/console.c @@ -62,25 +62,48 @@ EFI_STATUS console_key_read(UINT64 *key, UINT64 timeout_usec) { checked = TRUE; } - if (timeout_usec > 0) { - err = uefi_call_wrapper(BS->CreateEvent, 5, EVT_TIMER, 0, NULL, NULL, &timer); - if (EFI_ERROR(err)) - return log_error_status_stall(err, L"Error creating timer event: %r", err); + err = uefi_call_wrapper(BS->CreateEvent, 5, EVT_TIMER, 0, NULL, NULL, &timer); + if (EFI_ERROR(err)) + return log_error_status_stall(err, L"Error creating timer event: %r", err); + events[n_events++] = timer; + + /* Watchdog rearming loop in case the user never provides us with input or some + * broken firmware never returns from WaitForEvent. */ + for (;;) { + UINT64 watchdog_timeout_sec = 5 * 60, + watchdog_ping_usec = watchdog_timeout_sec / 2 * 1000 * 1000; /* SetTimer expects 100ns units for some reason. */ - err = uefi_call_wrapper(BS->SetTimer, 3, timer, TimerRelative, timeout_usec * 10); + err = uefi_call_wrapper( + BS->SetTimer, 3, + timer, + TimerRelative, + MIN(timeout_usec, watchdog_ping_usec) * 10); if (EFI_ERROR(err)) return log_error_status_stall(err, L"Error arming timer event: %r", err); - events[n_events++] = timer; - } + (void) uefi_call_wrapper(BS->SetWatchdogTimer, 4, watchdog_timeout_sec, 0x10000, 0, NULL); + err = uefi_call_wrapper(BS->WaitForEvent, 3, n_events, events, &index); + (void) uefi_call_wrapper(BS->SetWatchdogTimer, 4, watchdog_timeout_sec, 0x10000, 0, NULL); - err = uefi_call_wrapper(BS->WaitForEvent, 3, n_events, events, &index); - if (EFI_ERROR(err)) - return log_error_status_stall(err, L"Error waiting for events: %r", err); + if (EFI_ERROR(err)) + return log_error_status_stall(err, L"Error waiting for events: %r", err); - if (timeout_usec > 0 && timer == events[index]) + /* We have keyboard input, process it after this loop. */ + if (timer != events[index]) + break; + + /* The EFI timer fired instead. If this was a watchdog timeout, loop again. */ + if (timeout_usec == UINT64_MAX) + continue; + else if (timeout_usec > watchdog_ping_usec) { + timeout_usec -= watchdog_ping_usec; + continue; + } + + /* The caller requested a timeout? They shall have one! */ return EFI_TIMEOUT; + } /* TextInputEx might be ready too even if ConIn got to signal first. */ if (TextInputEx && !EFI_ERROR(uefi_call_wrapper(BS->CheckEvent, 1, TextInputEx->WaitForKeyEx))) {