[PATCH] efi: add dynamic control interface for EFI runtime services
From: Junxiao Chang
Date: Thu Jul 30 2026 - 02:42:24 EST
Add an interface for PREEMPT_RT kernels to dynamically enable or
disable EFI runtime services.
EFI runtime services are typically disabled on RT systems using
kernel parameters such as "noefi" or "efi=disable" to avoid
long latency caused by firmware calls. However, this permanently
disables EFI runtime services, preventing operations such as UEFI
firmware updates.
With this change, EFI runtime services can be disabled while
real-time workloads are running and re-enabled afterwards,
providing low-latency operation without permanently sacrificing
firmware functionality.
Signed-off-by: Junxiao Chang <junxiao.chang@xxxxxxxxx>
---
drivers/firmware/efi/efi.c | 31 +++++++++++++++++++++++++
drivers/firmware/efi/runtime-wrappers.c | 15 ++++++++++++
include/linux/efi.h | 1 +
3 files changed, 47 insertions(+)
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 0327a39d31fa5..f57784a815c61 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -401,6 +401,32 @@ static void __init efi_debugfs_init(void)
static inline void efi_debugfs_init(void) {}
#endif
+static ssize_t efi_dynamic_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", efi_enabled(EFI_RUNTIME_SERVICES));
+}
+
+static ssize_t efi_dynamic_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ bool enable;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret)
+ return ret;
+
+ if (efi_runtime_set_enable_flag(enable) != EFI_SUCCESS) {
+ pr_warn("unable to enable/disable efi runtime service\n");
+ return -EAGAIN;
+ }
+
+ return count;
+}
+
+static struct kobj_attribute efi_dynamic_attr =
+ __ATTR(dynamic_enable, 0644, efi_dynamic_show, efi_dynamic_store);
+
static int __init efipostcore_init(void)
{
if (!efi_enabled(EFI_RUNTIME_SERVICES))
@@ -446,6 +472,11 @@ static int __init efisubsys_init(void)
goto err_destroy_wq;
}
+ if (IS_ENABLED(CONFIG_PREEMPT_RT) && efi.runtime_supported_mask) {
+ if (sysfs_create_file(efi_kobj, &efi_dynamic_attr.attr))
+ pr_warn("unable to register efi dynamic sysfs interface\n");
+ }
+
if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE |
EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME)) {
error = generic_ops_register();
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index da8d296216441..8d1554714e3f4 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -602,3 +602,18 @@ void efi_runtime_assert_lock_held(void)
{
WARN_ON(efi_runtime_lock_owner != current);
}
+
+efi_status_t efi_runtime_set_enable_flag(bool enable)
+{
+ if (down_interruptible(&efi_runtime_lock))
+ return EFI_ABORTED;
+
+ if (enable)
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+ else
+ clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+
+ up(&efi_runtime_lock);
+
+ return EFI_SUCCESS;
+}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index ccbc35479684a..98b76008fd426 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1109,6 +1109,7 @@ extern void efi_call_virt_check_flags(unsigned long flags, const void *caller);
extern unsigned long efi_call_virt_save_flags(void);
void efi_runtime_assert_lock_held(void);
+efi_status_t efi_runtime_set_enable_flag(bool enable);
enum efi_secureboot_mode {
efi_secureboot_mode_unset,
--
2.43.0