mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH v1 46/54] efi: runtime: add EFI variable support
Date: Thu, 18 Dec 2025 11:38:06 +0100	[thread overview]
Message-ID: <20251218111242.1527495-47-a.fatoum@pengutronix.de> (raw)
In-Reply-To: <20251218111242.1527495-1-a.fatoum@pengutronix.de>

The in-memory EFI variable support in U-Boot is pretty self-contained,
so import it as-is to barebox. This is not power-fail safe and we'll
probably want to add StandAloneMM support for reliable use later.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 common/Kconfig.debug          |  16 ++
 efi/Makefile                  |   1 +
 efi/loader/Kconfig            |  29 +++
 efi/loader/Makefile           |   4 +
 efi/loader/efi_var_common.c   | 475 ++++++++++++++++++++++++++++++++++
 efi/loader/efi_var_file.c     | 203 +++++++++++++++
 efi/loader/efi_var_mem.c      |  80 ++++++
 efi/loader/efi_variable.c     | 214 +++++++++++++++
 efi/loader/protocols/disk.c   |  11 +
 efi/loader/runtime.c          |  10 +-
 efi/loader/setup.c            |   1 +
 efi/loader/variable.h         |  33 +++
 efi/runtime/Makefile          |  43 +++
 efi/runtime/common.h          |  35 +++
 efi/runtime/efi_var_mem.c     | 380 +++++++++++++++++++++++++++
 efi/runtime/efi_variable.c    | 211 +++++++++++++++
 include/efi/loader/variable.h | 153 +++++++++++
 include/efi/runtime.h         | 164 ++++++++++++
 include/efi/variable.h        |   7 +-
 19 files changed, 2065 insertions(+), 5 deletions(-)
 create mode 100644 efi/loader/efi_var_common.c
 create mode 100644 efi/loader/efi_var_file.c
 create mode 100644 efi/loader/efi_var_mem.c
 create mode 100644 efi/loader/efi_variable.c
 create mode 100644 efi/loader/variable.h
 create mode 100644 efi/runtime/Makefile
 create mode 100644 efi/runtime/common.h
 create mode 100644 efi/runtime/efi_var_mem.c
 create mode 100644 efi/runtime/efi_variable.c
 create mode 100644 include/efi/loader/variable.h
 create mode 100644 include/efi/runtime.h

diff --git a/common/Kconfig.debug b/common/Kconfig.debug
index 64127143a5d6..b307b84202a3 100644
--- a/common/Kconfig.debug
+++ b/common/Kconfig.debug
@@ -84,6 +84,22 @@ config DEBUG_EFI_LOADER_ENTRY
 	  If enabled, this will print whenever an EFI payload/app calls
 	  into barebox or is returned to before ExitBootServices.
 
+config DEBUG_EFI_RUNTIME_ENTRY
+	bool "Debug EFI runtime entry/exit"
+	depends on EFI_RUNTIME
+	depends on DEBUG_LL
+	help
+	  If enabled this will print whenever the operating system calls
+	  into barebox or is returned to after ExitBootServices.
+
+	  This requires DEBUG_LL support and board-specific setup, so
+	  any UART MMIO regions needed for the barebox runtime services
+	  are marked as such in the UEFI memory map.
+
+	  This option is most convenient to use with a second UART that
+	  the OS doesn't use, e.g. CONFIG_DEBUG_SEMIHOSTING when running
+	  under QEMU.
+
 config DMA_API_DEBUG
 	bool "Enable debugging of DMA-API usage"
 	depends on HAS_DMA
diff --git a/efi/Makefile b/efi/Makefile
index e0f6ac549009..7032e1fe1ded 100644
--- a/efi/Makefile
+++ b/efi/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_EFI_PAYLOAD)	+= payload/
 obj-$(CONFIG_EFI_LOADER)	+= loader/
+obj-$(CONFIG_EFI_RUNTIME)	+= runtime/
 obj-$(CONFIG_EFI_GUID)		+= guid.o
 obj-$(CONFIG_EFI_DEVICEPATH)	+= devicepath.o
 obj-y				+= errno.o handle.o efivar.o efivar-filename.o
diff --git a/efi/loader/Kconfig b/efi/loader/Kconfig
index ca0ec6b5010a..4a5e4c375fd4 100644
--- a/efi/loader/Kconfig
+++ b/efi/loader/Kconfig
@@ -21,6 +21,9 @@ config EFI_LOADER_DEBUG_SUPPORT
 	  agent or an external debugger to determine loaded image information
 	  in a quiescent manner.
 
+config EFI_LOADER_SECURE_BOOT
+	bool
+
 menu "UEFI services"
 
 config EFI_LOADER_GET_TIME
@@ -39,6 +42,32 @@ config EFI_LOADER_SET_TIME
 	  Provide the SetTime() runtime service at boottime. This service
 	  can be used by an EFI application to adjust the real time clock.
 
+choice
+	prompt "Store for non-volatile UEFI variables"
+	default EFI_VARIABLE_FILE_STORE
+	help
+	  Select where non-volatile UEFI variables shall be stored.
+
+config EFI_VARIABLE_FILE_STORE
+	bool "Store non-volatile UEFI variables as file"
+	depends on FS_FAT_WRITE
+	select EFI_RUNTIME_GET_VARIABLE
+	select EFI_RUNTIME_GET_NEXT_VARIABLE_NAME
+	select EFI_RUNTIME_QUERY_VARIABLE_INFO
+	help
+	  Select this option if you want non-volatile UEFI variables to be
+	  stored under the file name indicated by ${efi.vars.filestore}
+	  on the EFI system partition.
+
+config EFI_VARIABLE_NO_STORE
+	bool "Don't persist non-volatile UEFI variables"
+	help
+	  If you choose this option, non-volatile variables cannot be persisted.
+	  You could still provide non-volatile variables via the barebox
+	  environment.
+
+endchoice
+
 endmenu
 
 source "efi/loader/protocols/Kconfig"
diff --git a/efi/loader/Makefile b/efi/loader/Makefile
index 2a78361e58d5..5fd74a2e0c42 100644
--- a/efi/loader/Makefile
+++ b/efi/loader/Makefile
@@ -15,3 +15,7 @@ obj-y += loadopts.o
 obj-$(CONFIG_BOOT) += bootesp.o
 obj-$(CONFIG_EFI_LOADER_BOOTMGR) += efibootmgr.o
 obj-$(CONFIG_BOOTM) += bootm.o
+obj-y += efi_var_common.o
+obj-y += efi_variable.o
+obj-y += efi_var_mem.o
+obj-y += efi_var_file.o
diff --git a/efi/loader/efi_var_common.c b/efi/loader/efi_var_common.c
new file mode 100644
index 000000000000..bd5af007ed9c
--- /dev/null
+++ b/efi/loader/efi_var_common.c
@@ -0,0 +1,475 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/e9c34fab18a9a0022b36729afd8e262e062764e2/lib/efi_loader/efi_var_common.c
+/*
+ * UEFI runtime variable services
+ *
+ * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ * Copyright (c) 2020 Linaro Limited, Author: AKASHI Takahiro
+ */
+
+#define pr_fmt(fmt) "efi-loader: efibootmgr: " fmt
+
+#include <linux/kernel.h>
+#include <efi/loader/variable.h>
+#include <efi/loader/trace.h>
+#include <efi/variable.h>
+#include <efi/runtime.h>
+#include <efi/error.h>
+#include <efi/guid.h>
+#include <efi/variable.h>
+#include <stdlib.h>
+#include <crc.h>
+
+#include "variable.h"
+
+enum efi_secure_mode {
+	EFI_MODE_SETUP,
+	EFI_MODE_USER,
+	EFI_MODE_AUDIT,
+	EFI_MODE_DEPLOYED,
+};
+
+struct efi_auth_var_name_type {
+	const u16 *name;
+	const efi_guid_t *guid;
+	const enum efi_auth_var_type type;
+};
+
+static const struct efi_auth_var_name_type name_type[] = {
+	{u"PK", &efi_global_variable_guid, EFI_AUTH_VAR_PK},
+	{u"KEK", &efi_global_variable_guid, EFI_AUTH_VAR_KEK},
+	{u"db",  &efi_guid_image_security_database, EFI_AUTH_VAR_DB},
+	{u"dbx",  &efi_guid_image_security_database, EFI_AUTH_VAR_DBX},
+	{u"dbt",  &efi_guid_image_security_database, EFI_AUTH_VAR_DBT},
+	{u"dbr",  &efi_guid_image_security_database, EFI_AUTH_VAR_DBR},
+	{u"AuditMode", &efi_global_variable_guid, EFI_AUTH_MODE},
+	{u"DeployedMode", &efi_global_variable_guid, EFI_AUTH_MODE},
+};
+
+static bool efi_secure_boot;
+static enum efi_secure_mode efi_secure_mode;
+
+/**
+ * efi_get_variable_boot() - retrieve value of a UEFI variable
+ *
+ * This function implements the GetVariable runtime service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @variable_name:	name of the variable
+ * @vendor:		vendor GUID
+ * @attributes:		attributes of the variable
+ * @data_size:		size of the buffer to which the variable value is copied
+ * @data:		buffer to which the variable value is copied
+ * Return:		status code
+ */
+efi_status_t EFIAPI efi_get_variable_boot(u16 *variable_name,
+					  const efi_guid_t *vendor, u32 *attributes,
+					  efi_uintn_t *data_size, void *data)
+{
+	efi_status_t ret;
+
+	EFI_ENTRY("\"%ls\" %pUs %p %p %p", variable_name, vendor, attributes,
+		  data_size, data);
+
+	ret = efi_get_variable_int(variable_name, vendor, attributes,
+				   data_size, data, NULL);
+
+	/* Remove EFI_VARIABLE_READ_ONLY flag */
+	if (attributes)
+		*attributes &= EFI_VARIABLE_MASK;
+
+	return EFI_EXIT(ret);
+}
+
+/**
+ * efi_set_variable_boot() - set value of a UEFI variable
+ *
+ * This function implements the SetVariable runtime service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @variable_name:	name of the variable
+ * @vendor:		vendor GUID
+ * @attributes:		attributes of the variable
+ * @data_size:		size of the buffer with the variable value
+ * @data:		buffer with the variable value
+ * Return:		status code
+ */
+efi_status_t EFIAPI efi_set_variable_boot(u16 *variable_name,
+					  const efi_guid_t *vendor, u32 attributes,
+					  efi_uintn_t data_size, const void *data)
+{
+	efi_status_t ret;
+
+	EFI_ENTRY("\"%ls\" %pUs %x %zu %p", variable_name, vendor, attributes,
+		  data_size, data);
+
+	/* Make sure that the EFI_VARIABLE_READ_ONLY flag is not set */
+	if (attributes & ~EFI_VARIABLE_MASK)
+		ret = EFI_INVALID_PARAMETER;
+	else
+		ret = efi_set_variable_int(variable_name, vendor, attributes,
+					   data_size, data, true);
+
+	return EFI_EXIT(ret);
+}
+
+/**
+ * efi_get_next_variable_name_boot() - enumerate the current variable names
+ *
+ * @variable_name_size:	size of variable_name buffer in byte
+ * @variable_name:	name of uefi variable's name in u16
+ * @vendor:		vendor's guid
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * Return: status code
+ */
+efi_status_t EFIAPI efi_get_next_variable_name_boot(efi_uintn_t *variable_name_size,
+						    u16 *variable_name,
+						    efi_guid_t *vendor)
+{
+	efi_status_t ret;
+
+	EFI_ENTRY("%p \"%ls\" %pUs", variable_name_size, variable_name, vendor);
+
+	ret = efi_get_next_variable_name_int(variable_name_size, variable_name,
+					     vendor);
+
+	return EFI_EXIT(ret);
+}
+
+/**
+ * efi_query_variable_info_boot() - get information about EFI variables
+ *
+ * This function implements the QueryVariableInfo() runtime service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @attributes:				bitmask to select variables to be
+ *					queried
+ * @maximum_variable_storage_size:	maximum size of storage area for the
+ *					selected variable types
+ * @remaining_variable_storage_size:	remaining size of storage are for the
+ *					selected variable types
+ * @maximum_variable_size:		maximum size of a variable of the
+ *					selected type
+ * Returns:				status code
+ */
+efi_status_t EFIAPI efi_query_variable_info_boot(
+			u32 attributes, u64 *maximum_variable_storage_size,
+			u64 *remaining_variable_storage_size,
+			u64 *maximum_variable_size)
+{
+	efi_status_t ret;
+
+	EFI_ENTRY("%x %p %p %p", attributes, maximum_variable_storage_size,
+		  remaining_variable_storage_size, maximum_variable_size);
+
+	ret = efi_query_variable_info_int(attributes,
+					  maximum_variable_storage_size,
+					  remaining_variable_storage_size,
+					  maximum_variable_size);
+
+	return EFI_EXIT(ret);
+}
+
+/**
+ * efi_set_secure_state - modify secure boot state variables
+ * @secure_boot:	value of SecureBoot
+ * @setup_mode:		value of SetupMode
+ * @audit_mode:		value of AuditMode
+ * @deployed_mode:	value of DeployedMode
+ *
+ * Modify secure boot status related variables as indicated.
+ *
+ * Return:		status code
+ */
+static efi_status_t efi_set_secure_state(u8 secure_boot, u8 setup_mode,
+					 u8 audit_mode, u8 deployed_mode)
+{
+	efi_status_t ret;
+	const u32 attributes_ro = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				  EFI_VARIABLE_RUNTIME_ACCESS |
+				  EFI_VARIABLE_READ_ONLY;
+	const u32 attributes_rw = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				  EFI_VARIABLE_RUNTIME_ACCESS;
+
+	efi_secure_boot = secure_boot;
+
+	ret = efi_set_variable_int(u"SecureBoot", &efi_global_variable_guid,
+				   attributes_ro, sizeof(secure_boot),
+				   &secure_boot, false);
+	if (ret != EFI_SUCCESS)
+		goto err;
+
+	ret = efi_set_variable_int(u"SetupMode", &efi_global_variable_guid,
+				   attributes_ro, sizeof(setup_mode),
+				   &setup_mode, false);
+	if (ret != EFI_SUCCESS)
+		goto err;
+
+	ret = efi_set_variable_int(u"AuditMode", &efi_global_variable_guid,
+				   audit_mode || setup_mode ?
+				   attributes_ro : attributes_rw,
+				   sizeof(audit_mode), &audit_mode, false);
+	if (ret != EFI_SUCCESS)
+		goto err;
+
+	ret = efi_set_variable_int(u"DeployedMode",
+				   &efi_global_variable_guid,
+				   audit_mode || deployed_mode || setup_mode ?
+				   attributes_ro : attributes_rw,
+				   sizeof(deployed_mode), &deployed_mode,
+				   false);
+err:
+	return ret;
+}
+
+/**
+ * efi_transfer_secure_state - handle a secure boot state transition
+ * @mode:	new state
+ *
+ * Depending on @mode, secure boot related variables are updated.
+ * Those variables are *read-only* for users, efi_set_variable_int()
+ * is called here.
+ *
+ * Return:	status code
+ */
+static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
+{
+	efi_status_t ret;
+
+	EFI_PRINT("Switching secure state from %d to %d\n", efi_secure_mode,
+		  mode);
+
+	if (mode == EFI_MODE_DEPLOYED) {
+		ret = efi_set_secure_state(1, 0, 0, 1);
+		if (ret != EFI_SUCCESS)
+			goto err;
+	} else if (mode == EFI_MODE_AUDIT) {
+		ret = efi_set_variable_int(u"PK", &efi_global_variable_guid,
+					   EFI_VARIABLE_BOOTSERVICE_ACCESS |
+					   EFI_VARIABLE_RUNTIME_ACCESS,
+					   0, NULL, false);
+		if (ret != EFI_SUCCESS)
+			goto err;
+
+		ret = efi_set_secure_state(0, 1, 1, 0);
+		if (ret != EFI_SUCCESS)
+			goto err;
+	} else if (mode == EFI_MODE_USER) {
+		ret = efi_set_secure_state(1, 0, 0, 0);
+		if (ret != EFI_SUCCESS)
+			goto err;
+	} else if (mode == EFI_MODE_SETUP) {
+		ret = efi_set_secure_state(0, 1, 0, 0);
+		if (ret != EFI_SUCCESS)
+			goto err;
+	} else {
+		return EFI_INVALID_PARAMETER;
+	}
+
+	efi_secure_mode = mode;
+
+	return EFI_SUCCESS;
+
+err:
+	/* TODO: What action should be taken here? */
+	pr_err("Secure state transition failed\n");
+	return ret;
+}
+
+efi_status_t efi_init_secure_state(void)
+{
+	enum efi_secure_mode mode;
+	u8 efi_vendor_keys = 0;
+	efi_uintn_t size;
+	efi_status_t ret;
+	u8 deployed_mode = 0;
+	u8 audit_mode = 0;
+	u8 setup_mode = 1;
+
+	if (IS_ENABLED(CONFIG_EFI_LOADER_SECURE_BOOT)) {
+		size = sizeof(deployed_mode);
+		ret = efi_get_variable_int(u"DeployedMode", &efi_global_variable_guid,
+					   NULL, &size, &deployed_mode, NULL);
+		size = sizeof(audit_mode);
+		ret = efi_get_variable_int(u"AuditMode", &efi_global_variable_guid,
+					   NULL, &size, &audit_mode, NULL);
+		size = 0;
+		ret = efi_get_variable_int(u"PK", &efi_global_variable_guid,
+					   NULL, &size, NULL, NULL);
+		if (ret == EFI_BUFFER_TOO_SMALL) {
+			setup_mode = 0;
+			audit_mode = 0;
+		} else {
+			setup_mode = 1;
+			deployed_mode = 0;
+		}
+	}
+	if (deployed_mode)
+		mode = EFI_MODE_DEPLOYED;
+	else if (audit_mode)
+		mode = EFI_MODE_AUDIT;
+	else if (setup_mode)
+		mode = EFI_MODE_SETUP;
+	else
+		mode = EFI_MODE_USER;
+
+	ret = efi_transfer_secure_state(mode);
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	/* As we do not provide vendor keys this variable is always 0. */
+	ret = efi_set_variable_int(u"VendorKeys",
+				   &efi_global_variable_guid,
+				   EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				   EFI_VARIABLE_RUNTIME_ACCESS |
+				   EFI_VARIABLE_READ_ONLY,
+				   sizeof(efi_vendor_keys),
+				   &efi_vendor_keys, false);
+	return ret;
+}
+
+/**
+ * efi_secure_boot_enabled - return if secure boot is enabled or not
+ *
+ * Return:	true if enabled, false if disabled
+ */
+bool efi_secure_boot_enabled(void)
+{
+	return efi_secure_boot;
+}
+
+enum efi_auth_var_type efi_auth_var_get_type(const u16 *name,
+					     const efi_guid_t *guid)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
+		if (!wcscmp(name, name_type[i].name) &&
+		    !efi_guidcmp(*guid, *name_type[i].guid))
+			return name_type[i].type;
+	}
+	return EFI_AUTH_VAR_NONE;
+}
+
+const efi_guid_t *efi_auth_var_get_guid(const u16 *name)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
+		if (!wcscmp(name, name_type[i].name))
+			return name_type[i].guid;
+	}
+	return &efi_global_variable_guid;
+}
+
+/**
+ * efi_get_var() - read value of an EFI variable
+ *
+ * @name:	variable name
+ * @start:	vendor GUID
+ * @size:	size of allocated buffer
+ *
+ * Return:	buffer with variable data or NULL
+ */
+void *efi_get_var(const u16 *name, const efi_guid_t *vendor, efi_uintn_t *size)
+{
+	efi_status_t ret;
+	void *buf = NULL;
+
+	*size = 0;
+	ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		buf = malloc(*size);
+		if (!buf)
+			return NULL;
+		ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
+	}
+
+	if (ret != EFI_SUCCESS) {
+		free(buf);
+		*size = 0;
+		return NULL;
+	}
+
+	return buf;
+}
+
+/**
+ * efi_var_collect() - Copy EFI variables matching attributes mask
+ *
+ * @bufp:	buffer containing variable collection
+ * @lenp:	buffer length
+ * @attr_mask:	mask of matched attributes
+ *
+ * Return:	Status code
+ */
+efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, loff_t *lenp,
+					    u32 check_attr_mask)
+{
+	unsigned len;
+	struct efi_var_file *buf;
+	struct efi_var_entry *var, *old_var;
+	size_t old_var_name_length = 2;
+
+	efi_var_buf_get(&len);
+
+	*bufp = NULL; /* Avoid double free() */
+	buf = calloc(1, len);
+	if (!buf)
+		return EFI_OUT_OF_RESOURCES;
+	var = buf->var;
+	old_var = var;
+	for (;;) {
+		efi_uintn_t data_length, var_name_length;
+		u8 *data;
+		efi_status_t ret;
+
+		if ((uintptr_t)buf + len <=
+		    (uintptr_t)var->name + old_var_name_length)
+			return EFI_BUFFER_TOO_SMALL;
+
+		var_name_length = (uintptr_t)buf + len - (uintptr_t)var->name;
+		memcpy(var->name, old_var->name, old_var_name_length);
+		var->guid = old_var->guid;
+		ret = efi_get_next_variable_name_int(
+				&var_name_length, var->name, &var->guid);
+		if (ret == EFI_NOT_FOUND)
+			break;
+		if (ret != EFI_SUCCESS) {
+			free(buf);
+			return ret;
+		}
+		old_var_name_length = var_name_length;
+		old_var = var;
+
+		data = (u8 *)var->name + old_var_name_length;
+		data_length = (uintptr_t)buf + len - (uintptr_t)data;
+		ret = efi_get_variable_int(var->name, &var->guid,
+					   &var->attr, &data_length, data,
+					   &var->time);
+		if (ret != EFI_SUCCESS) {
+			free(buf);
+			return ret;
+		}
+		if ((var->attr & check_attr_mask) == check_attr_mask) {
+			var->length = data_length;
+			var = (struct efi_var_entry *)ALIGN((uintptr_t)data + data_length, 8);
+		}
+	}
+
+	buf->reserved = 0;
+	buf->magic = EFI_VAR_FILE_MAGIC;
+	len = (uintptr_t)var - (uintptr_t)buf;
+	buf->crc32 = crc32(0, (u8 *)buf->var,
+			   len - sizeof(struct efi_var_file));
+	buf->length = len;
+	*bufp = buf;
+	*lenp = len;
+
+	return EFI_SUCCESS;
+}
diff --git a/efi/loader/efi_var_file.c b/efi/loader/efi_var_file.c
new file mode 100644
index 000000000000..08a5c172cced
--- /dev/null
+++ b/efi/loader/efi_var_file.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0+
+// SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/bc4fe5666dae6ab01a433970c3f5e6eb4833ebe7/lib/efi_loader/efi_var_file.c
+/*
+ * File interface for UEFI variables
+ *
+ * Copyright (c) 2020, Heinrich Schuchardt
+ */
+
+#define pr_fmt(fmt) "efi-loader: var-file: " fmt
+
+#include <linux/kernel.h>
+#include <efi/loader.h>
+#include <efi/mode.h>
+#include <efi/loader/variable.h>
+#include <efi/variable.h>
+#include <efi/runtime.h>
+#include <efi/error.h>
+#include <efi/guid.h>
+#include <stdlib.h>
+#include <crc.h>
+#include <fs.h>
+#include <libfile.h>
+#include <string.h>
+#include <globalvar.h>
+#include <magicvar.h>
+
+#include "variable.h"
+
+/* Filename within ESP to save/restore EFI variables from
+ * when CONFIG_EFI_VARIABLE_FILE_STORE=y
+ */
+char *efi_var_file_name;
+
+/**
+ * efi_var_to_file() - save non-volatile variables as file
+ *
+ * File indiciated by efi_var_file_name with EFI variables is
+ * created on the EFI system partion.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_var_to_file(void)
+{
+	efi_status_t efiret;
+	struct efi_var_file *buf;
+	loff_t len;
+	int err, fd, dirfd;
+	static bool once;
+
+	if (!IS_ENABLED(CONFIG_EFI_VARIABLE_FILE_STORE))
+		return EFI_SUCCESS;
+
+	efiret = efi_var_collect(&buf, &len, EFI_VARIABLE_NON_VOLATILE);
+	if (efiret != EFI_SUCCESS) {
+		err = ENOMEM;
+		goto error;
+	}
+
+	dirfd = efiloader_esp_mount_dir();
+	if (dirfd < 0) {
+		if (!once) {
+			pr_warn("Cannot persist EFI variables without system partition\n");
+			once = true;
+		}
+		efiret = EFI_NO_MEDIA;
+		err = dirfd;
+		goto out;
+	}
+
+	// TODO: replace with rename
+	fd = openat(dirfd, efi_var_file_name, O_WRONLY | O_TRUNC | O_CREAT);
+	if (fd < 0) {
+		efiret = EFI_DEVICE_ERROR;
+		err = fd;
+		goto error;
+	}
+
+	err = write_full(fd, buf, len);
+
+	close(fd);
+
+	if (err < 0) {
+		efiret = EFI_DEVICE_ERROR;
+		goto error;
+	}
+
+	return 0;
+
+error:
+	if (efiret != EFI_SUCCESS)
+		pr_err("Failed to persist EFI variables %pe\n", ERR_PTR(err));
+
+out:
+	free(buf);
+	return efiret;
+}
+
+static efi_status_t efi_var_restore(struct efi_var_file *buf, bool safe)
+{
+	struct efi_var_entry *var, *last_var;
+	u16 *data;
+	efi_status_t ret;
+
+	if (buf->reserved || buf->magic != EFI_VAR_FILE_MAGIC ||
+	    buf->crc32 != crc32(0, (u8 *)buf->var,
+				buf->length - sizeof(struct efi_var_file))) {
+		pr_err("Invalid EFI variables file\n");
+		return EFI_INVALID_PARAMETER;
+	}
+
+	last_var = (struct efi_var_entry *)((u8 *)buf + buf->length);
+	for (var = buf->var; var < last_var;
+	     var = (struct efi_var_entry *)
+		   ALIGN((uintptr_t)data + var->length, 8)) {
+
+		data = var->name + wcslen(var->name) + 1;
+
+		/*
+		 * Secure boot related and volatile variables shall only be
+		 * restored from the preseed, but we didn't implement this yet.
+		 */
+		if (!safe &&
+		    (efi_auth_var_get_type(var->name, &var->guid) !=
+		     EFI_AUTH_VAR_NONE ||
+		     !efi_guidcmp(var->guid, shim_lock_guid) ||
+		     !(var->attr & EFI_VARIABLE_NON_VOLATILE)))
+			continue;
+		if (!var->length)
+			continue;
+		if (efi_var_mem_find(&var->guid, var->name, NULL))
+			continue;
+		ret = efi_var_mem_ins(var->name, &var->guid, var->attr,
+				      var->length, data, 0, NULL,
+				      var->time);
+		if (ret != EFI_SUCCESS)
+			pr_err("Failed to set EFI variable %ls\n", var->name);
+	}
+	return EFI_SUCCESS;
+}
+
+/**
+ * efi_var_from_file() - read variables from file
+ *
+ * Specified file is read from the EFI system partitions and the variables
+ * stored in the file are created.
+ *
+ * On first boot the file may not exist yet. This is why we must
+ * return EFI_SUCCESS in this case.
+ *
+ * If the variable file is corrupted, e.g. incorrect CRC32, we do not want to
+ * stop the boot process. We deliberately return EFI_SUCCESS in this case, too.
+ *
+ * @dirfd	directory fd
+ * @filename	name of the file to load variables from
+ * Return:	status code
+ */
+efi_status_t efi_var_from_file(int dirfd, const char *filename)
+{
+	struct efi_var_file *buf;
+	efi_status_t ret;
+	size_t len;
+	int fd;
+
+	fd = openat(dirfd, filename, O_RDONLY);
+	if (fd < 0)
+		return EFI_NOT_FOUND;
+
+	buf = read_fd(fd, &len);
+
+	close(fd);
+
+	if (!buf || len < sizeof(struct efi_var_file)) {
+		ret = EFI_NOT_FOUND;
+		goto error;
+	}
+
+	if (buf->length != len || efi_var_restore(buf, false) != EFI_SUCCESS) {
+		ret = EFI_CRC_ERROR;
+		goto error;
+	}
+
+	return EFI_SUCCESS;
+error:
+	free(buf);
+	return ret;
+}
+static int efi_init_var_params(void)
+{
+	if (efi_is_payload())
+		return 0;
+
+	/* Not 8.3, but brboxefi.var looks just too ugly */
+	efi_var_file_name = xstrdup("barebox.efivars");
+	dev_add_param_string(&efidev, "vars.filestore", NULL, NULL,
+			     &efi_var_file_name, NULL);
+
+
+	return 0;
+}
+late_initcall(efi_init_var_params);
+
+BAREBOX_MAGICVAR(efi.vars.filestore,
+		 "efiloader: Name of file within ESP to store variables to (WARNING: Not power-fail safe!)");
diff --git a/efi/loader/efi_var_mem.c b/efi/loader/efi_var_mem.c
new file mode 100644
index 000000000000..d2c89d4b0851
--- /dev/null
+++ b/efi/loader/efi_var_mem.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0+
+// SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/530e869ff89d9575103637af201fe97864d4f577/lib/efi_loader/efi_var_mem.c
+/*
+ * File interface for UEFI variables
+ *
+ * Copyright (c) 2020, Heinrich Schuchardt
+ */
+
+#define pr_fmt(fmt) "efi-loader: variable-mem: " fmt
+
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+#include <efi/loader/variable.h>
+#include <efi/runtime.h>
+#include <efi/mode.h>
+#include <efi/services.h>
+#include <efi/loader.h>
+#include <efi/variable.h>
+#include <efi/error.h>
+#include <param.h>
+#include <magicvar.h>
+
+static unsigned efi_var_buf_size = SZ_128K;
+
+efi_status_t efi_var_mem_init(void)
+{
+	struct efi_var_file *efi_var_buf;
+	u64 memory;
+	efi_status_t ret;
+
+	ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+				 EFI_RUNTIME_SERVICES_DATA,
+				 efi_size_in_pages(efi_var_buf_size),
+				 &memory, "vars");
+	if (ret != EFI_SUCCESS)
+		return ret;
+	efi_var_buf = (struct efi_var_file *)(uintptr_t)memory;
+	memset(efi_var_buf, 0,  efi_var_buf_size);
+	efi_var_buf->magic = EFI_VAR_FILE_MAGIC;
+	efi_var_buf->length = (uintptr_t)efi_var_buf->var -
+			      (uintptr_t)efi_var_buf;
+
+	/* we would have to register EFI_EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE otherwise */
+	static_assert(!IS_ENABLED(EFI_RUNTIME_SET_VIRTUAL_ADDRESS_MAP));
+
+	efi_var_buf_set(efi_var_buf, efi_var_buf_size);
+
+	return EFI_SUCCESS;
+}
+
+void efi_var_buf_update(struct efi_var_file *var_buf)
+{
+	unsigned len;
+	struct efi_var_file *dst = efi_var_buf_get(&len);
+
+	memcpy(dst, var_buf, len);
+}
+
+static int efi_var_buf_size_set(struct param_d *param, void *priv)
+{
+	if (!efi_var_buf_size || efi_var_buf_size % EFI_PAGE_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int efi_init_var_params(void)
+{
+	if (efi_is_payload())
+		return 0;
+
+	dev_add_param_uint32(&efidev, "vars.bufsize", efi_var_buf_size_set, NULL,
+			     &efi_var_buf_size, "%u", NULL);
+
+	return 0;
+}
+late_initcall(efi_init_var_params);
+
+BAREBOX_MAGICVAR(efi.vars.bufsize,
+		 "efiloader: Size in bytes of the memory area reserved for keeping UEFI variables");
diff --git a/efi/loader/efi_variable.c b/efi/loader/efi_variable.c
new file mode 100644
index 000000000000..e5b03c26edd0
--- /dev/null
+++ b/efi/loader/efi_variable.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0+
+// SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/58d825fb18053ec7e432de7bbb70a452b9228076/lib/efi_loader/efi_variable.c
+/*
+ * UEFI runtime variable services
+ *
+ * Copyright (c) 2017 Rob Clark
+ */
+
+#define pr_fmt(fmt) "efi-loader: variable: " fmt
+
+#include <linux/kernel.h>
+#include <efi/loader.h>
+#include <efi/error.h>
+#include <efi/variable.h>
+#include <efi/runtime.h>
+#include <efi/loader/trace.h>
+#include <efi/loader/variable.h>
+#include <stdlib.h>
+#include <crc.h>
+#include <fcntl.h>
+
+#include "variable.h"
+
+/* Initial set of efi variables. This is not written back and
+ * usually from barebox' built-in env
+ */
+#define BAREBOX_ENV_INIT_EFIVARS	"/env/data/init.efivars"
+
+/**
+ * efi_variable_authenticate - authenticate a variable
+ * @variable:	Variable name in u16
+ * @vendor:	Guid of variable
+ * @data_size:	Size of @data
+ * @data:	Pointer to variable's value
+ * @given_attr:	Attributes to be given at SetVariable()
+ * @env_attr:	Attributes that an existing variable holds
+ * @time:	signed time that an existing variable holds
+ *
+ *
+ * Return:	success as variable auth is not yet supported
+ */
+static efi_status_t efi_variable_authenticate(const u16 *variable,
+					      const efi_guid_t *vendor,
+					      efi_uintn_t *data_size,
+					      const void **data, u32 given_attr,
+					      u32 *env_attr, u64 *time)
+{
+	return EFI_SUCCESS;
+}
+
+efi_status_t efi_set_variable_int(const u16 *variable_name,
+				  const efi_guid_t *vendor,
+				  u32 attributes, efi_uintn_t data_size,
+				  const void *data, bool ro_check)
+{
+	struct efi_var_entry *var;
+	efi_uintn_t ret;
+	bool append, delete;
+	u64 time = 0;
+	enum efi_auth_var_type var_type;
+
+	ret = efi_setvariable_allowed(variable_name, vendor, attributes, data_size,
+				  data);
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	/* check if a variable exists */
+	var = efi_var_mem_find(vendor, variable_name, NULL);
+	append = !!(attributes & EFI_VARIABLE_APPEND_WRITE);
+	delete = !append && (!data_size || !attributes);
+
+	/* check attributes */
+	var_type = efi_auth_var_get_type(variable_name, vendor);
+	if (var) {
+		if (ro_check && (var->attr & EFI_VARIABLE_READ_ONLY))
+			return EFI_WRITE_PROTECTED;
+
+		if (var_type >= EFI_AUTH_VAR_PK)
+			return EFI_WRITE_PROTECTED;
+
+		/* attributes won't be changed */
+		if (!delete &&
+		    ((ro_check && var->attr != (attributes & ~EFI_VARIABLE_APPEND_WRITE)) ||
+		     (!ro_check && ((var->attr & ~EFI_VARIABLE_READ_ONLY)
+				    != (attributes & ~EFI_VARIABLE_READ_ONLY))))) {
+			return EFI_INVALID_PARAMETER;
+		}
+		time = var->time;
+	} else {
+		/*
+		 * UEFI specification does not clearly describe the expected
+		 * behavior of append write with data size 0, we follow
+		 * the EDK II reference implementation.
+		 */
+		if (append && !data_size)
+			return EFI_SUCCESS;
+
+		/*
+		 * EFI_VARIABLE_APPEND_WRITE to non-existent variable is accepted
+		 * and new variable is created in EDK II reference implementation.
+		 * We follow it and only check the deletion here.
+		 */
+		if (delete)
+			/* Trying to delete a non-existent variable. */
+			return EFI_NOT_FOUND;
+	}
+
+	if (var_type >= EFI_AUTH_VAR_PK) {
+		/* authentication is mandatory */
+		if (!(attributes &
+		      EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
+			EFI_PRINT("%ls: TIME_BASED_AUTHENTICATED_WRITE_ACCESS required\n",
+				  variable_name);
+			return EFI_INVALID_PARAMETER;
+		}
+	}
+
+	/* authenticate a variable */
+	if (IS_ENABLED(CONFIG_EFI_LOADER_SECURE_BOOT)) {
+		if (attributes &
+		    EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
+			u32 env_attr;
+
+			ret = efi_variable_authenticate(variable_name, vendor,
+							&data_size, &data,
+							attributes, &env_attr,
+							&time);
+			if (ret != EFI_SUCCESS)
+				return ret;
+
+			/* last chance to check for delete */
+			if (!data_size)
+				delete = true;
+		}
+	} else {
+		if (attributes &
+		    EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
+			EFI_PRINT("Secure boot is not configured\n");
+			return EFI_INVALID_PARAMETER;
+		}
+	}
+
+	if (delete) {
+		/* EFI_NOT_FOUND has been handled before */
+		attributes = var->attr;
+		ret = EFI_SUCCESS;
+	} else if (append && var) {
+		/*
+		 * data is appended if EFI_VARIABLE_APPEND_WRITE is set and
+		 * variable exists.
+		 */
+		u16 *old_data = var->name;
+
+		for (; *old_data; ++old_data)
+			;
+		++old_data;
+		ret = efi_var_mem_ins(variable_name, vendor,
+				      attributes & ~EFI_VARIABLE_APPEND_WRITE,
+				      var->length, old_data, data_size, data,
+				      time);
+	} else {
+		ret = efi_var_mem_ins(variable_name, vendor, attributes,
+				      data_size, data, 0, NULL, time);
+	}
+
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	efi_var_mem_del(var);
+
+	if (var_type == EFI_AUTH_VAR_PK)
+		ret = efi_init_secure_state();
+	else
+		ret = EFI_SUCCESS;
+
+	/*
+	 * Write non-volatile EFI variables to file
+	 * TODO: check if a value change has occured to avoid superfluous writes
+	 */
+	if (attributes & EFI_VARIABLE_NON_VOLATILE)
+		efi_var_to_file();
+
+	return EFI_SUCCESS;
+}
+
+/**
+ * efi_init_variables() - initialize variable services
+ *
+ * Return:	status code
+ */
+static efi_status_t efi_init_variables(void *data)
+{
+	efi_status_t ret;
+
+	ret = efi_var_mem_init();
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	ret = efi_var_from_file(AT_FDCWD, BAREBOX_ENV_INIT_EFIVARS);
+	if (ret != EFI_SUCCESS && ret != EFI_NOT_FOUND) {
+		pr_err(BAREBOX_ENV_INIT_EFIVARS
+		       " : Invalid EFI variables file (%lx)\n", ret);
+		return ret;
+	}
+
+	return efi_init_secure_state();
+}
+
+static int efi_variables_init(void)
+{
+	efi_register_deferred_init(efi_init_variables, NULL);
+	return 0;
+}
+postcore_initcall(efi_variables_init);
diff --git a/efi/loader/protocols/disk.c b/efi/loader/protocols/disk.c
index cb1771e0cf99..835dee4e2e26 100644
--- a/efi/loader/protocols/disk.c
+++ b/efi/loader/protocols/disk.c
@@ -16,6 +16,7 @@
 #include <efi/loader/object.h>
 #include <efi/loader/devicepath.h>
 #include <efi/loader/file.h>
+#include <efi/loader/variable.h>
 #include <efi/loader/trace.h>
 #include <efi/partition.h>
 #include <malloc.h>
@@ -390,6 +391,16 @@ static efi_status_t efi_disk_register(void *data)
 
 	symlink_esp();
 
+	if (IS_ENABLED(CONFIG_EFI_VARIABLE_FILE_STORE) && efi_var_file_name) {
+		int dirfd = efiloader_esp_mount_dir();
+		if (dirfd >= 0) {
+			ret = efi_var_from_file(dirfd, efi_var_file_name);
+			if (ret != EFI_SUCCESS && ret != EFI_NOT_FOUND)
+				pr_warn("Failed to load /esp/%s: %lx\n",
+					efi_var_file_name, ret);
+		}
+	}
+
 	return EFI_SUCCESS;
 }
 
diff --git a/efi/loader/runtime.c b/efi/loader/runtime.c
index 76b9bc101a06..b46c85eeaa7b 100644
--- a/efi/loader/runtime.c
+++ b/efi/loader/runtime.c
@@ -22,6 +22,8 @@
 #include <restart.h>
 #include <linux/rtc.h>
 
+#include "variable.h"
+
 
 /*
  * EFI runtime code lives in two stages. In the first stage, EFI loader and an
@@ -297,12 +299,12 @@ struct efi_runtime_services efi_runtime_services = {
 	.set_wakeup_time = (void *)efi_unimplemented,
 	.set_virtual_address_map = (void *)efi_unimplemented,
 	.convert_pointer = (void *)efi_unimplemented,
-	.get_variable = (void *)efi_unimplemented,
-	.get_next_variable = (void *)efi_unimplemented,
-	.set_variable = (void *)efi_unimplemented,
+	.get_variable = efi_get_variable_boot,
+	.get_next_variable = efi_get_next_variable_name_boot,
+	.set_variable = efi_set_variable_boot,
 	.get_next_high_mono_count = (void *)efi_unimplemented,
 	.reset_system = &efi_reset_system_boottime,
 	.update_capsule = (void *)efi_unimplemented,
 	.query_capsule_caps = (void *)efi_unimplemented,
-	.query_variable_info = (void *)efi_unimplemented,
+	.query_variable_info = efi_query_variable_info_boot,
 };
diff --git a/efi/loader/setup.c b/efi/loader/setup.c
index 87b7d3a68dc8..a24d3044afdc 100644
--- a/efi/loader/setup.c
+++ b/efi/loader/setup.c
@@ -11,6 +11,7 @@
 
 #include <linux/printk.h>
 #include <linux/array_size.h>
+#include <linux/sizes.h>
 #include <driver.h>
 #include <string.h>
 #include <magicvar.h>
diff --git a/efi/loader/variable.h b/efi/loader/variable.h
new file mode 100644
index 000000000000..3710be84a2d1
--- /dev/null
+++ b/efi/loader/variable.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <efi/types.h>
+#include <efi/error.h>
+
+efi_status_t EFIAPI efi_get_variable_boot(u16 *variable_name,
+					  const efi_guid_t *vendor, u32 *attributes,
+					  efi_uintn_t *data_size, void *data);
+
+efi_status_t EFIAPI efi_set_variable_boot(u16 *variable_name,
+					  const efi_guid_t *vendor, u32 attributes,
+					  efi_uintn_t data_size, const void *data);
+
+efi_status_t EFIAPI efi_get_next_variable_name_boot(efi_uintn_t *variable_name_size,
+						    u16 *variable_name,
+						    efi_guid_t *vendor);
+
+efi_status_t EFIAPI efi_query_variable_info_boot(
+			u32 attributes, u64 *maximum_variable_storage_size,
+			u64 *remaining_variable_storage_size,
+			u64 *maximum_variable_size);
+
+efi_status_t efi_init_secure_state(void);
+
+bool efi_secure_boot_enabled(void);
+
+void *efi_get_var(const u16 *name, const efi_guid_t *vendor, efi_uintn_t *size);
+
+struct efi_var_file;
+
+efi_status_t efi_var_collect(struct efi_var_file **bufp, loff_t *lenp,
+			     u32 check_attr_mask);
+
+efi_status_t efi_var_to_file(void);
diff --git a/efi/runtime/Makefile b/efi/runtime/Makefile
new file mode 100644
index 000000000000..90ed3ef454be
--- /dev/null
+++ b/efi/runtime/Makefile
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: GPL-2.0
+
+lib-y += efi_var_mem.o efi_variable.o
+
+KASAN_SANITIZE := n
+UBSAN_SANITIZE := n
+
+KBUILD_CFLAGS += $(picflags-y) -include $(srctree)/efi/runtime/common.h
+
+# Even when -mbranch-protection=none is set, Clang will generate a
+# .note.gnu.property for code-less object files (like lib/ctype.c),
+# so work around this by explicitly removing the unwanted section.
+# https://bugs.llvm.org/show_bug.cgi?id=46480
+EFIRTCP_FLAGS-y	+= --remove-section=.note.gnu.property
+
+# Cover compiler-generaed symbols like __func__ as well
+EFIRTCP_FLAGS-y	+= --prefix-alloc-sections .efi_runtime
+
+EFIRTCP_FLAGS-y	+= --redefine-sym memset=__pi_memset \
+		   --redefine-sym memcpy=__pi_memcpy \
+		   --redefine-sym memmove=__pi_memmove \
+		   --redefine-sym crc32=__pi_crc32
+
+#
+# Strip debug sections and some other sections that may legally contain
+# absolute relocations, so that we can inspect the remaining sections for
+# such relocations. If none are found, regenerate the output object, but
+# this time, use objcopy and leave all sections in place.
+#
+quiet_cmd_efirtcopy = EFIRTCP $@
+      cmd_efirtcopy =							\
+	$(STRIP) --strip-debug -o $@ $<;				\
+	if [ -n "$(EFIRTCP_RELOC-y)" ] && \
+	    $(OBJDUMP) -r $@ | grep $(EFIRTCP_RELOC-y); then		\
+		echo "$@: absolute symbol references not allowed in the EFI runtime" >&2; \
+		/bin/false;						\
+	fi;								\
+	$(OBJCOPY) $(EFIRTCP_FLAGS-y) $< $@
+
+$(obj)/%.efirt.o: $(obj)/%.o FORCE
+	$(call if_changed,efirtcopy)
+
+obj-y := $(patsubst %.o,%.efirt.o,$(lib-y))
diff --git a/efi/runtime/common.h b/efi/runtime/common.h
new file mode 100644
index 000000000000..c3d147ebe0a7
--- /dev/null
+++ b/efi/runtime/common.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __EFI_RUNTME_H_
+#define __EFI_RUNTME_H_
+
+/* For potential use in headers */
+#define __EFI_RUNTIME__
+
+/* We use objcopy(1) to prefix, so avoid double prefixing here */
+#define __efi_runtime
+#define __efi_runtime_data
+#define __efi_runtime_rodata
+#define EFI_RUNTIME_SECTION(sect) sect
+
+#ifdef CONFIG_DEBUG_EFI_RUNTIME_ENTRY
+#include <debug_ll.h>
+
+#define EFI_ENTRY(wstr, ...)	do {	\
+	puts_ll(__func__);		\
+	puts_ll("(");			\
+	putws_ll(wstr ?: L"<NULL>");	\
+	puts_ll(")");			\
+} while (0)
+#define EFI_EXIT(ret)		({	\
+	puts_ll("\t= ");		\
+	puthex_ll((ulong)ret);		\
+	puts_ll("\n");			\
+	(ret);				\
+})
+#else
+#define EFI_ENTRY(...)		(void)0
+#define EFI_EXIT(ret)		({ ret; })
+#endif /* CONFIG_DEBUG_EFI_RUNTIME_ENTRY */
+
+#endif
diff --git a/efi/runtime/efi_var_mem.c b/efi/runtime/efi_var_mem.c
new file mode 100644
index 000000000000..83b5c53b063b
--- /dev/null
+++ b/efi/runtime/efi_var_mem.c
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: GPL-2.0+
+// SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/530e869ff89d9575103637af201fe97864d4f577/lib/efi_loader/efi_var_mem.c
+/*
+ * File interface for UEFI variables
+ *
+ * Copyright (c) 2020, Heinrich Schuchardt
+ */
+
+#include <linux/kernel.h>
+#include <efi/loader.h>
+#include <efi/loader/variable.h>
+#include <efi/variable.h>
+#include <efi/runtime.h>
+#include <efi/error.h>
+#include <charset.h>
+#include <crc.h>
+
+#define efi_memcpy_runtime	memcpy
+
+/*
+ * Below variables must be static to avoid referencing them via the global
+ * offset table (section .got). The GOT is neither mapped as
+ * EfiRuntimeServicesData nor do we support its relocation during
+ * SetVirtualAddressMap().
+ *
+ * TODO: We probably want some vDSO-like mechanism.
+ */
+static struct efi_var_file __efi_runtime_data *efi_var_buf;
+static unsigned __efi_runtime_data efi_var_buf_rtsize;
+static struct efi_var_entry __efi_runtime_data *efi_current_var;
+static const u16 __efi_runtime_rodata vtf[] = u"VarToFile";
+
+__efi_runtime void efi_var_buf_set(struct efi_var_file *buf, unsigned size)
+{
+	efi_var_buf = buf;
+	efi_var_buf_rtsize = size;
+}
+
+__efi_runtime struct efi_var_file *efi_var_buf_get(unsigned *size)
+{
+	if (size)
+		*size = efi_var_buf_rtsize;
+	return efi_var_buf;
+}
+
+/**
+ * efi_var_mem_compare() - compare GUID and name with a variable
+ *
+ * @var:	variable to compare
+ * @guid:	GUID to compare
+ * @name:	variable name to compare
+ * @next:	pointer to next variable
+ * Return:	true if match
+ */
+static bool __efi_runtime
+efi_var_mem_compare(struct efi_var_entry *var, const efi_guid_t *guid,
+		    const u16 *name, struct efi_var_entry **next)
+{
+	int i;
+	u8 *guid1, *guid2;
+	const u16 *data, *var_name;
+	bool match = true;
+
+	for (guid1 = (u8 *)&var->guid, guid2 = (u8 *)guid, i = 0;
+	     i < sizeof(efi_guid_t) && match; ++i)
+		match = (guid1[i] == guid2[i]);
+
+	for (data = var->name, var_name = name;; ++data) {
+		if (match)
+			match = (*data == *var_name);
+		if (!*data)
+			break;
+		if (*var_name)
+			++var_name;
+	}
+
+	++data;
+
+	if (next)
+		*next = (struct efi_var_entry *)
+			ALIGN((uintptr_t)data + var->length, 8);
+
+	if (match)
+		efi_current_var = var;
+
+	return match;
+}
+
+/**
+ * efi_var_entry_len() - Get the entry len including headers & name
+ *
+ * @var:	pointer to variable start
+ *
+ * Return:	8-byte aligned variable entry length
+ */
+
+static u32 __efi_runtime efi_var_entry_len(struct efi_var_entry *var)
+{
+	if (!var)
+		return 0;
+
+	return ALIGN((sizeof(u16) * (u16_strlen(var->name) + 1)) +
+		     var->length + sizeof(*var), 8);
+}
+
+struct efi_var_entry __efi_runtime
+*efi_var_mem_find(const efi_guid_t *guid, const u16 *name,
+		  struct efi_var_entry **next)
+{
+	struct efi_var_entry *var, *last;
+
+	last = (struct efi_var_entry *)
+	       ((uintptr_t)efi_var_buf + efi_var_buf->length);
+
+	if (!*name) {
+		if (next) {
+			*next = efi_var_buf->var;
+			if (*next >= last)
+				*next = NULL;
+		}
+		return NULL;
+	}
+	if (efi_current_var &&
+	    efi_var_mem_compare(efi_current_var, guid, name, next)) {
+		if (next && *next >= last)
+			*next = NULL;
+		return efi_current_var;
+	}
+
+	var = efi_var_buf->var;
+	if (var < last) {
+		for (; var;) {
+			struct efi_var_entry *pos;
+			bool match;
+
+			match = efi_var_mem_compare(var, guid, name, &pos);
+			if (pos >= last)
+				pos = NULL;
+			if (match) {
+				if (next)
+					*next = pos;
+				return var;
+			}
+			var = pos;
+		}
+	}
+	if (next)
+		*next = NULL;
+	return NULL;
+}
+
+void __efi_runtime efi_var_mem_del(struct efi_var_entry *var)
+{
+	u16 *data;
+	struct efi_var_entry *next, *last;
+
+	if (!var)
+		return;
+
+	last = (struct efi_var_entry *)
+	       ((uintptr_t)efi_var_buf + efi_var_buf->length);
+	if (var <= efi_current_var)
+		efi_current_var = NULL;
+
+	for (data = var->name; *data; ++data)
+		;
+	++data;
+	next = (struct efi_var_entry *)
+	       ALIGN((uintptr_t)data + var->length, 8);
+	efi_var_buf->length -= (uintptr_t)next - (uintptr_t)var;
+
+	/* efi_memcpy_runtime() can be used because next >= var. */
+	efi_memcpy_runtime(var, next, (uintptr_t)last - (uintptr_t)next);
+	efi_var_buf->crc32 = crc32(0, (u8 *)efi_var_buf->var,
+				   efi_var_buf->length -
+				   sizeof(struct efi_var_file));
+}
+
+efi_status_t __efi_runtime efi_var_mem_ins(
+				const u16 *variable_name,
+				const efi_guid_t *vendor, u32 attributes,
+				const efi_uintn_t size1, const void *data1,
+				const efi_uintn_t size2, const void *data2,
+				const u64 time)
+{
+	u16 *data;
+	struct efi_var_entry *var;
+	u32 var_name_len;
+
+	var = (struct efi_var_entry *)
+	      ((uintptr_t)efi_var_buf + efi_var_buf->length);
+	var_name_len = u16_strlen(variable_name) + 1;
+	data = var->name + var_name_len;
+
+	if ((uintptr_t)data - (uintptr_t)efi_var_buf + size1 + size2 >
+	    efi_var_buf_rtsize)
+		return EFI_OUT_OF_RESOURCES;
+
+	var->attr = attributes;
+	var->length = size1 + size2;
+	var->time = time;
+
+	efi_memcpy_runtime(&var->guid, vendor, sizeof(efi_guid_t));
+	efi_memcpy_runtime(var->name, variable_name,
+			   sizeof(u16) * var_name_len);
+	efi_memcpy_runtime(data, data1, size1);
+	efi_memcpy_runtime((u8 *)data + size1, data2, size2);
+
+	var = (struct efi_var_entry *)
+	      ALIGN((uintptr_t)data + var->length, 8);
+	efi_var_buf->length = (uintptr_t)var - (uintptr_t)efi_var_buf;
+	efi_var_buf->crc32 = crc32(0, (u8 *)efi_var_buf->var,
+				   efi_var_buf->length -
+				   sizeof(struct efi_var_file));
+
+	return EFI_SUCCESS;
+}
+
+u64 __efi_runtime efi_var_mem_free(void)
+{
+	if (efi_var_buf->length + sizeof(struct efi_var_entry) >=
+	    efi_var_buf_rtsize)
+		return 0;
+
+	return efi_var_buf_rtsize - efi_var_buf->length -
+	       sizeof(struct efi_var_entry);
+}
+
+/**
+ * efi_var_collect_mem() - Copy EFI variables matching attributes mask from
+ *                         efi_var_buf
+ *
+ * @buf:	buffer containing variable collection
+ * @lenp:	buffer length
+ * @mask:	mask of matched attributes
+ *
+ * Return:	Status code
+ */
+static efi_status_t __efi_runtime
+efi_var_collect_mem(struct efi_var_file *buf, efi_uintn_t *lenp, u32 mask)
+{
+	static struct efi_var_file __efi_runtime_data hdr = {
+		.magic = EFI_VAR_FILE_MAGIC,
+	};
+	struct efi_var_entry *last, *var, *var_to;
+
+	hdr.length = sizeof(struct efi_var_file);
+
+	var = efi_var_buf->var;
+	last = (struct efi_var_entry *)
+	       ((uintptr_t)efi_var_buf + efi_var_buf->length);
+	if (buf)
+		var_to = buf->var;
+
+	while (var < last) {
+		u32 len = efi_var_entry_len(var);
+
+		if ((var->attr & mask) != mask) {
+			var = (void *)((uintptr_t)var + len);
+			continue;
+		}
+
+		hdr.length += len;
+
+		if (buf && hdr.length <= *lenp) {
+			efi_memcpy_runtime(var_to, var, len);
+			var_to = (void *)var_to + len;
+		}
+		var = (void *)var + len;
+	}
+
+	if (!buf && hdr.length <= *lenp) {
+		*lenp = hdr.length;
+		return EFI_INVALID_PARAMETER;
+	}
+
+	if (!buf || hdr.length > *lenp) {
+		*lenp = hdr.length;
+		return EFI_BUFFER_TOO_SMALL;
+	}
+	hdr.crc32 = crc32(0, (u8 *)buf->var,
+			  hdr.length - sizeof(struct efi_var_file));
+
+	efi_memcpy_runtime(buf, &hdr, sizeof(hdr));
+	*lenp = hdr.length;
+
+	return EFI_SUCCESS;
+}
+
+efi_status_t __efi_runtime
+efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor,
+		     u32 *attributes, efi_uintn_t *data_size, void *data,
+		     u64 *timep, u32 mask)
+{
+	efi_uintn_t old_size;
+	struct efi_var_entry *var;
+	u16 *pdata;
+
+	if (!variable_name || !vendor || !data_size)
+		return EFI_INVALID_PARAMETER;
+	var = efi_var_mem_find(vendor, variable_name, NULL);
+	if (!var)
+		return EFI_NOT_FOUND;
+
+	/*
+	 * This function is used at runtime to dump EFI variables.
+	 * The memory backend we keep around has BS-only variables as
+	 * well. At runtime we filter them here
+	 */
+	if (mask && !((var->attr & mask) == mask))
+		return EFI_NOT_FOUND;
+
+	if (attributes)
+		*attributes = var->attr;
+	if (timep)
+		*timep = var->time;
+
+	if (!u16_strcmp(variable_name, vtf))
+		return efi_var_collect_mem(data, data_size, EFI_VARIABLE_NON_VOLATILE);
+
+	old_size = *data_size;
+	*data_size = var->length;
+	if (old_size < var->length)
+		return EFI_BUFFER_TOO_SMALL;
+
+	if (!data)
+		return EFI_INVALID_PARAMETER;
+
+	for (pdata = var->name; *pdata; ++pdata)
+		;
+	++pdata;
+
+	efi_memcpy_runtime(data, pdata, var->length);
+
+	return EFI_SUCCESS;
+}
+
+efi_status_t __efi_runtime
+efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size,
+			       u16 *variable_name, efi_guid_t *vendor,
+			       u32 mask)
+{
+	struct efi_var_entry *var;
+	efi_uintn_t len, old_size;
+	u16 *pdata;
+
+	if (!variable_name_size || !variable_name || !vendor)
+		return EFI_INVALID_PARAMETER;
+
+skip:
+	len = *variable_name_size >> 1;
+	if (u16_strnlen(variable_name, len) == len)
+		return EFI_INVALID_PARAMETER;
+
+	if (!efi_var_mem_find(vendor, variable_name, &var) && *variable_name)
+		return EFI_INVALID_PARAMETER;
+
+	if (!var)
+		return EFI_NOT_FOUND;
+
+	for (pdata = var->name; *pdata; ++pdata)
+		;
+	++pdata;
+
+	old_size = *variable_name_size;
+	*variable_name_size = (uintptr_t)pdata - (uintptr_t)var->name;
+
+	if (old_size < *variable_name_size)
+		return EFI_BUFFER_TOO_SMALL;
+
+	efi_memcpy_runtime(variable_name, var->name, *variable_name_size);
+	efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t));
+
+	if (mask && !((var->attr & mask) == mask)) {
+		*variable_name_size = old_size;
+		goto skip;
+	}
+
+	return EFI_SUCCESS;
+}
diff --git a/efi/runtime/efi_variable.c b/efi/runtime/efi_variable.c
new file mode 100644
index 000000000000..5dc10846f5d3
--- /dev/null
+++ b/efi/runtime/efi_variable.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0+
+// SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/58d825fb18053ec7e432de7bbb70a452b9228076/lib/efi_loader/efi_variable.c
+/*
+ * UEFI runtime variable services
+ *
+ * Copyright (c) 2017 Rob Clark
+ */
+
+#include <linux/kernel.h>
+#include <efi/loader/variable.h>
+#include <efi/services.h>
+#include <efi/variable.h>
+#include <efi/loader.h>
+#include <efi/error.h>
+#include <efi/runtime.h>
+#include <charset.h>
+#include <stdlib.h>
+
+efi_status_t __efi_runtime
+efi_get_variable_int(const u16 *variable_name, const efi_guid_t *vendor,
+		     u32 *attributes, efi_uintn_t *data_size, void *data,
+		     u64 *timep)
+{
+	return efi_get_variable_mem(variable_name, vendor, attributes, data_size,
+				    data, timep, 0);
+}
+
+efi_status_t __efi_runtime
+efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
+			       u16 *variable_name, efi_guid_t *vendor)
+{
+	return efi_get_next_variable_name_mem(variable_name_size, variable_name,
+					      vendor, 0);
+}
+
+/**
+ * efi_setvariable_allowed() - checks defined by the UEFI spec for setvariable
+ *
+ * @variable_name:	name of the variable
+ * @vendor:		vendor GUID
+ * @attributes:		attributes of the variable
+ * @data_size:		size of the buffer with the variable value
+ * @data:		buffer with the variable value
+ * Return:		status code
+ */
+efi_status_t __efi_runtime
+efi_setvariable_allowed(const u16 *variable_name, const efi_guid_t *vendor,
+		    u32 attributes, efi_uintn_t data_size, const void *data)
+{
+	if (!variable_name || !*variable_name || !vendor)
+		return EFI_INVALID_PARAMETER;
+
+	if (data_size && !data)
+		return EFI_INVALID_PARAMETER;
+
+	/*
+	 * EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated.
+	 * We don't support EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS.
+	 */
+	if (attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \
+			  EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS))
+		return EFI_UNSUPPORTED;
+
+	/* Make sure if runtime bit is set, boot service bit is set also */
+	if ((attributes &
+	     (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) ==
+	    EFI_VARIABLE_RUNTIME_ACCESS)
+		return EFI_INVALID_PARAMETER;
+
+	/* only EFI_VARIABLE_NON_VOLATILE attribute is invalid */
+	if ((attributes & EFI_VARIABLE_MASK) == EFI_VARIABLE_NON_VOLATILE)
+		return EFI_INVALID_PARAMETER;
+
+	/* Make sure HR is set with NV, BS and RT */
+	if (attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD &&
+	    (!(attributes & EFI_VARIABLE_NON_VOLATILE) ||
+	     !(attributes & EFI_VARIABLE_RUNTIME_ACCESS) ||
+	     !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)))
+		return EFI_INVALID_PARAMETER;
+
+	return EFI_SUCCESS;
+}
+
+efi_status_t __efi_runtime
+efi_query_variable_info_int(u32 attributes,
+			    u64 *maximum_variable_storage_size,
+			    u64 *remaining_variable_storage_size,
+			    u64 *maximum_variable_size)
+{
+	unsigned size;
+
+	if (!maximum_variable_storage_size ||
+	    !remaining_variable_storage_size ||
+	    !maximum_variable_size || !attributes)
+		return EFI_INVALID_PARAMETER;
+
+	/* EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated */
+	if ((attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) ||
+	    ((attributes & EFI_VARIABLE_MASK) == 0))
+		return EFI_UNSUPPORTED;
+
+	if ((attributes & EFI_VARIABLE_MASK) == EFI_VARIABLE_NON_VOLATILE)
+		return EFI_INVALID_PARAMETER;
+
+	/* Make sure if runtime bit is set, boot service bit is set also. */
+	if ((attributes &
+	     (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) ==
+	    EFI_VARIABLE_RUNTIME_ACCESS)
+		return EFI_INVALID_PARAMETER;
+
+	if (attributes & ~EFI_VARIABLE_MASK)
+		return EFI_INVALID_PARAMETER;
+
+	efi_var_buf_get(&size);
+
+	*maximum_variable_storage_size = size - sizeof(struct efi_var_file);
+	*remaining_variable_storage_size = efi_var_mem_free();
+	*maximum_variable_size = size - sizeof(struct efi_var_file) -
+				 sizeof(struct efi_var_entry);
+	return EFI_SUCCESS;
+}
+
+/**
+ * efirt_set_variable() - runtime implementation of SetVariable()
+ *
+ * @variable_name:	name of the variable
+ * @vendor:		vendor GUID
+ * @attributes:		attributes of the variable
+ * @data_size:		size of the buffer with the variable value
+ * @data:		buffer with the variable value
+ * Return:		status code
+ */
+efi_status_t __efi_runtime EFIAPI
+efirt_set_variable(u16 *variable_name, const efi_guid_t *vendor,
+		   u32 attributes, efi_uintn_t data_size,
+		   const void *data)
+{
+	struct efi_var_entry *var;
+	efi_uintn_t ret;
+	bool append, delete;
+	u64 time = 0;
+
+	if (!IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE))
+		return EFI_UNSUPPORTED;
+
+	/*
+	 * Authenticated variables are not supported. The EFI spec
+	 * in §32.3.6 requires keys to be stored in non-volatile storage which
+	 * is tamper and delete resistant.
+	 * The rest of the checks are in efi_setvariable_allowed()
+	 */
+	if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
+		return EFI_INVALID_PARAMETER;
+
+	ret = efi_setvariable_allowed(variable_name, vendor, attributes, data_size,
+				      data);
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	/* check if a variable exists */
+	var = efi_var_mem_find(vendor, variable_name, NULL);
+	append = !!(attributes & EFI_VARIABLE_APPEND_WRITE);
+	attributes &= ~EFI_VARIABLE_APPEND_WRITE;
+	delete = !append && (!data_size || !attributes);
+
+	/* BS only variables are hidden deny writing them */
+	if (!delete && !(attributes & EFI_VARIABLE_RUNTIME_ACCESS))
+		return EFI_INVALID_PARAMETER;
+
+	if (var) {
+		if (var->attr & EFI_VARIABLE_READ_ONLY ||
+		    !(var->attr & EFI_VARIABLE_NON_VOLATILE))
+			return EFI_WRITE_PROTECTED;
+
+		/* attributes won't be changed */
+		if (!delete && (((var->attr & ~EFI_VARIABLE_READ_ONLY) !=
+		    (attributes & ~EFI_VARIABLE_READ_ONLY))))
+			return EFI_INVALID_PARAMETER;
+		time = var->time;
+	} else {
+		if (!(attributes & EFI_VARIABLE_NON_VOLATILE))
+			return EFI_INVALID_PARAMETER;
+		if (append && !data_size)
+			return EFI_SUCCESS;
+		if (delete)
+			return EFI_NOT_FOUND;
+	}
+
+	if (delete) {
+		/* EFI_NOT_FOUND has been handled before */
+		attributes = var->attr;
+		ret = EFI_SUCCESS;
+	} else if (append && var) {
+		u16 *old_data = (void *)((uintptr_t)var->name +
+			sizeof(u16) * (u16_strlen(var->name) + 1));
+
+		ret = efi_var_mem_ins(variable_name, vendor, attributes,
+				      var->length, old_data, data_size, data,
+				      time);
+	} else {
+		ret = efi_var_mem_ins(variable_name, vendor, attributes,
+				      data_size, data, 0, NULL, time);
+	}
+
+	if (ret != EFI_SUCCESS)
+		return ret;
+	/* We are always inserting new variables, get rid of the old copy */
+	efi_var_mem_del(var);
+
+	return EFI_SUCCESS;
+}
diff --git a/include/efi/loader/variable.h b/include/efi/loader/variable.h
new file mode 100644
index 000000000000..2f0038d8350c
--- /dev/null
+++ b/include/efi/loader/variable.h
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/89d911e386cc439c68ab961e76937c377e7d7127/include/efi_variable.h */
+
+#ifndef _EFI_LOADER_VARIABLE_H
+#define _EFI_LOADER_VARIABLE_H
+
+#include <efi/types.h>
+#include <efi/error.h>
+
+#define EFI_VARIABLE_READ_ONLY 0x80000000
+
+enum efi_auth_var_type {
+	EFI_AUTH_VAR_NONE = 0,
+	EFI_AUTH_MODE,
+	EFI_AUTH_VAR_PK,
+	EFI_AUTH_VAR_KEK,
+	EFI_AUTH_VAR_DB,
+	EFI_AUTH_VAR_DBX,
+	EFI_AUTH_VAR_DBT,
+	EFI_AUTH_VAR_DBR,
+};
+
+/**
+ * efi_auth_var_get_type() - convert variable name and guid to enum
+ *
+ * @name:	name of UEFI variable
+ * @guid:	guid of UEFI variable
+ * Return:	identifier for authentication related variables
+ */
+enum efi_auth_var_type efi_auth_var_get_type(const u16 *name,
+					     const efi_guid_t *guid);
+
+/**
+ * efi_auth_var_get_guid() - get the predefined GUID for a variable name
+ *
+ * @name:	name of UEFI variable
+ * Return:	guid of UEFI variable
+ */
+const efi_guid_t *efi_auth_var_get_guid(const u16 *name);
+
+/**
+ * efi_var_mem_init() - set-up variable list
+ *
+ * Return:	status code
+ */
+efi_status_t efi_var_mem_init(void);
+
+/**
+ * efi_get_next_variable_name_mem() - Runtime common code across efi variable
+ *                                    implementations for GetNextVariable()
+ *                                    from the cached memory copy
+ *
+ * @variable_name_size:	size of variable_name buffer in bytes
+ * @variable_name:	name of uefi variable's name in u16
+ * @mask:		bitmask with required attributes of variables to be collected.
+ *                      variables are only collected if all of the required
+ *                      attributes match. Use 0 to skip matching
+ * @vendor:		vendor's guid
+ *
+ * Return: status code
+ */
+efi_status_t __efi_runtime
+efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_name,
+			       efi_guid_t *vendor, u32 mask);
+/**
+ * efi_get_variable_mem() - Runtime common code across efi variable
+ *                          implementations for GetVariable() from
+ *                          the cached memory copy
+ *
+ * @variable_name:	name of the variable
+ * @vendor:		vendor GUID
+ * @attributes:		attributes of the variable
+ * @data_size:		size of the buffer to which the variable value is copied
+ * @data:		buffer to which the variable value is copied
+ * @timep:		authentication time (seconds since start of epoch)
+ * @mask:		bitmask with required attributes of variables to be collected.
+ *                      variables are only collected if all of the required
+ *                      attributes match. Use 0 to skip matching
+ * Return:		status code
+ */
+efi_status_t __efi_runtime
+efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor,
+		     u32 *attributes, efi_uintn_t *data_size, void *data,
+		     u64 *timep, u32 mask);
+
+/*
+ * This constant identifies the file format for storing UEFI variables in
+ * struct efi_var_file.
+ */
+#define EFI_VAR_FILE_MAGIC 0x0161566966456255 /* UbEfiVa, version 1 */
+
+/**
+ * struct efi_var_entry - UEFI variable file entry
+ *
+ * @length:	length of enty, multiple of 8
+ * @attr:	variable attributes
+ * @time:	authentication time (seconds since start of epoch)
+ * @guid:	vendor GUID
+ * @name:	UTF16 variable name
+ */
+struct efi_var_entry {
+	u32 length;
+	u32 attr;
+	u64 time;
+	efi_guid_t guid;
+	u16 name[];
+};
+
+/**
+ * struct efi_var_file - file for storing UEFI variables
+ *
+ * @reserved:	unused, may be overwritten by memory probing
+ * @magic:	identifies file format, takes value %EFI_VAR_FILE_MAGIC
+ * @length:	length including header
+ * @crc32:	CRC32 without header
+ * @var:	variables
+ */
+struct efi_var_file {
+	u64 reserved;
+	u64 magic;
+	u32 length;
+	u32 crc32;
+	struct efi_var_entry var[];
+};
+
+/**
+ * efi_var_buf_update() - udpate memory buffer for variables
+ *
+ * @var_buf:	source buffer
+ *
+ * This function copies to the memory buffer for UEFI variables. Call this
+ * function in ExitBootServices() if memory backed variables are only used
+ * at runtime to fill the buffer.
+ */
+void efi_var_buf_update(struct efi_var_file *var_buf);
+
+/* The name within the ESP of the file used to store barebox' EFI variables */
+extern char *efi_var_file_name;
+
+/**
+ * efi_var_from_file() - read variables from file
+ *
+ * File ubootefi.var is read from the EFI system partitions and the variables
+ * stored in the file are created.
+ *
+ * In case the file does not exist yet or a variable cannot be set EFI_SUCCESS
+ * is returned.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_var_from_file(int dirfd, const char *filename);
+
+#endif
diff --git a/include/efi/runtime.h b/include/efi/runtime.h
new file mode 100644
index 000000000000..d7f4f4264106
--- /dev/null
+++ b/include/efi/runtime.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/89d911e386cc439c68ab961e76937c377e7d7127/include/efi_variable.h */
+/*
+ * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+#ifndef _EFI_RUNTIME_H
+#define _EFI_RUNTIME_H
+
+#include <efi/types.h>
+
+#define EFI_VARIABLE_READ_ONLY 0x80000000
+
+/**
+ * efi_get_variable_int() - retrieve value of a UEFI variable
+ *
+ * @variable_name:	name of the variable
+ * @vendor:		vendor GUID
+ * @attributes:		attributes of the variable
+ * @data_size:		size of the buffer to which the variable value is copied
+ * @data:		buffer to which the variable value is copied
+ * @timep:		authentication time (seconds since start of epoch)
+ * Return:		status code
+ */
+efi_status_t __efi_runtime
+efi_get_variable_int(const u16 *variable_name,
+		     const efi_guid_t *vendor,
+		     u32 *attributes, efi_uintn_t *data_size,
+		     void *data, u64 *timep);
+
+/**
+ * efi_set_variable_int() - set value of a UEFI variable
+ *
+ * @variable_name:	name of the variable
+ * @vendor:		vendor GUID
+ * @attributes:		attributes of the variable
+ * @data_size:		size of the buffer with the variable value
+ * @data:		buffer with the variable value
+ * @ro_check:		check the read only read only bit in attributes
+ * Return:		status code
+ */
+efi_status_t efi_set_variable_int(const u16 *variable_name,
+				  const efi_guid_t *vendor,
+				  u32 attributes, efi_uintn_t data_size,
+				  const void *data, bool ro_check);
+
+/**
+ * efi_query_variable_info_int() - get information about EFI variables
+ *
+ * This function implements the QueryVariableInfo() runtime service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @attributes:				bitmask to select variables to be
+ *					queried
+ * @maximum_variable_storage_size:	maximum size of storage area for the
+ *					selected variable types
+ * @remaining_variable_storage_size:	remaining size of storage are for the
+ *					selected variable types
+ * @maximum_variable_size:		maximum size of a variable of the
+ *					selected type
+ * Returns:				status code
+ */
+efi_status_t __efi_runtime
+efi_query_variable_info_int(u32 attributes,
+			    u64 *maximum_variable_storage_size,
+			    u64 *remaining_variable_storage_size,
+			    u64 *maximum_variable_size);
+
+/**
+ * efi_setvariable_allowed() - checks defined by the UEFI spec for setvariable
+ *
+ * @variable_name:	name of the variable
+ * @vendor:		vendor GUID
+ * @attributes:		attributes of the variable
+ * @data_size:		size of the buffer with the variable value
+ * @data:		buffer with the variable value
+ * Return:		status code
+ */
+efi_status_t __efi_runtime
+efi_setvariable_allowed(const u16 *variable_name, const efi_guid_t *vendor,
+			u32 attributes, efi_uintn_t data_size, const void *data);
+
+
+efi_status_t __efi_runtime EFIAPI
+efirt_set_variable(u16 *variable_name, const efi_guid_t *vendor,
+		   u32 attributes, efi_uintn_t data_size,
+		   const void *data);
+
+/**
+ * efi_var_mem_find() - find a variable in the list
+ *
+ * @guid:	GUID of the variable
+ * @name:	name of the variable
+ * @next:	on exit pointer to the next variable after the found one
+ * Return:	found variable
+ */
+struct efi_var_entry *efi_var_mem_find(const efi_guid_t *guid, const u16 *name,
+				       struct efi_var_entry **next);
+
+/**
+ * efi_var_mem_ins() - append a variable to the list of variables
+ *
+ * The variable is appended without checking if a variable of the same name
+ * already exists. The two data buffers are concatenated.
+ *
+ * @variable_name:	variable name
+ * @vendor:		GUID
+ * @attributes:		variable attributes
+ * @size1:		size of the first data buffer
+ * @data1:		first data buffer
+ * @size2:		size of the second data field
+ * @data2:		second data buffer
+ * @time:		time of authentication (as seconds since start of epoch)
+ * Result:		status code
+ */
+efi_status_t __efi_runtime
+efi_var_mem_ins(const u16 *variable_name,
+		const efi_guid_t *vendor, u32 attributes,
+		const efi_uintn_t size1, const void *data1,
+		const efi_uintn_t size2, const void *data2,
+		const u64 time);
+
+/**
+ * efi_get_next_variable_name_int() - enumerate the current variable names
+ *
+ * @variable_name_size:	size of variable_name buffer in byte
+ * @variable_name:	name of uefi variable's name in u16
+ * @vendor:		vendor's guid
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * Return: status code
+ */
+efi_status_t __efi_runtime
+efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
+			       u16 *variable_name,
+			       efi_guid_t *vendor);
+
+/**
+ * efi_var_mem_del() - delete a variable from the list of variables
+ *
+ * @var:	variable to delete
+ */
+void __efi_runtime efi_var_mem_del(struct efi_var_entry *var);
+
+/**
+ * efi_var_mem_free() - determine free memory for variables
+ *
+ * Return:	maximum data size plus variable name size
+ */
+u64 __efi_runtime efi_var_mem_free(void);
+
+struct efi_var_file;
+extern __efi_runtime void efi_var_buf_set(struct efi_var_file *buf, unsigned size);
+extern __efi_runtime struct efi_var_file *efi_var_buf_get(unsigned *size);
+
+struct efi_system_table;
+void __efi_runtime efirt_trace_init(void *_ring);
+void efi_runtime_prep(void);
+void __efi_runtime efi_runtime_detach(struct efi_system_table *systab);
+
+#endif
diff --git a/include/efi/variable.h b/include/efi/variable.h
index 53f465117cd5..12c39ef592a8 100644
--- a/include/efi/variable.h
+++ b/include/efi/variable.h
@@ -15,6 +15,10 @@
 #define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x0000000000000010
 #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x0000000000000020
 #define EFI_VARIABLE_APPEND_WRITE	0x0000000000000040
+#define EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS	0x00000080
+
+#define EFI_VARIABLE_ACCESSIBLE(attrs) \
+	((attrs) & (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS))
 
 #define EFI_VARIABLE_MASK 	(EFI_VARIABLE_NON_VOLATILE | \
 				EFI_VARIABLE_BOOTSERVICE_ACCESS | \
@@ -22,7 +26,8 @@
 				EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
 				EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \
 				EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
-				EFI_VARIABLE_APPEND_WRITE)
+				EFI_VARIABLE_APPEND_WRITE | \
+				EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS)
 /*
  * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"))
  * not including trailing NUL
-- 
2.47.3




  parent reply	other threads:[~2025-12-18 11:41 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-18 10:37 [PATCH v1 00/54] efi: implement EFI loader support in barebox Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 01/54] efi: payload: initrd: fix type mismatch on 32-bit Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 02/54] efi: loader: switch over event/memory key type to efi_uintn_t Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 03/54] lib: vsprintf: print human-readable EFI GUIDs with %pUs Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 04/54] fs: fat: don't duplicate dentries when resolving differently cased paths Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 05/54] efi: loader: add memory accounting Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 06/54] efi: loader: add pool allocator Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 07/54] efi: types: add EFI_RUNTIME_SECTION Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 08/54] resource: assign memory banks a default type and attr Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 09/54] ARM: lds: add EFI runtime service section Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 10/54] ARM: move needed assembly routines into EFI runtime section Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 11/54] crypto: crc32: implement position independent CRC32 Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 12/54] efi: loader: add support for tracing calls back into UEFI Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 13/54] efi: loader: add table utility functions Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 14/54] lib: add charset helpers Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 15/54] efi: loader: add object handling API Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 16/54] efi: loader: add devicepath support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 17/54] efi: loader: add debug support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 18/54] efi: loader: add boot services support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 19/54] efi: loader: add support for runtime services before ExitBootServices Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 20/54] efi: loader: setup root node Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 21/54] efi: loader: add watchdog support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 22/54] efi: loader: move PE implementation out of common code Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 23/54] efi: loader: protocol: add file protocol support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 24/54] efi: loader: protocol: add Block IO support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 25/54] efi: loader: protocol: implement efi_file_from_path Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 26/54] efi: loader: boot: implement LoadImage BootService Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 27/54] efi: loader: add EFI load option handling Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 28/54] efi: loader: protocol: add graphical output protocol support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 29/54] efi: loader: protocol: add console support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 30/54] efi: loader: protocol: add HII support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 31/54] efi: loader: protocol: add unicode collation support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 32/54] efi: loader: protocol: add random number generator protocol Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 33/54] efi: loader: protocol: add device_path_utilities Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 34/54] efi: loader: support formatting only first device path node to text Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 35/54] efi: loader: protocol: add efi_device_path_to_text support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 36/54] restart: allow drivers to register runtime restart handler Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 37/54] poweroff: allow drivers to register runtime poweroff handler Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 38/54] ARM: psci: client: register runtime service " Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 39/54] ARM: psci: client: register runtime service restart handler Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 40/54] hardening: disable some features when EFI runtime support is enabled Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 41/54] filetype: add new filetype for efi-stubbed ARM zImages Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 42/54] bootm: add global.bootm.efi toggle Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 43/54] efi: loader: add ESP boot entry provider Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 44/54] efi: loader: add rudimentary EFI boot manager Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 45/54] efi: loader: implement bootm handler Ahmad Fatoum
2025-12-18 10:38 ` Ahmad Fatoum [this message]
2025-12-18 10:38 ` [PATCH v1 47/54] efi: loader: populate OsIndicationsSupported/PlatformLang variables Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 48/54] ARM: don't disable MMU when EFI booting Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 49/54] efi: runtime: add runtime service support after ExitBootServices Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 50/54] efi: runtime: add relocation check Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 51/54] efi: loader: CONFIG_EFI_RT_VOLATILE_STORE Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 52/54] efi: loader: support ExitBootServices Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 53/54] efi: loader: pass along SMBIOS table Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 54/54] ARM: configs: add multi_v7/8_efiloader_defconfig Ahmad Fatoum

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251218111242.1527495-47-a.fatoum@pengutronix.de \
    --to=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox