Merge tag 'efi-2020-10-rc1-4' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

Pull request for UEFI sub-system for efi-2020-10-rc1 (4)

Improvements for the UEFI subsystem include:

* support for read-only TEE-backed variables
* allow to compile PK, KEK, db, dbx fixed values into U-Boot
* bug fixes

Python testing related changes comprise:

* enable 'bootefi hello' for better test coverage
* remove SKIP messages in UEFI Python tests

The fitupd command is dropped.
Build errors for the lsblk command are fixed.
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 846c905..bfe6c16 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -378,6 +378,7 @@
 config CMD_BOOTEFI_HELLO
 	bool "Allow booting a standard EFI hello world for testing"
 	depends on CMD_BOOTEFI_HELLO_COMPILE
+	default y if CMD_BOOTEFI_SELFTEST
 	help
 	  This adds a standard EFI hello world application to U-Boot so that
 	  it can be used with the 'bootefi hello' command. This is useful
@@ -489,13 +490,6 @@
 	  flash used by Falcon-mode boot. See the documentation until CMD_SPL
 	  for detail.
 
-config CMD_FITUPD
-	bool "fitImage update command"
-	depends on UPDATE_TFTP
-	help
-	  Implements the 'fitupd' command, which allows to automatically
-	  store software updates present on a TFTP server in NOR Flash
-
 config CMD_THOR_DOWNLOAD
 	bool "thor - TIZEN 'thor' download"
 	select DFU
diff --git a/cmd/Makefile b/cmd/Makefile
index dc412d1..7952138 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -62,7 +62,6 @@
 obj-$(CONFIG_CMD_EXT2) += ext2.o
 obj-$(CONFIG_CMD_FAT) += fat.o
 obj-$(CONFIG_CMD_FDT) += fdt.o
-obj-$(CONFIG_CMD_FITUPD) += fitupd.o
 obj-$(CONFIG_CMD_FLASH) += flash.o
 obj-$(CONFIG_CMD_FPGA) += fpga.o
 obj-$(CONFIG_CMD_FPGAD) += fpgad.o
diff --git a/cmd/fitupd.c b/cmd/fitupd.c
deleted file mode 100644
index 0f490c5..0000000
--- a/cmd/fitupd.c
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * (C) Copyright 2011
- * Andreas Pretzsch, carpe noctem engineering, apr@cn-eng.de
- */
-
-#include <common.h>
-#include <command.h>
-#include <net.h>
-
-static int do_fitupd(struct cmd_tbl *cmdtp, int flag, int argc,
-		     char *const argv[])
-{
-	ulong addr = 0UL;
-
-	if (argc > 2)
-		return CMD_RET_USAGE;
-
-	if (argc == 2)
-		addr = simple_strtoul(argv[1], NULL, 16);
-
-	return update_tftp(addr, NULL, NULL);
-}
-
-U_BOOT_CMD(fitupd, 2, 0, do_fitupd,
-	"update from FIT image",
-	"[addr]\n"
-	"\t- run update from FIT image at addr\n"
-	"\t  or from tftp 'updatefile'"
-);
diff --git a/cmd/lsblk.c b/cmd/lsblk.c
index ece8bbf..653dffc 100644
--- a/cmd/lsblk.c
+++ b/cmd/lsblk.c
@@ -5,6 +5,8 @@
  */
 
 #include <common.h>
+#include <blk.h>
+#include <command.h>
 #include <dm.h>
 
 static int do_lsblk(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
diff --git a/cmd/nvedit.c b/cmd/nvedit.c
index 49338b4..ca0be92 100644
--- a/cmd/nvedit.c
+++ b/cmd/nvedit.c
@@ -1410,7 +1410,7 @@
 #endif
 	"env print [-a | name ...] - print environment\n"
 #if defined(CONFIG_CMD_NVEDIT_EFI)
-	"env print -e [-guid guid|-all][-n] [name ...] - print UEFI environment\n"
+	"env print -e [-guid guid] [-n] [name ...] - print UEFI environment\n"
 #endif
 #if defined(CONFIG_CMD_RUN)
 	"env run var [...] - run commands in an environment variable\n"
@@ -1452,8 +1452,9 @@
 	"print environment variables",
 	"[-a]\n    - print [all] values of all environment variables\n"
 #if defined(CONFIG_CMD_NVEDIT_EFI)
-	"printenv -e [-guid guid|-all][-n] [name ...]\n"
+	"printenv -e [-guid guid][-n] [name ...]\n"
 	"    - print UEFI variable 'name' or all the variables\n"
+	"      \"-guid\": GUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n"
 	"      \"-n\": suppress dumping variable's value\n"
 #endif
 	"printenv name ...\n"
@@ -1487,7 +1488,7 @@
 	"-e [-guid guid][-nv][-bs][-rt][-at][-a][-v]\n"
 	"        [-i addr,size name], or [name [value ...]]\n"
 	"    - set UEFI variable 'name' to 'value' ...'\n"
-	"      \"-guid\": set vendor guid\n"
+	"      \"-guid\": GUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n"
 	"      \"-nv\": set non-volatile attribute\n"
 	"      \"-bs\": set boot-service attribute\n"
 	"      \"-rt\": set runtime attribute\n"
diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c
index 3f61d5d..8e31f43 100644
--- a/cmd/nvedit_efi.c
+++ b/cmd/nvedit_efi.c
@@ -52,8 +52,7 @@
 	{EFI_CERT_TYPE_PKCS7_GUID, "EFI_CERT_TYPE_PKCS7_GUID"},
 };
 
-/* "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */
-static char unknown_guid[37];
+static const char unknown_guid[] = "";
 
 /**
  * efi_guid_to_str() - convert guid to readable name
@@ -71,9 +70,6 @@
 		if (!guidcmp(guid, &efi_guid_text[i].guid))
 			return efi_guid_text[i].text;
 
-	uuid_bin_to_str((unsigned char *)guid->b, unknown_guid,
-			UUID_STR_FORMAT_GUID);
-
 	return unknown_guid;
 }
 
@@ -115,7 +111,7 @@
 		goto out;
 
 	rtc_to_tm(time, &tm);
-	printf("%ls:\n    %s:\n", name, efi_guid_to_str(guid));
+	printf("%ls:\n    %pUl %s\n", name, guid, efi_guid_to_str(guid));
 	if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
 		printf("    %04d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year,
 		       tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
@@ -136,50 +132,6 @@
 	free(data);
 }
 
-/**
- * efi_dump_vars() - show information about named UEFI variables
- *
- * @argc:	Number of arguments (variables)
- * @argv:	Argument (variable name) array
- * @verbose:	if true, dump data
- * Return:	CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE
- *
- * Show information encoded in named UEFI variables
- */
-static int efi_dump_vars(int argc,  char *const argv[],
-			 const efi_guid_t *guid, bool verbose)
-{
-	u16 *var_name16, *p;
-	efi_uintn_t buf_size, size;
-
-	buf_size = 128;
-	var_name16 = malloc(buf_size);
-	if (!var_name16)
-		return CMD_RET_FAILURE;
-
-	for (; argc > 0; argc--, argv++) {
-		size = (utf8_utf16_strlen(argv[0]) + 1) * sizeof(u16);
-		if (buf_size < size) {
-			buf_size = size;
-			p = realloc(var_name16, buf_size);
-			if (!p) {
-				free(var_name16);
-				return CMD_RET_FAILURE;
-			}
-			var_name16 = p;
-		}
-
-		p = var_name16;
-		utf8_utf16_strcpy(&p, argv[0]);
-
-		efi_dump_single_var(var_name16, guid, verbose);
-	}
-
-	free(var_name16);
-
-	return CMD_RET_SUCCESS;
-}
-
 static bool match_name(int argc, char *const argv[], u16 *var_name16)
 {
 	char *buf, *p;
@@ -225,10 +177,7 @@
 	efi_uintn_t buf_size, size;
 	efi_guid_t guid;
 	efi_status_t ret;
-
-	if (argc && guid_p)
-		/* simplified case */
-		return efi_dump_vars(argc, argv, guid_p, verbose);
+	bool match = false;
 
 	buf_size = 128;
 	var_name16 = malloc(buf_size);
@@ -259,13 +208,18 @@
 			return CMD_RET_FAILURE;
 		}
 
-		if ((!guid_p || !guidcmp(guid_p, &guid)) &&
-		    (!argc || match_name(argc, argv, var_name16)))
+		if (guid_p && guidcmp(guid_p, &guid))
+			continue;
+		if (!argc || match_name(argc, argv, var_name16)) {
+			match = true;
 			efi_dump_single_var(var_name16, &guid, verbose);
+		}
 	}
-
 	free(var_name16);
 
+	if (!match && argc == 1)
+		printf("Error: \"%s\" not defined\n", argv[0]);
+
 	return CMD_RET_SUCCESS;
 }
 
@@ -286,9 +240,8 @@
 int do_env_print_efi(struct cmd_tbl *cmdtp, int flag, int argc,
 		     char *const argv[])
 {
-	efi_guid_t guid;
-	const efi_guid_t *guid_p;
-	bool default_guid, guid_any, verbose;
+	const efi_guid_t *guid_p = NULL;
+	bool verbose = true;
 	efi_status_t ret;
 
 	/* Initialize EFI drivers */
@@ -299,31 +252,18 @@
 		return CMD_RET_FAILURE;
 	}
 
-	default_guid = true;
-	guid_any = false;
-	verbose = true;
 	for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
 		if (!strcmp(argv[0], "-guid")) {
-			if (argc == 1)
-				return CMD_RET_USAGE;
+			efi_guid_t guid;
 
-			/* -a already specified */
-			if (!default_guid && guid_any)
+			if (argc == 1)
 				return CMD_RET_USAGE;
-
 			argc--;
 			argv++;
 			if (uuid_str_to_bin(argv[0], guid.b,
 					    UUID_STR_FORMAT_GUID))
 				return CMD_RET_USAGE;
-			default_guid = false;
-		} else if (!strcmp(argv[0], "-all")) {
-			/* -guid already specified */
-			if (!default_guid && !guid_any)
-				return CMD_RET_USAGE;
-
-			guid_any = true;
-			default_guid = false;
+			guid_p = (const efi_guid_t *)guid.b;
 		} else if (!strcmp(argv[0], "-n")) {
 			verbose = false;
 		} else {
@@ -331,13 +271,6 @@
 		}
 	}
 
-	if (guid_any)
-		guid_p = NULL;
-	else if (default_guid)
-		guid_p = &efi_global_variable_guid;
-	else
-		guid_p = (const efi_guid_t *)guid.b;
-
 	/* enumerate and show all UEFI variables */
 	return efi_dump_var_all(argc, argv, guid_p, verbose);
 }
@@ -518,8 +451,7 @@
 			argv++;
 			if (uuid_str_to_bin(argv[0], guid.b,
 					    UUID_STR_FORMAT_GUID)) {
-				printf("## Guid not specified or in XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX format\n");
-				return CMD_RET_FAILURE;
+				return CMD_RET_USAGE;
 			}
 			default_guid = false;
 		} else if (!strcmp(argv[0], "-bs")) {
@@ -567,8 +499,8 @@
 	}
 
 	if (verbose) {
-		printf("GUID: %s\n", efi_guid_to_str((const efi_guid_t *)
-						     &guid));
+		printf("GUID: %pUl %s\n", &guid,
+		       efi_guid_to_str((const efi_guid_t *)&guid));
 		printf("Attributes: 0x%x\n", attributes);
 	}
 
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 9b74e40..d43d78d 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -48,6 +48,7 @@
 CONFIG_CMD_GPT_RENAME=y
 CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
+CONFIG_CMD_LSBLK=y
 CONFIG_CMD_OSD=y
 CONFIG_CMD_PCI=y
 CONFIG_CMD_READ=y
diff --git a/doc/README.dfutftp b/doc/README.dfutftp
index 127d2d6..a3341bb 100644
--- a/doc/README.dfutftp
+++ b/doc/README.dfutftp
@@ -42,8 +42,6 @@
 The "dfu" command has been extended to support transfer via TFTP - one
 needs to type for example "dfu tftp 0 mmc 0"
 
-This feature does not depend on "fitupd" command enabled.
-
 As of this writing (SHA1:8d77576371381ade83de475bb639949b44941e8c v2015.10-rc2)
 the update.c code is not enabled (CONFIG_UPDATE_TFTP) by any board in the
 contemporary u-boot tree.
diff --git a/doc/README.update b/doc/README.update
index d37f2c4..bf43792 100644
--- a/doc/README.update
+++ b/doc/README.update
@@ -51,11 +51,6 @@
 to be prepared. Refer to the doc/uImage.FIT/ directory for more details on FIT
 images.
 
-This mechanism can be also triggered by the command "fitupd".
-If an optional, non-zero address is provided as argument, the TFTP transfer
-is skipped and the image at this address is used.
-The fitupd command is enabled by CONFIG_CMD_FITUPD.
-
 
 Example .its files
 ------------------
diff --git a/doc/uefi/uefi.rst b/doc/uefi/uefi.rst
index 03d6fd0..a72e729 100644
--- a/doc/uefi/uefi.rst
+++ b/doc/uefi/uefi.rst
@@ -188,6 +188,15 @@
     cd <U-Boot source directory>
     pytest.py test/py/tests/test_efi_secboot/test_signed.py --bd sandbox
 
+UEFI binaries may be signed by Microsoft using the following certificates:
+
+* KEK: Microsoft Corporation KEK CA 2011
+  http://go.microsoft.com/fwlink/?LinkId=321185.
+* db: Microsoft Windows Production PCA 2011
+  http://go.microsoft.com/fwlink/p/?linkid=321192.
+* db: Microsoft Corporation UEFI CA 2011
+  http://go.microsoft.com/fwlink/p/?linkid=321194.
+
 Using OP-TEE for EFI variables
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 17a31ec..0577238 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -25,6 +25,8 @@
 extern char __start_rodata[], __end_rodata[];
 extern char __efi_helloworld_begin[];
 extern char __efi_helloworld_end[];
+extern char __efi_var_file_begin[];
+extern char __efi_var_file_end[];
 
 /* Start and end of .ctors section - used for constructor calls. */
 extern char __ctors_start[], __ctors_end[];
diff --git a/include/efi_variable.h b/include/efi_variable.h
index bc5985c..2c629e4 100644
--- a/include/efi_variable.h
+++ b/include/efi_variable.h
@@ -10,6 +10,16 @@
 
 #define EFI_VARIABLE_READ_ONLY BIT(31)
 
+enum efi_auth_var_type {
+	EFI_AUTH_VAR_NONE = 0,
+	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_get_variable() - retrieve value of a UEFI variable
  *
@@ -83,6 +93,10 @@
 
 #define EFI_VAR_BUF_SIZE 0x4000
 
+/*
+ * This constant identifies the file format for storing UEFI variables in
+ * struct efi_var_file.
+ */
 #define EFI_VAR_FILE_MAGIC 0x0161566966456255 /* UbEfiVa, version 1 */
 
 /**
@@ -106,7 +120,7 @@
  * struct efi_var_file - file for storing UEFI variables
  *
  * @reserved:	unused, may be overwritten by memory probing
- * @magic:	identifies file format
+ * @magic:	identifies file format, takes value %EFI_VAR_FILE_MAGIC
  * @length:	length including header
  * @crc32:	CRC32 without header
  * @var:	variables
@@ -129,6 +143,14 @@
 efi_status_t efi_var_to_file(void);
 
 /**
+ * efi_var_restore() - restore EFI variables from buffer
+ *
+ * @buf:	buffer
+ * Return:	status code
+ */
+efi_status_t efi_var_restore(struct efi_var_file *buf);
+
+/**
  * efi_var_from_file() - read variables from file
  *
  * File ubootefi.var is read from the EFI system partitions and the variables
@@ -195,4 +217,20 @@
  */
 u64 efi_var_mem_free(void);
 
+/**
+ * efi_init_secure_state - initialize secure boot state
+ *
+ * Return:	status code
+ */
+efi_status_t efi_init_secure_state(void);
+
+/**
+ * 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(u16 *name, const efi_guid_t *guid);
+
 #endif
diff --git a/include/mm_communication.h b/include/mm_communication.h
index 193c4d1..f9c05bb 100644
--- a/include/mm_communication.h
+++ b/include/mm_communication.h
@@ -205,4 +205,47 @@
 	u32 attr;
 };
 
+#define VAR_CHECK_VARIABLE_PROPERTY_REVISION 0x0001
+#define VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY BIT(0)
+/**
+ * struct var_check_property - Used to store variable properties in StMM
+ *
+ * @revision:   magic revision number for variable property checking
+ * @property:   properties mask for the variable used in StMM.
+ *              Currently RO flag is supported
+ * @attributes: variable attributes used in StMM checking when properties
+ *              for a variable are enabled
+ * @minsize:    minimum allowed size for variable payload checked against
+ *              smm_variable_access->datasize in StMM
+ * @maxsize:    maximum allowed size for variable payload checked against
+ *              smm_variable_access->datasize in StMM
+ *
+ * Defined in EDK2 as VAR_CHECK_VARIABLE_PROPERTY.
+ */
+struct var_check_property {
+	u16         revision;
+	u16         property;
+	u32         attributes;
+	efi_uintn_t minsize;
+	efi_uintn_t maxsize;
+};
+
+/**
+ * struct smm_variable_var_check_property - Used to communicate variable
+ *                                          properties with StMM
+ *
+ * @guid:       vendor GUID
+ * @name_size:  size of EFI name
+ * @property:   variable properties struct
+ * @name:       variable name
+ *
+ * Defined in EDK2 as SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY.
+ */
+struct smm_variable_var_check_property {
+	efi_guid_t                guid;
+	efi_uintn_t               name_size;
+	struct var_check_property property;
+	u16                       name[];
+};
+
 #endif /* _MM_COMMUNICATION_H_ */
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 4324694..6017ffe 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -27,13 +27,51 @@
 
 if EFI_LOADER
 
+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 FAT_WRITE
-	default y
+	help
+	  Select this option if you want non-volatile UEFI variables to be
+	  stored as file /ubootefi.var on the EFI system partition.
+
+config EFI_MM_COMM_TEE
+	bool "UEFI variables storage service via OP-TEE"
+	depends on OPTEE
+	help
+	  If OP-TEE is present and running StandAloneMM, dispatch all UEFI
+	  variable related operations to that. The application will verify,
+	  authenticate and store the variables on an RPMB.
+
+endchoice
+
+config EFI_VARIABLES_PRESEED
+	bool "Initial values for UEFI variables"
+	depends on EFI_VARIABLE_FILE_STORE
 	help
-	  Select tis option if you want non-volatile UEFI variables to be stored
-	  as file /ubootefi.var on the EFI system partition.
+	  Include a file with the initial values for non-volatile UEFI variables
+	  into the U-Boot binary. If this configuration option is set, changes
+	  to authentication related variables (PK, KEK, db, dbx) are not
+	  allowed.
+
+if EFI_VARIABLES_PRESEED
+
+config EFI_VAR_SEED_FILE
+	string "File with initial values of non-volatile UEFI variables"
+	default ubootefi.var
+	help
+	  File with initial values of non-volatile UEFI variables. The file must
+	  be in the same format as the storage in the EFI system partition. The
+	  easiest way to create it is by setting the non-volatile variables in
+	  U-Boot. If a relative file path is used, it is relative to the source
+	  directory.
+
+endif
 
 config EFI_GET_TIME
 	bool "GetTime() runtime service"
@@ -174,13 +212,4 @@
 	  it is signed with a trusted key. To do that, you need to install,
 	  at least, PK, KEK and db.
 
-config EFI_MM_COMM_TEE
-	bool "UEFI variables storage service via OP-TEE"
-	depends on OPTEE
-	default n
-	help
-	  If OP-TEE is present and running StandAloneMM, dispatch all UEFI variable
-	  related operations to that. The application will verify, authenticate and
-	  store the variables on an RPMB.
-
 endif
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index f81ec8d..441ac94 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -6,7 +6,7 @@
 # This file only gets included with CONFIG_EFI_LOADER set, so all
 # object inclusion implicitly depends on it
 
-asflags-y += -DHOST_ARCH="$(HOST_ARCH)"
+asflags-y += -DHOST_ARCH="$(HOST_ARCH)" -I.
 ccflags-y += -DHOST_ARCH="$(HOST_ARCH)"
 
 CFLAGS_efi_boottime.o += \
@@ -42,6 +42,7 @@
 else
 obj-y += efi_variable.o
 obj-y += efi_var_file.o
+obj-$(CONFIG_EFI_VARIABLES_PRESEED) += efi_var_seed.o
 endif
 obj-y += efi_watchdog.o
 obj-$(CONFIG_LCD) += efi_gop.o
@@ -53,3 +54,6 @@
 obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
 obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o
 obj-y += efi_signature.o
+
+EFI_VAR_SEED_FILE := $(subst $\",,$(CONFIG_EFI_VAR_SEED_FILE))
+$(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE)
diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c
index 1e2be11..ee2e67b 100644
--- a/lib/efi_loader/efi_var_common.c
+++ b/lib/efi_loader/efi_var_common.c
@@ -9,6 +9,33 @@
 #include <efi_loader.h>
 #include <efi_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},
+	/* not used yet
+	{u"dbt",  &efi_guid_image_security_database, EFI_AUTH_VAR_DBT},
+	{u"dbr",  &efi_guid_image_security_database, EFI_AUTH_VAR_DBR},
+	*/
+};
+
+static bool efi_secure_boot;
+static enum efi_secure_mode efi_secure_mode;
+
 /**
  * efi_efi_get_variable() - retrieve value of a UEFI variable
  *
@@ -138,3 +165,158 @@
 
 	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(L"SecureBoot", &efi_global_variable_guid,
+				   attributes_ro, sizeof(secure_boot),
+				   &secure_boot, false);
+	if (ret != EFI_SUCCESS)
+		goto err;
+
+	ret = efi_set_variable_int(L"SetupMode", &efi_global_variable_guid,
+				   attributes_ro, sizeof(setup_mode),
+				   &setup_mode, false);
+	if (ret != EFI_SUCCESS)
+		goto err;
+
+	ret = efi_set_variable_int(L"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(L"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(L"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? */
+	printf("ERROR: Secure state transition failed\n");
+	return ret;
+}
+
+efi_status_t efi_init_secure_state(void)
+{
+	enum efi_secure_mode mode = EFI_MODE_SETUP;
+	u8 efi_vendor_keys = 0;
+	efi_uintn_t size = 0;
+	efi_status_t ret;
+
+	ret = efi_get_variable_int(L"PK", &efi_global_variable_guid,
+				   NULL, &size, NULL, NULL);
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT))
+			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(L"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(u16 *name, const efi_guid_t *guid)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(name_type); ++i) {
+		if (!u16_strcmp(name, name_type[i].name) &&
+		    !guidcmp(guid, name_type[i].guid))
+			return name_type[i].type;
+	}
+	return EFI_AUTH_VAR_NONE;
+}
diff --git a/lib/efi_loader/efi_var_file.c b/lib/efi_loader/efi_var_file.c
index 880c279..6f9d76f 100644
--- a/lib/efi_loader/efi_var_file.c
+++ b/lib/efi_loader/efi_var_file.c
@@ -159,13 +159,7 @@
 #endif
 }
 
-/**
- * efi_var_restore() - restore EFI variables from buffer
- *
- * @buf:	buffer
- * Return:	status code
- */
-static efi_status_t __maybe_unused efi_var_restore(struct efi_var_file *buf)
+efi_status_t efi_var_restore(struct efi_var_file *buf)
 {
 	struct efi_var_entry *var, *last_var;
 	efi_status_t ret;
diff --git a/lib/efi_loader/efi_var_seed.S b/lib/efi_loader/efi_var_seed.S
new file mode 100644
index 0000000..e0a40cf
--- /dev/null
+++ b/lib/efi_loader/efi_var_seed.S
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Predefined UEFI variables
+ *
+ * Copyright (c) 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+
+#include <config.h>
+
+.section .rodata.efi_seed.init,"a"
+.balign 16
+.global __efi_var_file_begin
+__efi_var_file_begin:
+.incbin CONFIG_EFI_VAR_SEED_FILE
+.global __efi_var_file_end
+__efi_var_file_end:
+.balign 16
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index eab5f00..39a8482 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -5,12 +5,15 @@
  * Copyright (c) 2017 Rob Clark
  */
 
+#define LOG_CATEGORY LOGC_EFI
+
 #include <common.h>
 #include <efi_loader.h>
 #include <efi_variable.h>
 #include <env.h>
 #include <env_internal.h>
 #include <hexdump.h>
+#include <log.h>
 #include <malloc.h>
 #include <rtc.h>
 #include <search.h>
@@ -18,166 +21,7 @@
 #include <crypto/pkcs7_parser.h>
 #include <linux/compat.h>
 #include <u-boot/crc.h>
-
-enum efi_secure_mode {
-	EFI_MODE_SETUP,
-	EFI_MODE_USER,
-	EFI_MODE_AUDIT,
-	EFI_MODE_DEPLOYED,
-};
-
-static bool efi_secure_boot;
-static enum efi_secure_mode efi_secure_mode;
-static u8 efi_vendor_keys;
-
-/**
- * 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(L"SecureBoot", &efi_global_variable_guid,
-				   attributes_ro, sizeof(secure_boot),
-				   &secure_boot, false);
-	if (ret != EFI_SUCCESS)
-		goto err;
-
-	ret = efi_set_variable_int(L"SetupMode", &efi_global_variable_guid,
-				   attributes_ro, sizeof(setup_mode),
-				   &setup_mode, false);
-	if (ret != EFI_SUCCESS)
-		goto err;
-
-	ret = efi_set_variable_int(L"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(L"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(L"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? */
-	printf("ERROR: Secure state transition failed\n");
-	return ret;
-}
-
-/**
- * efi_init_secure_state - initialize secure boot state
- *
- * Return:	status code
- */
-static efi_status_t efi_init_secure_state(void)
-{
-	enum efi_secure_mode mode = EFI_MODE_SETUP;
-	efi_uintn_t size = 0;
-	efi_status_t ret;
-
-	ret = efi_get_variable_int(L"PK", &efi_global_variable_guid,
-				   NULL, &size, NULL, NULL);
-	if (ret == EFI_BUFFER_TOO_SMALL) {
-		if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT))
-			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(L"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;
-}
+#include <asm/sections.h>
 
 #ifdef CONFIG_EFI_SECURE_BOOT
 static u8 pkcs7_hdr[] = {
@@ -292,6 +136,7 @@
 	struct efi_time timestamp;
 	struct rtc_time tm;
 	u64 new_time;
+	enum efi_auth_var_type var_type;
 	efi_status_t ret;
 
 	var_sig = NULL;
@@ -368,18 +213,20 @@
 	}
 
 	/* signature database used for authentication */
-	if (u16_strcmp(variable, L"PK") == 0 ||
-	    u16_strcmp(variable, L"KEK") == 0) {
+	var_type = efi_auth_var_get_type(variable, vendor);
+	switch (var_type) {
+	case EFI_AUTH_VAR_PK:
+	case EFI_AUTH_VAR_KEK:
 		/* with PK */
 		truststore = efi_sigstore_parse_sigdb(L"PK");
 		if (!truststore)
 			goto err;
-	} else if (u16_strcmp(variable, L"db") == 0 ||
-		   u16_strcmp(variable, L"dbx") == 0) {
+		break;
+	case EFI_AUTH_VAR_DB:
+	case EFI_AUTH_VAR_DBX:
 		/* with PK and KEK */
 		truststore = efi_sigstore_parse_sigdb(L"KEK");
 		truststore2 = efi_sigstore_parse_sigdb(L"PK");
-
 		if (!truststore) {
 			if (!truststore2)
 				goto err;
@@ -387,7 +234,8 @@
 			truststore = truststore2;
 			truststore2 = NULL;
 		}
-	} else {
+		break;
+	default:
 		/* TODO: support private authenticated variables */
 		goto err;
 	}
@@ -506,6 +354,7 @@
 	efi_uintn_t ret;
 	bool append, delete;
 	u64 time = 0;
+	enum efi_auth_var_type var_type;
 
 	if (!variable_name || !*variable_name || !vendor ||
 	    ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
@@ -519,10 +368,16 @@
 	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 (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) {
+			if (var_type != EFI_AUTH_VAR_NONE)
+				return EFI_WRITE_PROTECTED;
+		}
+
 		/* attributes won't be changed */
 		if (!delete &&
 		    ((ro_check && var->attr != attributes) ||
@@ -540,12 +395,7 @@
 			return EFI_NOT_FOUND;
 	}
 
-	if (((!u16_strcmp(variable_name, L"PK") ||
-	      !u16_strcmp(variable_name, L"KEK")) &&
-		!guidcmp(vendor, &efi_global_variable_guid)) ||
-	    ((!u16_strcmp(variable_name, L"db") ||
-	      !u16_strcmp(variable_name, L"dbx")) &&
-		!guidcmp(vendor, &efi_guid_image_security_database))) {
+	if (var_type != EFI_AUTH_VAR_NONE) {
 		/* authentication is mandatory */
 		if (!(attributes &
 		      EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
@@ -604,7 +454,7 @@
 	if (ret != EFI_SUCCESS)
 		return ret;
 
-	if (!u16_strcmp(variable_name, L"PK"))
+	if (var_type == EFI_AUTH_VAR_PK)
 		ret = efi_init_secure_state();
 	else
 		ret = EFI_SUCCESS;
@@ -747,5 +597,12 @@
 	if (ret != EFI_SUCCESS)
 		return ret;
 
+	if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) {
+		ret = efi_var_restore((struct efi_var_file *)
+				      __efi_var_file_begin);
+		if (ret != EFI_SUCCESS)
+			log_err("Invalid EFI variable seed\n");
+	}
+
 	return efi_var_from_file();
 }
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index ff90aa8..c042348 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -244,10 +244,92 @@
 	return ret;
 }
 
+/*
+ * StMM can store internal attributes and properties for variables, i.e enabling
+ * R/O variables
+ */
+static efi_status_t set_property_int(u16 *variable_name, efi_uintn_t name_size,
+				     const efi_guid_t *vendor,
+				     struct var_check_property *var_property)
+{
+	struct smm_variable_var_check_property *smm_property;
+	efi_uintn_t payload_size;
+	u8 *comm_buf = NULL;
+	efi_status_t ret;
+
+	payload_size = sizeof(*smm_property) + name_size;
+	if (payload_size > max_payload_size) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+	comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
+				SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET,
+				&ret);
+	if (!comm_buf)
+		goto out;
+
+	guidcpy(&smm_property->guid, vendor);
+	smm_property->name_size = name_size;
+	memcpy(&smm_property->property, var_property,
+	       sizeof(smm_property->property));
+	memcpy(smm_property->name, variable_name, name_size);
+
+	ret = mm_communicate(comm_buf, payload_size);
+
+out:
+	free(comm_buf);
+	return ret;
+}
+
+static efi_status_t get_property_int(u16 *variable_name, efi_uintn_t name_size,
+				     const efi_guid_t *vendor,
+				     struct var_check_property *var_property)
+{
+	struct smm_variable_var_check_property *smm_property;
+	efi_uintn_t payload_size;
+	u8 *comm_buf = NULL;
+	efi_status_t ret;
+
+	memset(var_property, 0, sizeof(*var_property));
+	payload_size = sizeof(*smm_property) + name_size;
+	if (payload_size > max_payload_size) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+	comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
+				SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET,
+				&ret);
+	if (!comm_buf)
+		goto out;
+
+	guidcpy(&smm_property->guid, vendor);
+	smm_property->name_size = name_size;
+	memcpy(smm_property->name, variable_name, name_size);
+
+	ret = mm_communicate(comm_buf, payload_size);
+	/*
+	 * Currently only R/O property is supported in StMM.
+	 * Variables that are not set to R/O will not set the property in StMM
+	 * and the call will return EFI_NOT_FOUND. We are setting the
+	 * properties to 0x0 so checking against that is enough for the
+	 * EFI_NOT_FOUND case.
+	 */
+	if (ret == EFI_NOT_FOUND)
+		ret = EFI_SUCCESS;
+	if (ret != EFI_SUCCESS)
+		goto out;
+	memcpy(var_property, &smm_property->property, sizeof(*var_property));
+
+out:
+	free(comm_buf);
+	return ret;
+}
+
 efi_status_t efi_get_variable_int(u16 *variable_name, const efi_guid_t *vendor,
 				  u32 *attributes, efi_uintn_t *data_size,
 				  void *data, u64 *timep)
 {
+	struct var_check_property var_property;
 	struct smm_variable_access *var_acc;
 	efi_uintn_t payload_size;
 	efi_uintn_t name_size;
@@ -299,8 +381,16 @@
 	if (ret != EFI_SUCCESS)
 		goto out;
 
+	ret = get_property_int(variable_name, name_size, vendor, &var_property);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
-	if (attributes)
+	if (attributes) {
 		*attributes = var_acc->attr;
+		if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
+			*attributes |= EFI_VARIABLE_READ_ONLY;
+	}
+
 	if (data)
 		memcpy(data, (u8 *)var_acc->name + var_acc->name_size,
 		       var_acc->data_size);
@@ -387,11 +477,13 @@
 				  u32 attributes, efi_uintn_t data_size,
 				  const void *data, bool ro_check)
 {
+	efi_status_t ret, alt_ret = EFI_SUCCESS;
+	struct var_check_property var_property;
 	struct smm_variable_access *var_acc;
 	efi_uintn_t payload_size;
 	efi_uintn_t name_size;
 	u8 *comm_buf = NULL;
-	efi_status_t ret;
+	bool ro;
 
 	if (!variable_name || variable_name[0] == 0 || !vendor) {
 		ret = EFI_INVALID_PARAMETER;
@@ -401,7 +493,6 @@
 		ret = EFI_INVALID_PARAMETER;
 		goto out;
 	}
-
 	/* Check payload size */
 	name_size = u16_strsize(variable_name);
 	payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size;
@@ -410,12 +501,41 @@
 		goto out;
 	}
 
-	/* Get communication buffer and initialize header */
+	/*
+	 * Allocate the buffer early, before switching to RW (if needed)
+	 * so we won't need to account for any failures in reading/setting
+	 * the properties, if the allocation fails
+	 */
 	comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
 				SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
 	if (!comm_buf)
 		goto out;
 
+	ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
+	attributes &= EFI_VARIABLE_MASK;
+
+	/*
+	 * The API has the ability to override RO flags. If no RO check was
+	 * requested switch the variable to RW for the duration of this call
+	 */
+	ret = get_property_int(variable_name, name_size, vendor,
+			       &var_property);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) {
+		/* Bypass r/o check */
+		if (!ro_check) {
+			var_property.property &= ~VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+			ret = set_property_int(variable_name, name_size, vendor, &var_property);
+			if (ret != EFI_SUCCESS)
+				goto out;
+		} else {
+			ret = EFI_WRITE_PROTECTED;
+			goto out;
+		}
+	}
+
 	/* Fill in contents */
 	guidcpy(&var_acc->guid, vendor);
 	var_acc->data_size = data_size;
@@ -426,10 +546,26 @@
 
 	/* Communicate */
 	ret = mm_communicate(comm_buf, payload_size);
+	if (ret != EFI_SUCCESS)
+		alt_ret = ret;
 
+	if (ro && !(var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)) {
+		var_property.revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+		var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+		var_property.attributes = attributes;
+		var_property.minsize = 1;
+		var_property.maxsize = var_acc->data_size;
+		ret = set_property_int(variable_name, name_size, vendor, &var_property);
+	}
+
+	if (alt_ret != EFI_SUCCESS)
+		goto out;
+
+	if (!u16_strcmp(variable_name, L"PK"))
+		alt_ret = efi_init_secure_state();
 out:
 	free(comm_buf);
-	return ret;
+	return alt_ret == EFI_SUCCESS ? ret : alt_ret;
 }
 
 efi_status_t efi_query_variable_info_int(u32 attributes,
@@ -586,5 +722,9 @@
 			  MM_VARIABLE_COMMUNICATE_SIZE +
 			  max_payload_size;
 
+	ret = efi_init_secure_state();
+	if (ret != EFI_SUCCESS)
+		return ret;
+
 	return EFI_SUCCESS;
 }
diff --git a/test/py/tests/test_efi_loader.py b/test/py/tests/test_efi_loader.py
index 9465c28..7aa422e 100644
--- a/test/py/tests/test_efi_loader.py
+++ b/test/py/tests/test_efi_loader.py
@@ -68,8 +68,8 @@
         u_boot_console.run_command('pci enum')
 
 @pytest.mark.buildconfigspec('cmd_dhcp')
-def test_efi_dhcp(u_boot_console):
-    """Test the dhcp command.
+def test_efi_setup_dhcp(u_boot_console):
+    """Set up the network using DHCP.
 
     The boardenv_* file may be used to enable/disable this test; see the
     comment at the beginning of this file.
@@ -77,7 +77,10 @@
 
     test_dhcp = u_boot_console.config.env.get('env__net_dhcp_server', False)
     if not test_dhcp:
-        pytest.skip('No DHCP server available')
+        env_vars = u_boot_console.config.env.get('env__net_static_env_vars', None)
+        if not env_vars:
+            pytest.skip('No DHCP server available')
+        return None
 
     u_boot_console.run_command('setenv autoload no')
     output = u_boot_console.run_command('dhcp')
@@ -88,7 +91,7 @@
 
 @pytest.mark.buildconfigspec('net')
 def test_efi_setup_static(u_boot_console):
-    """Set up a static IP configuration.
+    """Set up the network using a static IP configuration.
 
     The configuration is provided by the boardenv_* file; see the comment at
     the beginning of this file.
@@ -96,7 +99,10 @@
 
     env_vars = u_boot_console.config.env.get('env__net_static_env_vars', None)
     if not env_vars:
-        pytest.skip('No static network configuration is defined')
+        test_dhcp = u_boot_console.config.env.get('env__net_dhcp_server', False)
+        if not test_dhcp:
+            pytest.skip('No static network configuration is defined')
+        return None
 
     for (var, val) in env_vars:
         u_boot_console.run_command('setenv %s %s' % (var, val))