Merge tag 'efi-2024-10-rc1-2' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request efi-2024-10-rc1-2

Documentation:

* use current versions of certifi and urllib3 for building documentation
* add bootelf command documentation
* correct the description of the Goldfish RTC driver
* correct heading level of itest examples

UEFI:

* print device-tree in dtbdump.efi
* consider CONFIG_EFI_IGNORE_OSINDICATIONS in TestEfiCapsuleFirmwareRaw
* correct cmd_capsule_esl_gen invocation in scripts/Makefile.lib
* use capsule CRT instead of ESL file when building capsules

Others:

* let ENV_IS_IN_EXT4 enable SYS_MMC_ENV_DEV
* check if CONFIG_SYS_MMC_ENV_DEV is defined in mmc_get_env_dev
diff --git a/board/sandbox/capsule_pub_esl_good.esl b/board/sandbox/capsule_pub_esl_good.esl
deleted file mode 100644
index f8cc272..0000000
--- a/board/sandbox/capsule_pub_esl_good.esl
+++ /dev/null
Binary files differ
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index ed86f1d..b9d47f5 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -515,7 +515,7 @@
 	return 0;
 }
 
-#if CONFIG_MMC_SUNXI_SLOT_EXTRA != -1
+#ifdef CONFIG_SYS_MMC_ENV_DEV
 int mmc_get_env_dev(void)
 {
 	switch (sunxi_get_boot_device()) {
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index da8c197..e2db66d 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -353,7 +353,7 @@
 CONFIG_EFI_CAPSULE_ON_DISK=y
 CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
 CONFIG_EFI_CAPSULE_AUTHENTICATE=y
-CONFIG_EFI_CAPSULE_ESL_FILE="board/sandbox/capsule_pub_esl_good.esl"
+CONFIG_EFI_CAPSULE_CRT_FILE="board/sandbox/capsule_pub_key_good.crt"
 CONFIG_EFI_SECURE_BOOT=y
 CONFIG_TEST_FDTDEC=y
 CONFIG_UNIT_TEST=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index 6bf8874..049a606 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -227,7 +227,7 @@
 CONFIG_EFI_CAPSULE_ON_DISK=y
 CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y
 CONFIG_EFI_CAPSULE_AUTHENTICATE=y
-CONFIG_EFI_CAPSULE_ESL_FILE="board/sandbox/capsule_pub_esl_good.esl"
+CONFIG_EFI_CAPSULE_CRT_FILE="board/sandbox/capsule_pub_key_good.crt"
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst
index 88596f3..d450b12 100644
--- a/doc/develop/uefi/uefi.rst
+++ b/doc/develop/uefi/uefi.rst
@@ -580,10 +580,10 @@
     }
 
 You can perform step-4 through the Kconfig symbol
-CONFIG_EFI_CAPSULE_ESL_FILE. This symbol points to the esl file
-generated in step-2. Once the symbol has been populated with the path
-to the esl file, it will automatically get embedded into the
-platform's dtb as part of U-Boot build.
+CONFIG_EFI_CAPSULE_CRT_FILE. This symbol points to the signing key
+generated in step-2. As part of U-Boot build, the ESL certificate file will
+be generated from the signing key and automatically get embedded into the
+platform's dtb.
 
 Anti-rollback Protection
 ************************
diff --git a/doc/sphinx/requirements.txt b/doc/sphinx/requirements.txt
index 306b05a..40dde59 100644
--- a/doc/sphinx/requirements.txt
+++ b/doc/sphinx/requirements.txt
@@ -1,6 +1,6 @@
 alabaster==0.7.16
 Babel==2.15.0
-certifi==2024.6.2
+certifi==2024.7.4
 charset-normalizer==3.3.2
 docutils==0.20.1
 idna==3.7
@@ -22,4 +22,4 @@
 sphinxcontrib-jsmath==1.0.1
 sphinxcontrib-qthelp==1.0.7
 sphinxcontrib-serializinghtml==1.1.10
-urllib3==2.2.1
+urllib3==2.2.2
diff --git a/doc/usage/cmd/bootelf.rst b/doc/usage/cmd/bootelf.rst
new file mode 100644
index 0000000..705524c
--- /dev/null
+++ b/doc/usage/cmd/bootelf.rst
@@ -0,0 +1,61 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+.. Copyright 2024, Maxim Moskalets <maximmosk4@gmail.com>
+
+.. index::
+   single: bootelf (command)
+
+bootelf command
+===============
+
+Synopsis
+--------
+
+::
+
+    bootelf [-p|-s] [-d <fdt_addr>] [<image_addr> [<arg>]...]
+
+Description
+-----------
+
+The *bootelf* command is used to launch a ELF binary at *image_addr*. If
+*image_addr* is not specified, the bootelf command will try to find image in
+*image_load_addr* variable (*CONFIG\_SYS\_LOAD\_ADDR* by default).
+
+Args after *image_addr* will be passed to application in common *argc*, *argv*
+format.
+
+A command sequence to run a ELF image using FDT might look like
+
+::
+
+    load mmc 0:1 ${loadaddr} /kernel.elf
+    load mmc 0:1 ${fdt_addr_r} /soc-board.dtb
+    bootelf -d ${fdt_addr_r} ${loadaddr} ${loadaddr}
+
+image_addr
+    Address of the ELF binary.
+
+fdt_addr
+    Address of the device-tree. This argument in only needed if bootable
+    application uses FDT that requires additional setup (like /memory node).
+
+arg
+    Any text arguments for bootable application. This is usually the address
+    of the device-tree.
+
+Flags:
+
+-p
+    Load ELF image via program headers.
+
+-s
+    Load ELF image via section headers.
+
+-d
+    Setup FDT by address.
+
+Configuration
+-------------
+
+The bootelf command is only available if CONFIG_CMD_ELF=y. FDT setup by flag -d
+need CONFIG_CMD_ELF_FDT_SETUP=y.
diff --git a/doc/usage/cmd/itest.rst b/doc/usage/cmd/itest.rst
index 9c307fb..adcad05 100644
--- a/doc/usage/cmd/itest.rst
+++ b/doc/usage/cmd/itest.rst
@@ -58,7 +58,7 @@
     ======== ======================
 
 Examples
-========
+--------
 
 The itest command sets the result variable $? to true (0) or false (1):
 
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 2f211f7..49b354e 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -33,6 +33,7 @@
    cmd/bootd
    cmd/bootdev
    cmd/bootefi
+   cmd/bootelf
    cmd/bootflow
    cmd/booti
    cmd/bootm
diff --git a/drivers/rtc/goldfish_rtc.c b/drivers/rtc/goldfish_rtc.c
index 3231eb0..e63a276 100644
--- a/drivers/rtc/goldfish_rtc.c
+++ b/drivers/rtc/goldfish_rtc.c
@@ -2,7 +2,9 @@
 /*
  * Copyright 2023, Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
  *
- * This driver emulates a real time clock based on timer ticks.
+ * This driver supports the Google Goldfish virtual platform RTC device.
+ * The device is provided by the RISC-V virt machine in QEMU. It exposes
+ * a 64-bit nanosecond timer via two memory-mapped 32-bit registers.
  */
 
 #include <div64.h>
diff --git a/env/Kconfig b/env/Kconfig
index 451bab4..031cf58 100644
--- a/env/Kconfig
+++ b/env/Kconfig
@@ -655,7 +655,7 @@
 
 config SYS_MMC_ENV_DEV
 	int "mmc device number"
-	depends on ENV_IS_IN_MMC || ENV_IS_IN_FAT || \
+	depends on ENV_IS_IN_MMC || ENV_IS_IN_FAT || ENV_IS_IN_EXT4 || \
 		CMD_MVEBU_BUBT || FMAN_ENET || QE || PHY_CORTINA
 	default 0
 	help
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index ee71f41..2fb24d7 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -298,13 +298,15 @@
 	  Select the max capsule index value used for capsule report
 	  variables. This value is used to create CapsuleMax variable.
 
-config EFI_CAPSULE_ESL_FILE
-	string "Path to the EFI Signature List File"
+config EFI_CAPSULE_CRT_FILE
+	string "Path to the EFI capsule public key certificate"
 	depends on EFI_CAPSULE_AUTHENTICATE
 	help
-	  Provides the path to the EFI Signature List file which will
-	  be embedded in the platform's device tree and used for
-	  capsule authentication at the time of capsule update.
+	  Provides the path to the EFI capsule public key certificate that
+	  corresponds to the capsule signing key. This certificate will be used
+	  to generate the EFI capsule ESL (signature list file) that gets
+	  embedded in the platform's device tree and used for capsule
+	  authentication at the time of capsule update.
 
 config EFI_DEVICE_PATH_TO_TEXT
 	bool "Device path to text protocol"
diff --git a/lib/efi_loader/dtbdump.c b/lib/efi_loader/dtbdump.c
index 5f39cf2..9f1d8fb 100644
--- a/lib/efi_loader/dtbdump.c
+++ b/lib/efi_loader/dtbdump.c
@@ -41,6 +41,53 @@
 }
 
 /**
+ * print_char() - print character
+ *
+ * 0x00 is replaced by '", "'.
+ *
+ * @c:	- character
+ */
+static void print_char(unsigned char c)
+{
+	u16 out[2] = u"?";
+
+	if (!c) {
+		print(u"\", \"");
+		return;
+	}
+
+	if (c > 0x1f && c < 0x80)
+		out[0] = c;
+
+	print(out);
+}
+
+/**
+ * print_hex_digit() - print hexadecimal digit
+ *
+ * @digit:	digit to print
+ */
+static void print_hex_digit(unsigned char digit)
+{
+	if (digit < 10)
+		digit += '0';
+	else
+		digit += 'a' - 10;
+	print_char(digit);
+}
+
+/**
+ * printx() - print hexadecimal byte
+ *
+ * @val:	value to print
+ */
+static void printx(unsigned char val)
+{
+	print_hex_digit(val >> 4);
+	print_hex_digit(val & 0xf);
+}
+
+/**
  * error() - print error string
  *
  * @string:	error text
@@ -227,6 +274,7 @@
  */
 void do_help(void)
 {
+	error(u"dump       - print device-tree\r\n");
 	error(u"load <dtb> - load device-tree from file\r\n");
 	error(u"save <dtb> - save device-tree to file\r\n");
 	error(u"exit       - exit the shell\r\n");
@@ -490,6 +538,217 @@
 }
 
 /**
+ * indent() - print a number of tabstops
+ *
+ * @level:	indentation level
+ */
+static void indent(u32 level)
+{
+	for (; level; --level)
+		print(u"\t");
+}
+
+/**
+ * is_string_value() - determine if property is a string
+ *
+ * If a property is a string, an x-string, or a u32 cannot be deducted
+ * from the device-tree. Therefore a heuristic is used.
+ *
+ * @str:	pointer to device-tree property
+ * @len:	length of the device-tree property
+ * Return:	1 for string, 0 otherwise
+ */
+static int is_string_value(const unsigned char *str, u32 len)
+{
+	int nonzero_flag = 0;
+
+	/* Zero length or not ending with 0x00 */
+	if (!len || str[len - 1])
+		return 0;
+
+	for (u32 i = 0; i < len; ++i) {
+		if (!str[i]) {
+			/* Zero length string or two consecutive 0x00 */
+			if (!nonzero_flag)
+				return 0;
+
+			nonzero_flag = 0;
+
+			continue;
+		}
+		/* Non-printable */
+		if (str[i] < 0x20 || str[i] >= 0x80)
+			return 0;
+
+		nonzero_flag = 1;
+	}
+
+	return 1;
+}
+
+/**
+ * print_property() - print device-tree property
+ *
+ * If a property is a string, an x-string, or a u32 cannot be deducted
+ * from the device-tree. Therefore a heuristic is used.
+ *
+ * @str:	property value
+ * @len:	length of property value
+ */
+static void print_property(const unsigned char *val, u32 len)
+{
+	if (is_string_value(val, len)) {
+		/* string */
+		print(u"\"");
+		for (int i = 0; i < len - 1; ++i)
+			print_char(val[i]);
+		print(u"\"");
+	} else if (len & 0x3) {
+		/* byte string */
+		print(u"[");
+		for (int i = 0; i < len; ++i) {
+			if (i)
+				print(u" ");
+			printx(val[i]);
+		}
+		print(u"]\"");
+	} else {
+		/* cell list */
+		print(u"<");
+		for (u32 i = 0; i < len; ++i) {
+			if ((i & 0x3) == 0) {
+				if (i > 0)
+					print(u" ");
+				print(u"0x");
+			}
+			printx(val[i]);
+		}
+		print(u">");
+	}
+}
+
+/**
+ * print_mem_res_block() - print memory reservation block
+ *
+ * @rsvblk:	memory reservation block
+ */
+static void print_mem_res_block(const struct fdt_reserve_entry *rsvblk)
+{
+	for (; rsvblk->address || rsvblk->size; ++rsvblk) {
+		const unsigned char *val;
+
+		print(u"/memreserve/ 0x");
+		val = (const unsigned char *)&rsvblk->address;
+		for (u32 i = 0; i < sizeof(u64); ++i)
+			printx(val[i]);
+		print(u" 0x");
+		val = (const unsigned char *)&rsvblk->size;
+		for (u32 i = 0; i < sizeof(u64); ++i)
+			printx(val[i]);
+		print(u";\r\n");
+	}
+}
+
+/**
+ * do_dump() - print device-tree
+ */
+static efi_status_t do_dump(void)
+{
+	const unsigned char *fdt;
+	struct fdt_header *header;
+	const u32 *end;
+	const u32 *pos;
+	const char *strings;
+	u32 level = 0;
+
+	fdt = get_dtb(systable);
+	if (!fdt) {
+		error(u"DTB not found\r\n");
+		return EFI_NOT_FOUND;
+	}
+
+	header = (struct fdt_header *)fdt;
+	if (f2h(header->magic) != FDT_MAGIC) {
+		error(u"Wrong device tree magic\r\n");
+		error(u"Not a device-tree\r\n");
+		return EFI_LOAD_ERROR;
+	}
+
+	pos = (u32 *)(fdt + f2h(header->off_dt_struct));
+	end = &pos[f2h(header->totalsize) >> 2];
+	strings = fdt + f2h(header->off_dt_strings);
+
+	print(u"/dts-v1/;\r\n");
+
+	print_mem_res_block((const struct fdt_reserve_entry *)
+			    (fdt + f2h(header->off_mem_rsvmap)));
+
+	print(u"/");
+	for (; pos < end;) {
+		switch (f2h(pos[0])) {
+		case FDT_BEGIN_NODE: {
+			const char *c = (char *)&pos[1];
+			size_t i;
+
+			indent(level);
+			for (i = 0; c[i]; ++i)
+				print_char(c[i]);
+			print(u" {\n\r");
+
+			++level;
+			pos = &pos[2 + (i >> 2)];
+			break;
+		}
+		case FDT_PROP: {
+			struct fdt_property *prop = (struct fdt_property *)pos;
+			const unsigned char *label = &strings[f2h(prop->nameoff)];
+			u32 len = f2h(prop->len);
+			const unsigned char *str = (unsigned char *)&pos[3];
+
+			indent(level);
+			for (int i = 0; label[i]; ++i)
+				print_char(label[i]);
+
+			if (len) {
+				print(u" = ");
+				print_property(str, len);
+			}
+			print(u";\r\n");
+
+			pos = &pos[3 + ((f2h(prop->len) + 3) >> 2)];
+			break;
+		}
+		case FDT_NOP:
+			++pos;
+			break;
+		case FDT_END_NODE:
+			if (!level) {
+				error(u"Extraneous end node\r\n");
+				return EFI_LOAD_ERROR;
+			}
+
+			--level;
+			indent(level);
+			print(u"};\n\r");
+			++pos;
+			break;
+		case FDT_END:
+			if (level) {
+				error(u"Missing end node\r\n");
+				return EFI_LOAD_ERROR;
+			}
+			return EFI_SUCCESS;
+		default:
+			error(u"Invalid device tree token\r\n");
+			return EFI_LOAD_ERROR;
+		}
+	}
+	error(u"Overrun\r\n");
+
+	return EFI_LOAD_ERROR;
+}
+
+/**
  * efi_main() - entry point of the EFI application.
  *
  * @handle:	handle of the loaded image
@@ -524,6 +783,8 @@
 		pos = skip_whitespace(command);
 		if (starts_with(pos, u"exit"))
 			break;
+		else if (starts_with(pos, u"dump"))
+			do_dump();
 		else if (starts_with(pos, u"load "))
 			do_load(pos + 5);
 		else if (starts_with(pos, u"save "))
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 3e68d5a..f66a65d 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -342,21 +342,27 @@
 		; \
 	sed "s:$(pre-tmp):$(<):" $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
 
+capsule_esl_input_file=$(srctree)/lib/efi_loader/capsule_esl.dtsi.in
+capsule_crt_file=$(subst $(quote),,$(CONFIG_EFI_CAPSULE_CRT_FILE))
+capsule_esl_dtsi=.capsule_esl.dtsi
+
 quiet_cmd_capsule_esl_gen = CAPSULE_ESL_GEN $@
-cmd_capsule_esl_gen = \
-	$(shell sed "s:ESL_BIN_FILE:$(capsule_esl_path):" $(capsule_esl_input_file) > $@)
+cmd_capsule_esl_gen = cert-to-efi-sig-list $< $@
 
-$(obj)/.capsule_esl.dtsi: FORCE
-ifeq ($(CONFIG_EFI_CAPSULE_ESL_FILE),"")
-	$(error "CONFIG_EFI_CAPSULE_ESL_FILE is empty, EFI capsule authentication \
+$(obj)/capsule_esl_file: $(capsule_crt_file) FORCE
+ifeq ($(CONFIG_EFI_CAPSULE_CRT_FILE),"")
+	$(error "CONFIG_EFI_CAPSULE_CRT_FILE is empty, EFI capsule authentication \
 	public key must be specified when CONFIG_EFI_CAPSULE_AUTHENTICATE is enabled")
 else
-	$(call cmd_capsule_esl_gen)
+	$(call cmd,capsule_esl_gen)
 endif
 
-capsule_esl_input_file=$(srctree)/lib/efi_loader/capsule_esl.dtsi.in
-capsule_esl_dtsi = .capsule_esl.dtsi
-capsule_esl_path=$(abspath $(srctree)/$(subst $(quote),,$(CONFIG_EFI_CAPSULE_ESL_FILE)))
+quiet_cmd_capsule_dtsi_gen = CAPSULE_DTSI_GEN $@
+cmd_capsule_dtsi_gen = \
+	$(shell sed "s:ESL_BIN_FILE:$(abspath $<):" $(capsule_esl_input_file) > $@)
+
+$(obj)/$(capsule_esl_dtsi): $(obj)/capsule_esl_file FORCE
+	$(call cmd,capsule_dtsi_gen)
 
 dtsi_include_list_deps := $(addprefix $(u_boot_dtsi_loc),$(subst $(quote),,$(dtsi_include_list)))
 
diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py
index a5b5c8a..f3a2dff 100644
--- a/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py
+++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_raw.py
@@ -76,7 +76,7 @@
             self, u_boot_config, u_boot_console, efi_capsule_data):
         """ Test Case 2
         Update U-Boot and U-Boot environment on SPI Flash but with OsIndications unset
-        No update should happen
+        No update should happen unless CONFIG_EFI_IGNORE_OSINDICATIONS is set
         0x100000-0x150000: U-Boot binary (but dummy)
         0x150000-0x200000: U-Boot environment (but dummy)
         """
@@ -91,16 +91,27 @@
         # reboot
         u_boot_console.restart_uboot()
 
+        ignore_os_indications = u_boot_config.buildconfig.get(
+            'config_efi_ignore_osindications')
+        need_reboot = True if ignore_os_indications else False
+
+        capsule_auth = u_boot_config.buildconfig.get(
+            'config_efi_capsule_authenticate')
+
         capsule_early = u_boot_config.buildconfig.get(
             'config_efi_capsule_on_disk_early')
         with u_boot_console.log.section('Test Case 2-b, after reboot'):
             if not capsule_early:
-                exec_manual_update(u_boot_console, disk_img, capsule_files, False)
+                exec_manual_update(u_boot_console, disk_img, capsule_files, need_reboot)
 
-            check_file_exist(u_boot_console, disk_img, capsule_files)
+            if not ignore_os_indications:
+                check_file_exist(u_boot_console, disk_img, capsule_files)
+
+            expected = 'u-boot:New' if (ignore_os_indications and not capsule_auth) else 'u-boot:Old'
+            verify_content(u_boot_console, '100000', expected)
 
-            verify_content(u_boot_console, '100000', 'u-boot:Old')
-            verify_content(u_boot_console, '150000', 'u-boot-env:Old')
+            expected = 'u-boot-env:New' if (ignore_os_indications and not capsule_auth) else 'u-boot-env:Old'
+            verify_content(u_boot_console, '150000', expected)
 
     def test_efi_capsule_fw3(
             self, u_boot_config, u_boot_console, efi_capsule_data):