Linux EFI development
 help / color / mirror / Atom feed
* [PATCH] mefi: add dynamic control interface for EFI runtime services
@ 2026-07-04  0:33 Junxiao Chang
  2026-07-23  6:37 ` Ard Biesheuvel
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Junxiao Chang @ 2026-07-04  0:33 UTC (permalink / raw)
  To: ardb, ilias.apalodimas, linux-efi, linux-kernel; +Cc: -cc=junxiao.chang

Add an interface to dynamically enable or disable EFI runtime
services at runtime. By default, EFI runtime services remain
enabled, but they can be temporarily disabled to improve real-time
latency.

Currently, EFI runtime services are typically disabled on RT
systems using kernel parameters such as "noefi" or "efi=disable".
However, this permanently disables EFI services, preventing use
cases such as UEFI firmware updates.

With this change, EFI runtime services can be disabled during
execution of real-time workloads and re-enabled afterwards,
allowing better balance between real-time performance and firmware
service availability.

Signed-off-by: Junxiao Chang <junxiao.chang@intel.com>
---
 .../admin-guide/kernel-parameters.txt         |  5 ++-
 drivers/firmware/efi/efi.c                    | 39 +++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index b5493a7f8f228..533213101f808 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1595,7 +1595,8 @@ Kernel parameters
 	efi=		[EFI,EARLY]
 			Format: { "debug", "disable_early_pci_dma",
 				  "nochunk", "noruntime", "nosoftreserve",
-				  "novamap", "no_disable_early_pci_dma" }
+				  "novamap", "no_disable_early_pci_dma",
+				  "dynamic" }
 			debug: enable misc debug output.
 			disable_early_pci_dma: disable the busmaster bit on all
 			PCI bridges while in the EFI boot stub.
@@ -1612,6 +1613,8 @@ Kernel parameters
 			novamap: do not call SetVirtualAddressMap().
 			no_disable_early_pci_dma: Leave the busmaster bit set
 			on all PCI bridges while in the EFI boot stub
+			dynamic: enable EFI runtime services, which can be
+			disabled via /sys/firmware/efi/dynamic_enable.
 
 	efi_no_storage_paranoia [EFI,X86,EARLY]
 			Using this parameter you can use more than 50% of
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 0327a39d31fa5..18d5d99fab821 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -81,6 +81,7 @@ struct mm_struct efi_mm = {
 
 struct workqueue_struct *efi_rts_wq;
 
+static bool efi_in_dynamic __initdata;
 static bool disable_runtime = IS_ENABLED(CONFIG_EFI_DISABLE_RUNTIME);
 static int __init setup_noefi(char *arg)
 {
@@ -115,6 +116,11 @@ static int __init parse_efi_cmdline(char *str)
 	if (parse_option_str(str, "runtime"))
 		disable_runtime = false;
 
+	if (parse_option_str(str, "dynamic")) {
+		disable_runtime = false;
+		efi_in_dynamic = true;
+	}
+
 	if (parse_option_str(str, "nosoftreserve"))
 		set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags);
 
@@ -401,6 +407,34 @@ 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 (enable)
+		set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+	else {
+		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+		if (efi_rts_wq)
+			flush_workqueue(efi_rts_wq);
+	}
+
+	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 +480,11 @@ static int __init efisubsys_init(void)
 		goto err_destroy_wq;
 	}
 
+	if (efi_in_dynamic && 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();
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] mefi: add dynamic control interface for EFI runtime services
  2026-07-04  0:33 [PATCH] mefi: add dynamic control interface for EFI runtime services Junxiao Chang
@ 2026-07-23  6:37 ` Ard Biesheuvel
  2026-07-30  6:14   ` Chang, Junxiao
  2026-07-31  6:24 ` [PATCH] efi: " Junxiao Chang
  2026-08-06  9:49 ` Junxiao Chang
  2 siblings, 1 reply; 6+ messages in thread
From: Ard Biesheuvel @ 2026-07-23  6:37 UTC (permalink / raw)
  To: Junxiao Chang, Ilias Apalodimas, linux-efi, linux-kernel
  Cc: Sebastian Andrzej Siewior

(cc Sebastian)

On Sat, 4 Jul 2026, at 02:33, Junxiao Chang wrote:
> Add an interface to dynamically enable or disable EFI runtime
> services at runtime. By default, EFI runtime services remain
> enabled, but they can be temporarily disabled to improve real-time
> latency.
>
> Currently, EFI runtime services are typically disabled on RT
> systems using kernel parameters such as "noefi" or "efi=disable".
> However, this permanently disables EFI services, preventing use
> cases such as UEFI firmware updates.
>
> With this change, EFI runtime services can be disabled during
> execution of real-time workloads and re-enabled afterwards,
> allowing better balance between real-time performance and firmware
> service availability.
>
> Signed-off-by: Junxiao Chang <junxiao.chang@intel.com>
> ---
>  .../admin-guide/kernel-parameters.txt         |  5 ++-
>  drivers/firmware/efi/efi.c                    | 39 +++++++++++++++++++
>  2 files changed, 43 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt 
> b/Documentation/admin-guide/kernel-parameters.txt
> index b5493a7f8f228..533213101f808 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -1595,7 +1595,8 @@ Kernel parameters
>  	efi=		[EFI,EARLY]
>  			Format: { "debug", "disable_early_pci_dma",
>  				  "nochunk", "noruntime", "nosoftreserve",
> -				  "novamap", "no_disable_early_pci_dma" }
> +				  "novamap", "no_disable_early_pci_dma",
> +				  "dynamic" }
>  			debug: enable misc debug output.
>  			disable_early_pci_dma: disable the busmaster bit on all
>  			PCI bridges while in the EFI boot stub.
> @@ -1612,6 +1613,8 @@ Kernel parameters
>  			novamap: do not call SetVirtualAddressMap().
>  			no_disable_early_pci_dma: Leave the busmaster bit set
>  			on all PCI bridges while in the EFI boot stub
> +			dynamic: enable EFI runtime services, which can be
> +			disabled via /sys/firmware/efi/dynamic_enable.
> 
>  	efi_no_storage_paranoia [EFI,X86,EARLY]
>  			Using this parameter you can use more than 50% of

I'd prefer not to add a command line option for this. If the sysfs control
is useful, we can enable it unconditionally, or depend on PREEMPT_RT.

> diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
> index 0327a39d31fa5..18d5d99fab821 100644
> --- a/drivers/firmware/efi/efi.c
> +++ b/drivers/firmware/efi/efi.c
> @@ -81,6 +81,7 @@ struct mm_struct efi_mm = {
> 
>  struct workqueue_struct *efi_rts_wq;
> 
> +static bool efi_in_dynamic __initdata;
>  static bool disable_runtime = IS_ENABLED(CONFIG_EFI_DISABLE_RUNTIME);
>  static int __init setup_noefi(char *arg)
>  {
> @@ -115,6 +116,11 @@ static int __init parse_efi_cmdline(char *str)
>  	if (parse_option_str(str, "runtime"))
>  		disable_runtime = false;
> 
> +	if (parse_option_str(str, "dynamic")) {
> +		disable_runtime = false;
> +		efi_in_dynamic = true;
> +	}
> +
>  	if (parse_option_str(str, "nosoftreserve"))
>  		set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags);
> 
> @@ -401,6 +407,34 @@ 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 (enable)
> +		set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
> +	else {
> +		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);

This is racy, no?


> +		if (efi_rts_wq)
> +			flush_workqueue(efi_rts_wq);
> +	}
> +
> +	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 +480,11 @@ static int __init efisubsys_init(void)
>  		goto err_destroy_wq;
>  	}
> 
> +	if (efi_in_dynamic && 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();
> -- 
> 2.43.0

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH] mefi: add dynamic control interface for EFI runtime services
  2026-07-23  6:37 ` Ard Biesheuvel
@ 2026-07-30  6:14   ` Chang, Junxiao
  0 siblings, 0 replies; 6+ messages in thread
From: Chang, Junxiao @ 2026-07-30  6:14 UTC (permalink / raw)
  To: Ard Biesheuvel, Ilias Apalodimas, linux-efi@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: Sebastian Andrzej Siewior

Ard Biesheuvel wrote:
>Subject: Re: [PATCH] mefi: add dynamic control interface for EFI runtime services
>
>(cc Sebastian)
>
>On Sat, 4 Jul 2026, at 02:33, Junxiao Chang wrote:
>> Add an interface to dynamically enable or disable EFI runtime services
>
>I'd prefer not to add a command line option for this. If the sysfs control is useful,
>we can enable it unconditionally, or depend on PREEMPT_RT.
I will remove cmdline option and make it depend on PREEMPT_RT. Usually EFI runtime service takes 100us to 2ms, it is ok for non-rt case, but it is a high latency for RT.

>
>> diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
>> +		clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
>
>This is racy, no?
Is it ok to change it with locking "efi_runtime_lock"?

>
>> --
>> 2.43.0

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] efi: add dynamic control interface for EFI runtime services
  2026-07-04  0:33 [PATCH] mefi: add dynamic control interface for EFI runtime services Junxiao Chang
  2026-07-23  6:37 ` Ard Biesheuvel
@ 2026-07-31  6:24 ` Junxiao Chang
  2026-08-01 13:45   ` Ard Biesheuvel
  2026-08-06  9:49 ` Junxiao Chang
  2 siblings, 1 reply; 6+ messages in thread
From: Junxiao Chang @ 2026-07-31  6:24 UTC (permalink / raw)
  To: ardb, ilias.apalodimas, linux-efi, linux-kernel; +Cc: bigeasy, junxiao.chang

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@intel.com>
---
 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


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] efi: add dynamic control interface for EFI runtime services
  2026-07-31  6:24 ` [PATCH] efi: " Junxiao Chang
@ 2026-08-01 13:45   ` Ard Biesheuvel
  0 siblings, 0 replies; 6+ messages in thread
From: Ard Biesheuvel @ 2026-08-01 13:45 UTC (permalink / raw)
  To: Junxiao Chang, Ilias Apalodimas, linux-efi, linux-kernel
  Cc: Sebastian Andrzej Siewior

Hi Junxiao,

On Fri, 31 Jul 2026, at 08:24, Junxiao Chang wrote:
> 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@intel.com>
> ---
>  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);

This interface allows enabling of EFI_RUNTIME_SERVICES even if it
was disabled for other reasons, e.g., a firmware crash or a 
command line option. IOW, the set_bit() path is only permitted
if the clear_bit() path was taken first.


> +	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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] efi: add dynamic control interface for EFI runtime services
  2026-07-04  0:33 [PATCH] mefi: add dynamic control interface for EFI runtime services Junxiao Chang
  2026-07-23  6:37 ` Ard Biesheuvel
  2026-07-31  6:24 ` [PATCH] efi: " Junxiao Chang
@ 2026-08-06  9:49 ` Junxiao Chang
  2 siblings, 0 replies; 6+ messages in thread
From: Junxiao Chang @ 2026-08-06  9:49 UTC (permalink / raw)
  To: ardb, ilias.apalodimas, linux-efi, linux-kernel; +Cc: bigeasy, junxiao.chang

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@intel.com>
---
 drivers/firmware/efi/efi.c              | 31 +++++++++++++++++++++++++
 drivers/firmware/efi/runtime-wrappers.c | 28 ++++++++++++++++++++++
 include/linux/efi.h                     |  1 +
 3 files changed, 60 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..24cd8d0478385 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -602,3 +602,31 @@ void efi_runtime_assert_lock_held(void)
 {
 	WARN_ON(efi_runtime_lock_owner != current);
 }
+
+efi_status_t efi_runtime_set_enable_flag(bool enable)
+{
+	static bool dynamic_disabled;
+	efi_status_t ret = EFI_NOT_READY;
+
+	if (down_interruptible(&efi_runtime_lock))
+		return EFI_ABORTED;
+
+	if (enable) {
+		/* It could be enabled only if it is disabled here */
+		if (dynamic_disabled) {
+			set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+			dynamic_disabled = false;
+			ret = EFI_SUCCESS;
+		}
+	} else {
+		if (efi_enabled(EFI_RUNTIME_SERVICES)) {
+			clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+			dynamic_disabled = true;
+			ret = EFI_SUCCESS;
+		}
+	}
+
+	up(&efi_runtime_lock);
+
+	return ret;
+}
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


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-08-05  9:55 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-04  0:33 [PATCH] mefi: add dynamic control interface for EFI runtime services Junxiao Chang
2026-07-23  6:37 ` Ard Biesheuvel
2026-07-30  6:14   ` Chang, Junxiao
2026-07-31  6:24 ` [PATCH] efi: " Junxiao Chang
2026-08-01 13:45   ` Ard Biesheuvel
2026-08-06  9:49 ` Junxiao Chang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox