]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-boot: Rearm the watchdog in console_key_read
authorJan Janssen <medhefgo@web.de>
Tue, 28 Sep 2021 08:57:06 +0000 (10:57 +0200)
committerJan Janssen <medhefgo@web.de>
Sun, 17 Oct 2021 09:52:36 +0000 (11:52 +0200)
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.

src/boot/efi/boot.c
src/boot/efi/console.c

index 71e645a6080680062c654d1aad6b1a5c886ec15d..4c64d1c7e809f638ee7e3c96188b5763ed14e286 100644 (file)
@@ -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);
index b581c21bdab0c69d4ed45892de56b720ff6cde34..42e3af614bf2df419c6aa301c09936541ce562ec 100644 (file)
@@ -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))) {