All of lore.kernel.org
 help / color / mirror / Atom feed
From: AKASHI Takahiro <takahiro.akashi@linaro.org>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v2 05/11] env: save UEFI non-volatile variables in dedicated storage
Date: Wed, 24 Apr 2019 15:30:39 +0900	[thread overview]
Message-ID: <20190424063045.14443-6-takahiro.akashi@linaro.org> (raw)
In-Reply-To: <20190424063045.14443-1-takahiro.akashi@linaro.org>

We need a variant of env_save()/env_load() to handle dedicated storage
for UEFI variables.
It is assumed that env_efi_load() will be called only ince at init
and that env_efi_save() will be called at every SetVariable.

In this patch, new parameters will be expected to be configured:
  CONFIG_ENV_EFI_FAT_DEVICE_AND_PART
  CONFIG_ENV_EFI_FAT_FILE
in case of CONFIG_ENV_IS_IN_FAT.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
---
 env/Kconfig                       |  34 ++++++++++
 env/env.c                         |  98 ++++++++++++++++++++++++++-
 env/fat.c                         | 109 ++++++++++++++++++++++++++++++
 include/asm-generic/global_data.h |   1 +
 include/environment.h             |  24 +++++++
 5 files changed, 265 insertions(+), 1 deletion(-)

diff --git a/env/Kconfig b/env/Kconfig
index 78300660c720..8f59e9347d4b 100644
--- a/env/Kconfig
+++ b/env/Kconfig
@@ -438,6 +438,34 @@ config ENV_FAT_FILE
 	  It's a string of the FAT file name. This file use to store the
 	  environment.
 
+config ENV_EFI_FAT_DEVICE_AND_PART
+	string "Device and partition for where to store the UEFI non-volatile variables in FAT"
+	depends on ENV_IS_IN_FAT
+	depends on EFI_LOADER
+	help
+	  Define this to a string to specify the partition of the device. It can
+	  be as following:
+
+	    "D:P", "D:0", "D", "D:" or "D:auto" (D, P are integers. And P >= 1)
+	       - "D:P": device D partition P. Error occurs if device D has no
+	                partition table.
+	       - "D:0": device D.
+	       - "D" or "D:": device D partition 1 if device D has partition
+	                      table, or the whole device D if has no partition
+	                      table.
+	       - "D:auto": first partition in device D with bootable flag set.
+	                   If none, first valid partition in device D. If no
+	                   partition table then means device D.
+
+config ENV_EFI_FAT_FILE
+	string "Name of the FAT file to use for the UEFI non-volatile variables"
+	depends on ENV_IS_IN_FAT
+	depends on EFI_LOADER
+	default "uboot_efi.env"
+	help
+	  It's a string of the FAT file name. This file use to store the
+	  UEFI non-volatile variables.
+
 config ENV_EXT4_INTERFACE
 	string "Name of the block device for the environment"
 	depends on ENV_IS_IN_EXT4
@@ -470,6 +498,12 @@ config ENV_EXT4_FILE
 	  It's a string of the EXT4 file name. This file use to store the
 	  environment (explicit path to the file)
 
+config ENV_EFI_SIZE
+	hex "UEFI Variables Environment Size"
+	default 0x20000
+	help
+	  Size of the UEFI variables storage area
+
 if ARCH_ROCKCHIP || ARCH_SUNXI || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL || ARC
 
 config ENV_OFFSET
diff --git a/env/env.c b/env/env.c
index 4b417b90a291..d5af761ba57e 100644
--- a/env/env.c
+++ b/env/env.c
@@ -24,6 +24,10 @@ void env_fix_drivers(void)
 			entry->load += gd->reloc_off;
 		if (entry->save)
 			entry->save += gd->reloc_off;
+		if (entry->efi_load)
+			entry->efi_load += gd->reloc_off;
+		if (entry->efi_save)
+			entry->efi_save += gd->reloc_off;
 		if (entry->init)
 			entry->init += gd->reloc_off;
 	}
@@ -125,7 +129,8 @@ __weak enum env_location env_get_location(enum env_operation op, int prio)
 	if (prio >= ARRAY_SIZE(env_locations))
 		return ENVL_UNKNOWN;
 
-	gd->env_load_prio = prio;
+	if (op != ENVOP_EFI)
+		gd->env_load_prio = prio;
 
 	return env_locations[prio];
 }
@@ -280,3 +285,94 @@ int env_init(void)
 
 	return ret;
 }
+
+#ifdef CONFIG_EFI_LOADER
+extern struct hsearch_data efi_var_htab;
+extern struct hsearch_data efi_nv_var_htab;
+
+/* TODO: experimental */
+int env_efi_save(void)
+{
+	struct env_driver *drv = NULL;
+	int ret;
+
+	if (!efi_nv_var_htab.table)
+		return 0;
+
+	if (gd->env_efi_prio == -1) {
+		printf("Cannot save UEFI non-volatile variable\n");
+		return -1;
+	}
+
+	drv = _env_driver_lookup(env_get_location(ENVOP_EFI, gd->env_efi_prio));
+	if (!drv) {
+		printf("Cannot save UEFI non-volatile variable\n");
+		return -1;
+	}
+
+	ret = drv->efi_save();
+	if (ret)
+		printf("Saving UEFI non-volatile variable failed\n");
+
+	return ret;
+}
+
+/* TODO: experimental */
+/* This function should be called only once at init */
+int env_efi_load(void)
+{
+	struct env_driver *drv = NULL;
+	int prio, ret;
+	enum env_location loc;
+
+	gd->env_efi_prio = -1;
+
+	/* volatile variables */
+	if (!efi_var_htab.table) {
+		ret = himport_r(&efi_var_htab, NULL, 0, '\0', 0, 0, 0, NULL);
+		if (!ret) {
+			printf("Creating default UEFI variables failed\n");
+			return -1;
+		}
+	}
+
+	/* non-loratile variables */
+	if (efi_nv_var_htab.table)
+		return 0;
+
+	for (prio = 0; prio < ARRAY_SIZE(env_locations); prio++) {
+		loc = env_get_location(ENVOP_EFI, prio);
+		drv = _env_driver_lookup(loc);
+		if (!drv)
+			continue;
+
+		if (drv->efi_load && drv->efi_save)
+			break;
+	}
+	if (!drv || prio == ARRAY_SIZE(env_locations)) {
+		printf("No driver for UEFI storage is available\n");
+		return -1;
+	}
+
+	gd->env_efi_prio = prio;
+
+	ret = drv->efi_load();
+	if (ret) {
+		printf("Loading UEFI non-volatile variables failed\n");
+		return -1;
+	}
+
+	/* FIXME: init needed here? */
+	if (!efi_nv_var_htab.table) {
+		ret = himport_r(&efi_nv_var_htab, NULL, 0, '\0', 0, 0, 0, NULL);
+		if (!ret) {
+			printf("Creating default UEFI non-volatile variables failed\n");
+			return -1;
+		}
+
+		return 0;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_EFI_LOADER */
diff --git a/env/fat.c b/env/fat.c
index 7f74c64dfe7e..e2b050d4553d 100644
--- a/env/fat.c
+++ b/env/fat.c
@@ -14,6 +14,7 @@
 #include <malloc.h>
 #include <memalign.h>
 #include <search.h>
+#include <efi_loader.h>
 #include <errno.h>
 #include <fat.h>
 #include <mmc.h>
@@ -128,6 +129,110 @@ err_env_relocate:
 }
 #endif /* LOADENV */
 
+#ifdef CONFIG_EFI_LOADER
+#if 1
+extern int efi_variable_import(const char *buf, int check);
+extern int efi_variable_export(env_t *env_out);
+#endif
+static int env_fat_efi_save(void)
+{
+	env_t __aligned(ARCH_DMA_MINALIGN) env_new;
+	struct blk_desc *dev_desc = NULL;
+	disk_partition_t info;
+	int dev, part;
+	int err;
+	loff_t size;
+
+	err = efi_variable_export(&env_new);
+	if (err)
+		return err;
+
+	part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,
+				       CONFIG_ENV_EFI_FAT_DEVICE_AND_PART,
+				       &dev_desc, &info, 1);
+	if (part < 0)
+		return 1;
+
+	dev = dev_desc->devnum;
+	if (fat_set_blk_dev(dev_desc, &info) != 0) {
+		/*
+		 * This printf is embedded in the messages from env_save that
+		 * will calling it. The missing \n is intentional.
+		 */
+		printf("Unable to use %s %d:%d... ",
+		       CONFIG_ENV_FAT_INTERFACE, dev, part);
+		return 1;
+	}
+
+	err = file_fat_write(CONFIG_ENV_EFI_FAT_FILE,
+			     (void *)&env_new, 0, sizeof(env_t), &size);
+	if (err < 0) {
+		/*
+		 * This printf is embedded in the messages from env_save that
+		 * will calling it. The missing \n is intentional.
+		 */
+		printf("Unable to write \"%s\" from %s%d:%d... ",
+		       CONFIG_ENV_EFI_FAT_FILE, CONFIG_ENV_FAT_INTERFACE,
+		       dev, part);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int env_fat_efi_load(void)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_EFI_SIZE);
+	struct blk_desc *dev_desc = NULL;
+	disk_partition_t info;
+	int dev, part;
+	int err;
+
+#ifdef CONFIG_MMC
+	if (!strcmp(CONFIG_ENV_FAT_INTERFACE, "mmc"))
+		mmc_initialize(NULL);
+#endif
+
+	part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,
+				       CONFIG_ENV_EFI_FAT_DEVICE_AND_PART,
+				       &dev_desc, &info, 1);
+	if (part < 0)
+		goto err_env_relocate;
+
+	dev = dev_desc->devnum;
+	if (fat_set_blk_dev(dev_desc, &info) != 0) {
+		/*
+		 * This printf is embedded in the messages from env_save that
+		 * will calling it. The missing \n is intentional.
+		 */
+		printf("Unable to use %s %d:%d...\n",
+		       CONFIG_ENV_FAT_INTERFACE, dev, part);
+		goto err_env_relocate;
+	}
+
+	err = file_fat_read(CONFIG_ENV_EFI_FAT_FILE, buf, CONFIG_ENV_EFI_SIZE);
+	if (err <= 0 && (err != -ENOENT)) {
+		/*
+		 * This printf is embedded in the messages from env_save that
+		 * will calling it. The missing \n is intentional.
+		 */
+		printf("Unable to read \"%s\" from %s %d:%d...\n",
+		       CONFIG_ENV_EFI_FAT_FILE, CONFIG_ENV_FAT_INTERFACE,
+		       dev, part);
+		goto err_env_relocate;
+	}
+
+	if (err > 0)
+		return efi_variable_import(buf, 1);
+	else
+		return 0;
+
+err_env_relocate:
+
+	return -EIO;
+}
+#endif /* CONFIG_EFI_LOADER */
+
 U_BOOT_ENV_LOCATION(fat) = {
 	.location	= ENVL_FAT,
 	ENV_NAME("FAT")
@@ -137,4 +242,8 @@ U_BOOT_ENV_LOCATION(fat) = {
 #ifdef CMD_SAVEENV
 	.save		= env_save_ptr(env_fat_save),
 #endif
+#ifdef CONFIG_EFI_LOADER
+	.efi_load	= env_fat_efi_load,
+	.efi_save	= env_fat_efi_save,
+#endif
 };
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 78dcf40bff48..8c4d56c346f3 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -51,6 +51,7 @@ typedef struct global_data {
 	unsigned long env_valid;	/* Environment valid? enum env_valid */
 	unsigned long env_has_init;	/* Bitmask of boolean of struct env_location offsets */
 	int env_load_prio;		/* Priority of the loaded environment */
+	int env_efi_prio;		/* Priority of the UEFI variables */
 
 	unsigned long ram_base;		/* Base address of RAM used by U-Boot */
 	unsigned long ram_top;		/* Top address of RAM used by U-Boot */
diff --git a/include/environment.h b/include/environment.h
index cd966761416e..f62399863ef9 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -200,6 +200,7 @@ enum env_operation {
 	ENVOP_INIT,	/* we want to call the init function */
 	ENVOP_LOAD,	/* we want to call the load function */
 	ENVOP_SAVE,	/* we want to call the save function */
+	ENVOP_EFI,	/* we want to call the efi_load/save function */
 };
 
 struct env_driver {
@@ -225,6 +226,24 @@ struct env_driver {
 	 */
 	int (*save)(void);
 
+	/**
+	 * efi_load() - Load UEFI non-volatile variables from storage
+	 *
+	 * This method is required for UEFI non-volatile variables
+	 *
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*efi_load)(void);
+
+	/**
+	 * efi_save() - Save UEFI non-volatile variables to storage
+	 *
+	 * This method is required for UEFI non-volatile variables
+	 *
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*efi_save)(void);
+
 	/**
 	 * init() - Set up the initial pre-relocation environment
 	 *
@@ -312,6 +331,11 @@ void eth_parse_enetaddr(const char *addr, uint8_t *enetaddr);
 int eth_env_get_enetaddr(const char *name, uint8_t *enetaddr);
 int eth_env_set_enetaddr(const char *name, const uint8_t *enetaddr);
 
+#ifdef CONFIG_EFI_LOADER
+int env_efi_load(void);
+int env_efi_save(void);
+#endif
+
 #endif /* DO_DEPS_ONLY */
 
 #endif /* _ENVIRONMENT_H_ */
-- 
2.20.1

  parent reply	other threads:[~2019-04-24  6:30 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-24  6:30 [U-Boot] [PATCH v2 00/11] efi_loader: non-volatile variables support AKASHI Takahiro
2019-04-24  6:30 ` [U-Boot] [PATCH v2 01/11] lib: charset: add u16_strcmp() AKASHI Takahiro
2019-04-24 16:24   ` Heinrich Schuchardt
2019-04-25  0:38     ` AKASHI Takahiro
2019-04-24  6:30 ` [U-Boot] [PATCH v2 02/11] lib: charset: add u16_strncmp() AKASHI Takahiro
2019-04-24 17:40   ` Heinrich Schuchardt
2019-04-24 18:36   ` Heinrich Schuchardt
2019-04-25  0:16     ` AKASHI Takahiro
2019-04-24  6:30 ` [U-Boot] [PATCH v2 03/11] cmd: efidebug: rework "boot dump" sub-command using GetNextVariableName() AKASHI Takahiro
2019-04-24 20:13   ` Heinrich Schuchardt
2019-04-25  0:30     ` AKASHI Takahiro
2019-04-24  6:30 ` [U-Boot] [PATCH v2 04/11] efi_loader: set OsIndicationsSupported at init AKASHI Takahiro
2019-04-24  6:30 ` AKASHI Takahiro [this message]
2019-04-25 18:44   ` [U-Boot] [PATCH v2 05/11] env: save UEFI non-volatile variables in dedicated storage Heinrich Schuchardt
2019-04-24  6:30 ` [U-Boot] [PATCH v2 06/11] efi_loader: variable: support non-volatile attribute AKASHI Takahiro
2019-04-24  6:30 ` [U-Boot] [PATCH v2 07/11] efi_loader: variable: split UEFI variables from U-Boot environment AKASHI Takahiro
2019-04-24  6:30 ` [U-Boot] [PATCH v2 08/11] efi_loader: load saved non-volatile variables at init AKASHI Takahiro
2019-04-24  6:30 ` [U-Boot] [PATCH v2 09/11] efi_loader: bootmgr: handle BootNext as non-volatile AKASHI Takahiro
2019-04-24  6:30 ` [U-Boot] [PATCH v2 10/11] cmd: env: add -nv option for UEFI non-volatile variable AKASHI Takahiro
2019-04-24  6:30 ` [U-Boot] [PATCH v2 11/11] cmd: efidebug: make some boot variables non-volatile AKASHI Takahiro
2019-04-24 22:12 ` [U-Boot] [PATCH v2 00/11] efi_loader: non-volatile variables support Heinrich Schuchardt
2019-04-25  1:12   ` AKASHI Takahiro

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=20190424063045.14443-6-takahiro.akashi@linaro.org \
    --to=takahiro.akashi@linaro.org \
    --cc=u-boot@lists.denx.de \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.