]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Disable EFI watchdog timer when shutting down to boot an OS
authorMichael Brown <mcb30@ipxe.org>
Wed, 24 Nov 2021 15:43:46 +0000 (15:43 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 25 Nov 2021 09:30:59 +0000 (09:30 +0000)
The UEFI specification mandates that the EFI watchdog timer should be
disabled by the platform firmware as part of the ExitBootServices()
call, but some platforms (e.g. Hyper-V) are observed to occasionally
forget to do so, resulting in a reboot approximately five minutes
after starting the operating system.

Work around these firmware bugs by disabling the watchdog timer
ourselves.

Requested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Tested-by: Andreas Hammarskjöld <junior@2PintSoftware.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/interface/efi/efi_watchdog.c

index 7061f81d88bb7cb3da450972d4af37ad35eb63a7..dcc9a56680368205b917676cda0eb790204f2961 100644 (file)
@@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <string.h>
 #include <ipxe/retry.h>
 #include <ipxe/timer.h>
+#include <ipxe/init.h>
 #include <ipxe/efi/efi.h>
 #include <ipxe/efi/efi_watchdog.h>
 
@@ -80,3 +81,36 @@ static void efi_watchdog_expired ( struct retry_timer *timer,
 
 /** Watchdog holdoff timer */
 struct retry_timer efi_watchdog = TIMER_INIT ( efi_watchdog_expired );
+
+/**
+ * Disable watching when shutting down to boot an operating system
+ *
+ * @v booting          System is shutting down for OS boot
+ */
+static void efi_watchdog_shutdown ( int booting ) {
+       EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+       EFI_STATUS efirc;
+       int rc;
+
+       /* If we are shutting down to boot an operating system, then
+        * disable the boot services watchdog timer.  The UEFI
+        * specification mandates that the platform firmware does this
+        * as part of the ExitBootServices() call, but some platforms
+        * (e.g. Hyper-V) are observed to occasionally forget to do
+        * so, resulting in a reboot approximately five minutes after
+        * starting the operating system.
+        */
+       if ( booting &&
+            ( ( efirc = bs->SetWatchdogTimer ( 0, 0, 0, NULL ) ) != 0 ) ) {
+               rc = -EEFI ( efirc );
+               DBGC ( &efi_watchdog, "EFI could not disable watchdog timer: "
+                      "%s\n", strerror ( rc ) );
+               /* Nothing we can do */
+       }
+}
+
+/** Watchdog startup/shutdown function */
+struct startup_fn efi_watchdog_startup_fn __startup_fn ( STARTUP_EARLY ) = {
+       .name = "efi_watchdog",
+       .shutdown = efi_watchdog_shutdown,
+};