[PATCH v1 37/54] poweroff: allow drivers to register runtime poweroff handler

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


A runtime poweroff handler needs to be usable from within the barebox EFI
runtime services, even when everything else in barebox has been
discarded and barebox no longer has exclusive access to peripherals.
This driver allows existing drivers for boot time barebox to probe as
normal and optionally register a runtime poweroff handler, which is
suitable for being called from within EFI runtime code.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/poweroff.c  | 36 ++++++++++++++++++++++++++++++++++++
 include/poweroff.h |  2 ++
 2 files changed, 38 insertions(+)

diff --git a/common/poweroff.c b/common/poweroff.c
index 896716bb258c..dfbd727b969c 100644
--- a/common/poweroff.c
+++ b/common/poweroff.c
@@ -7,10 +7,33 @@
 #include <common.h>
 #include <poweroff.h>
 #include <malloc.h>
+#include <efi/types.h>
+#include <asm/sections.h>
 #include <of.h>
 
 static LIST_HEAD(poweroff_handler_list);
 
+static __efi_runtime_data void (*rt_poweroff)(unsigned long flags);
+static int rt_poweroff_prio = INT_MIN;
+
+static void rt_poweroff_handler_register(struct poweroff_handler *handler)
+{
+	if (!IS_ENABLED(CONFIG_EFI_RUNTIME))
+		return;
+	if (!handler->rt_poweroff)
+		return;
+	if (!in_barebox_efi_runtime((ulong)handler->rt_poweroff)) {
+		/* Check if __efi_runtime attribute is missing */
+		pr_warn("handler outside EFI runtime section\n");
+		return;
+	}
+	if (handler->priority <= rt_poweroff_prio)
+		return;
+
+	rt_poweroff = handler->rt_poweroff;
+	rt_poweroff_prio = handler->priority;
+}
+
 /**
  * poweroff_handler_register() - register a handler for poweroffing the system
  * @rst:	The handler struct
@@ -26,6 +49,8 @@ int poweroff_handler_register(struct poweroff_handler *handler)
 	if (!handler->priority)
 		handler->priority = POWEROFF_DEFAULT_PRIORITY;
 
+	rt_poweroff_handler_register(handler);
+
 	list_add_tail(&handler->list, &poweroff_handler_list);
 
 	pr_debug("registering poweroff handler \"%s\" with priority %d\n",
@@ -61,6 +86,17 @@ int poweroff_handler_register_fn(void (*poweroff_fn)(struct poweroff_handler *,
 	return ret;
 }
 
+/**
+ * rt_poweroff_machine() - power off the machine from a runtime service
+ */
+void __noreturn __efi_runtime rt_poweroff_machine(unsigned long flags)
+{
+	if (rt_poweroff)
+		rt_poweroff(flags);
+
+	__hang();
+}
+
 /**
  * poweroff_machine() - power off the machine
  */
diff --git a/include/poweroff.h b/include/poweroff.h
index 3e86003563a9..d8b2856ced9f 100644
--- a/include/poweroff.h
+++ b/include/poweroff.h
@@ -6,10 +6,12 @@
 #include <linux/types.h>
 
 void __noreturn poweroff_machine(unsigned long poweroff_flags);
+void __noreturn rt_poweroff_machine(unsigned long poweroff_flags);
 
 struct poweroff_handler {
 	void (*poweroff)(struct poweroff_handler *,
 			 unsigned long flags);
+	void (*rt_poweroff)(unsigned long flags);
 	int priority;
 	const char *name;
 	struct list_head list;
-- 
2.47.3




More information about the barebox mailing list