[PATCH v1 21/54] efi: loader: add watchdog support

Ahmad Fatoum a.fatoum at pengutronix.de
Thu Dec 18 02:37:41 PST 2025


The UEFI standard requires that the watchdog timer is set to five
minutes when invoking an EFI boot option.

Add the necessary support, so we can start configuring the watchdog
where appropriate.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 efi/loader/Makefile   |  1 +
 efi/loader/boot.c     |  2 +-
 efi/loader/watchdog.c | 94 +++++++++++++++++++++++++++++++++++++++++++
 include/efi/loader.h  |  3 ++
 4 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 efi/loader/watchdog.c

diff --git a/efi/loader/Makefile b/efi/loader/Makefile
index bb739210ac1d..640c9707060c 100644
--- a/efi/loader/Makefile
+++ b/efi/loader/Makefile
@@ -8,3 +8,4 @@ obj-y += debug_support.o
 obj-y += boot.o
 obj-y += runtime.o
 obj-y += setup.o
+obj-y += watchdog.o
diff --git a/efi/loader/boot.c b/efi/loader/boot.c
index 1e2496f1ec53..263165135944 100644
--- a/efi/loader/boot.c
+++ b/efi/loader/boot.c
@@ -1831,7 +1831,7 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout,
 {
 	EFI_ENTRY("%ld, 0x%llx, %zu, %p", timeout, watchdog_code,
 		  data_size, watchdog_data);
-	return EFI_EXIT(EFI_UNSUPPORTED);
+	return EFI_EXIT(efi_set_watchdog(timeout));
 }
 
 /**
diff --git a/efi/loader/watchdog.c b/efi/loader/watchdog.c
new file mode 100644
index 000000000000..a4715c149add
--- /dev/null
+++ b/efi/loader/watchdog.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+// SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/e9c34fab18a9a0022b36729afd8e262e062764e2/lib/efi_loader/efi_watchdog.c
+/*
+ *  EFI watchdog
+ *
+ *  Copyright (c) 2017 Heinrich Schuchardt
+ */
+
+#define pr_fmt(fmt) "efi-loader: watchdog: " fmt
+
+#include <linux/printk.h>
+#include <efi/loader.h>
+#include <efi/loader/event.h>
+#include <efi/loader/trace.h>
+#include <efi/services.h>
+#include <efi/error.h>
+#include <init.h>
+
+/* Conversion factor from seconds to multiples of 100ns */
+#define EFI_SECONDS_TO_100NS 10000000ULL
+
+static struct efi_event *watchdog_timer_event;
+
+/**
+ * efi_watchdog_timer_notify() - resets system upon watchdog event
+ *
+ * Reset the system when the watchdog event is notified.
+ *
+ * @event:	the watchdog event
+ * @context:	not used
+ */
+static void EFIAPI efi_watchdog_timer_notify(struct efi_event *event,
+					     void *context)
+{
+	EFI_ENTRY("%p, %p", event, context);
+
+	pr_emerg("\nEFI: Watchdog timeout\n");
+	EFI_CALL_VOID(efi_runtime_services.reset_system(EFI_RESET_COLD,
+							EFI_SUCCESS, 0, NULL));
+
+	EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/**
+ * efi_set_watchdog() - resets the watchdog timer
+ *
+ * This function is used by the SetWatchdogTimer service.
+ *
+ * @timeout:		seconds before reset by watchdog
+ * Return:		status code
+ */
+efi_status_t efi_set_watchdog(unsigned long timeout)
+{
+	efi_status_t r;
+
+	if (timeout)
+		/* Reset watchdog */
+		r = efi_set_timer(watchdog_timer_event, EFI_TIMER_RELATIVE,
+				  EFI_SECONDS_TO_100NS * timeout);
+	else
+		/* Deactivate watchdog */
+		r = efi_set_timer(watchdog_timer_event, EFI_TIMER_CANCEL, 0);
+	return r;
+}
+
+/**
+ * efi_watchdog_register() - initializes the EFI watchdog
+ *
+ * Return:	status code
+ */
+static efi_status_t efi_watchdog_register(void *data)
+{
+	efi_status_t r;
+
+	/*
+	 * Create a timer event.
+	 */
+	r = efi_create_event(EFI_EVT_TIMER | EFI_EVT_NOTIFY_SIGNAL, EFI_TPL_CALLBACK,
+			     efi_watchdog_timer_notify, NULL, NULL,
+			     &watchdog_timer_event);
+	if (r) {
+		pr_err("Failed to register watchdog event\n");
+		return r;
+	}
+
+	return EFI_SUCCESS;
+}
+
+static int efi_watchdog_init(void)
+{
+	efi_register_deferred_init(efi_watchdog_register, NULL);
+	return 0;
+}
+late_initcall(efi_watchdog_init);
diff --git a/include/efi/loader.h b/include/efi/loader.h
index e1a3c1e298c5..ef82a2f5214e 100644
--- a/include/efi/loader.h
+++ b/include/efi/loader.h
@@ -26,6 +26,9 @@ extern struct efi_system_table systab;
 efi_status_t efi_alloc_system_table(void);
 efi_status_t efi_initialize_system_table(void);
 
+/* Called by efi_set_watchdog_timer to reset the timer */
+efi_status_t efi_set_watchdog(unsigned long timeout);
+
 /* Allocate boot service data pool memory */
 void *efi_alloc(size_t len, const char *name);
 /* Reallocate boot service data pool memory */
-- 
2.47.3




More information about the barebox mailing list