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

Pull request efi-2024-10-rc2

Documentation:

* Add a description for bootmeth_android

UEFI:

* Provide and use function list_count_nodes()
* Require EFI boot manager for EBBR compliance
* Correct check in efi_load_option_dp_join()
* Adjust config options for capsule updates

SMBIOS:

* Add extended Extended BIOS ROM Size
diff --git a/MAINTAINERS b/MAINTAINERS
index a6e47e8..c283234 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -945,6 +945,7 @@
 T:	git https://source.denx.de/u-boot/custodians/u-boot-dfu.git
 F:	boot/bootmeth_android.c
 F:	boot/bootmeth_android.h
+F:	doc/develop/bootstd/android.rst
 
 BTRFS
 M:	Marek Behún <kabel@kernel.org>
diff --git a/doc/develop/bootstd/android.rst b/doc/develop/bootstd/android.rst
new file mode 100644
index 0000000..41701d5
--- /dev/null
+++ b/doc/develop/bootstd/android.rst
@@ -0,0 +1,39 @@
+.. SPDX-License-Identifier: GPL-2.0+:
+
+Android Bootmeth
+================
+
+Android provides a mechanism for booting its Operating System from eMMC storage,
+described on `source.android.com <https://source.android.com/docs/core/architecture/bootloader>`_.
+
+Android has strong requirements about partitioning layout which are described
+`here <https://source.android.com/docs/core/architecture/partitions>`_.
+Because multiple partitions are required, this bootmeth only operates on whole mmc
+devices which have a valid partition table.
+
+When invoked on a bootdev, this bootmeth searches for the ``misc`` partition in order
+to read the *boot mode*, which can be one of following:
+
+Normal
+  Boot the regular Android Operating System.
+
+Recovery
+  Boot a slimmed down Recovery Operating System. Can be used
+  to factory reset the device or to apply system updates.
+
+Bootloader
+  Stay in U-Boot and wait for fastboot commands from the host.
+
+After the *boot mode* has been determined, this bootmeth will read the *slot suffix*
+from the ``misc`` partition. For details about slots, see
+`the AOSP documentation <https://source.android.com/docs/core/ota/ab#slots>`_.
+
+When both the *boot mode* and the *slot suffix* are known, the bootflow is created.
+
+When the bootflow is booted, the bootmeth reads the kernel, the boot arguments and
+the vendor ramdisk.
+It then boots the kernel using bootm. The relevant devicetree blob is extracted
+from the ``boot`` partition based on the ``adtb_idx`` environment variable.
+
+The compatible string "u-boot,android" is used for the driver. It is present
+if `CONFIG_BOOTMETH_ANDROID` is enabled.
diff --git a/doc/develop/bootstd/index.rst b/doc/develop/bootstd/index.rst
index 9d35b56..4c4e26c 100644
--- a/doc/develop/bootstd/index.rst
+++ b/doc/develop/bootstd/index.rst
@@ -10,6 +10,7 @@
    extlinux
    pxelinux
    qfw
+   android
    cros
    script
    sandbox
diff --git a/doc/develop/bootstd/overview.rst b/doc/develop/bootstd/overview.rst
index ff3cc48..c6f0038 100644
--- a/doc/develop/bootstd/overview.rst
+++ b/doc/develop/bootstd/overview.rst
@@ -429,7 +429,7 @@
 
 Bootmeth drivers are provided for booting from various media:
 
-   - Android bootflow (boot image v4)
+   - :doc:`Android <android>` bootflow (boot image v4)
    - :doc:`ChromiumOS <cros>` ChromiumOS boot from a disk
    - EFI boot using bootefi from disk
    - EFI boot using boot manager
diff --git a/drivers/core/util.c b/drivers/core/util.c
index 108a3bc..fa89348 100644
--- a/drivers/core/util.c
+++ b/drivers/core/util.c
@@ -3,23 +3,13 @@
  * Copyright (c) 2013 Google, Inc
  */
 
+#include <vsprintf.h>
 #include <dm/device.h>
 #include <dm/ofnode.h>
 #include <dm/read.h>
 #include <dm/util.h>
 #include <linux/libfdt.h>
-#include <vsprintf.h>
-
-int list_count_items(struct list_head *head)
-{
-	struct list_head *node;
-	int count = 0;
-
-	list_for_each(node, head)
-		count++;
-
-	return count;
-}
+#include <linux/list.h>
 
 #if CONFIG_IS_ENABLED(OF_REAL)
 int pci_get_devfn(struct udevice *dev)
diff --git a/include/dm/util.h b/include/dm/util.h
index 95c3527..ec518c5 100644
--- a/include/dm/util.h
+++ b/include/dm/util.h
@@ -17,14 +17,6 @@
 struct list_head;
 
 /**
- * list_count_items() - Count number of items in a list
- *
- * @param head:		Head of list
- * Return: number of items, or 0 if empty
- */
-int list_count_items(struct list_head *head);
-
-/**
  * Dump out a tree of all devices starting @uclass
  *
  * @dev_name: udevice name
diff --git a/include/linux/list.h b/include/linux/list.h
index 6910721..0f9d939 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -547,6 +547,21 @@
 	     &pos->member != (head);					\
 	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
 
+/**
+ * list_count_nodes - count nodes in the list
+ * @head:	the head for your list.
+ */
+static inline size_t list_count_nodes(struct list_head *head)
+{
+	struct list_head *pos;
+	size_t count = 0;
+
+	list_for_each(pos, head)
+		count++;
+
+	return count;
+}
+
 /*
  * Double linked lists with a single pointer list head.
  * Mostly useful for hash tables where the two pointer list head is
diff --git a/include/smbios.h b/include/smbios.h
index a4fda9d..00119d7 100644
--- a/include/smbios.h
+++ b/include/smbios.h
@@ -105,6 +105,7 @@
 	u8 bios_minor_release;
 	u8 ec_major_release;
 	u8 ec_minor_release;
+	u16 extended_bios_rom_size;
 	char eos[SMBIOS_STRUCT_EOS_BYTES];
 };
 
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 38e64af..1179c31 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -220,6 +220,7 @@
 config EFI_IGNORE_OSINDICATIONS
 	bool "Ignore OsIndications for CapsuleUpdate on-disk"
 	depends on EFI_CAPSULE_ON_DISK
+	default y if !EFI_RT_VOLATILE_STORE
 	help
 	  There are boards where U-Boot does not support SetVariable at runtime.
 	  Select this option if you want to use the capsule-on-disk feature
@@ -486,6 +487,7 @@
 
 config EFI_EBBR_2_1_CONFORMANCE
 	bool "Add the EBBRv2.1 conformance entry to the ECPT table"
+	depends on BOOTMETH_EFI_BOOTMGR
 	depends on EFI_ECPT
 	depends on EFI_LOADER_HII
 	depends on EFI_RISCV_BOOT_PROTOCOL || !RISCV
diff --git a/lib/efi_loader/efi_fdt.c b/lib/efi_loader/efi_fdt.c
index 4ccf205..c5ecade 100644
--- a/lib/efi_loader/efi_fdt.c
+++ b/lib/efi_loader/efi_fdt.c
@@ -43,6 +43,9 @@
 	case 2:
 		prefix = "/dtb/current";
 		break;
+	case 3:
+		prefix = "/dtbs";
+		break;
 	default:
 		return log_msg_ret("pref", -EINVAL);
 	}
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
index 348612c..65d2116 100644
--- a/lib/efi_loader/efi_helper.c
+++ b/lib/efi_loader/efi_helper.c
@@ -133,7 +133,7 @@
 
 		*dp = efi_dp_concat(tmp_dp, fdt_dp, *dp_size);
 		efi_free_pool(tmp_dp);
-		if (!dp)
+		if (!*dp)
 			return EFI_OUT_OF_RESOURCES;
 		*dp_size += efi_dp_size(fdt_dp) + sizeof(END);
 	}
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index 12cf23f..c6f1dd0 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -127,7 +127,7 @@
  */
 static void efi_mem_sort(void)
 {
-	struct list_head *lhandle;
+	struct efi_mem_list *lmem;
 	struct efi_mem_list *prevmem = NULL;
 	bool merge_again = true;
 
@@ -136,19 +136,18 @@
 	/* Now merge entries that can be merged */
 	while (merge_again) {
 		merge_again = false;
-		list_for_each(lhandle, &efi_mem) {
-			struct efi_mem_list *lmem;
-			struct efi_mem_desc *prev = &prevmem->desc;
+		list_for_each_entry(lmem, &efi_mem, link) {
+			struct efi_mem_desc *prev;
 			struct efi_mem_desc *cur;
 			uint64_t pages;
 
-			lmem = list_entry(lhandle, struct efi_mem_list, link);
 			if (!prevmem) {
 				prevmem = lmem;
 				continue;
 			}
 
 			cur = &lmem->desc;
+			prev = &prevmem->desc;
 
 			if ((desc_get_end(cur) == prev->physical_start) &&
 			    (prev->type == cur->type) &&
@@ -268,7 +267,7 @@
 					  int memory_type,
 					  bool overlap_only_ram)
 {
-	struct list_head *lhandle;
+	struct efi_mem_list *lmem;
 	struct efi_mem_list *newlist;
 	bool carve_again;
 	uint64_t carved_pages = 0;
@@ -308,11 +307,9 @@
 	/* Add our new map */
 	do {
 		carve_again = false;
-		list_for_each(lhandle, &efi_mem) {
-			struct efi_mem_list *lmem;
+		list_for_each_entry(lmem, &efi_mem, link) {
 			s64 r;
 
-			lmem = list_entry(lhandle, struct efi_mem_list, link);
 			r = efi_mem_carve_out(lmem, &newlist->desc,
 					      overlap_only_ram);
 			switch (r) {
@@ -444,7 +441,7 @@
  */
 static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr)
 {
-	struct list_head *lhandle;
+	struct efi_mem_list *lmem;
 
 	/*
 	 * Prealign input max address, so we simplify our matching
@@ -452,9 +449,7 @@
 	 */
 	max_addr &= ~EFI_PAGE_MASK;
 
-	list_for_each(lhandle, &efi_mem) {
-		struct efi_mem_list *lmem = list_entry(lhandle,
-			struct efi_mem_list, link);
+	list_for_each_entry(lmem, &efi_mem, link) {
 		struct efi_mem_desc *desc = &lmem->desc;
 		uint64_t desc_len = desc->num_pages << EFI_PAGE_SHIFT;
 		uint64_t desc_end = desc->physical_start + desc_len;
@@ -742,9 +737,9 @@
 				efi_uintn_t *descriptor_size,
 				uint32_t *descriptor_version)
 {
+	size_t map_entries;
 	efi_uintn_t map_size = 0;
-	int map_entries = 0;
-	struct list_head *lhandle;
+	struct efi_mem_list *lmem;
 	efi_uintn_t provided_map_size;
 
 	if (!memory_map_size)
@@ -752,8 +747,7 @@
 
 	provided_map_size = *memory_map_size;
 
-	list_for_each(lhandle, &efi_mem)
-		map_entries++;
+	map_entries = list_count_nodes(&efi_mem);
 
 	map_size = map_entries * sizeof(struct efi_mem_desc);
 
@@ -774,10 +768,7 @@
 	/* Copy list into array */
 	/* Return the list in ascending order */
 	memory_map = &memory_map[map_entries - 1];
-	list_for_each(lhandle, &efi_mem) {
-		struct efi_mem_list *lmem;
-
-		lmem = list_entry(lhandle, struct efi_mem_list, link);
+	list_for_each_entry(lmem, &efi_mem, link) {
 		*memory_map = lmem->desc;
 		memory_map--;
 	}
diff --git a/lib/smbios.c b/lib/smbios.c
index 4126466..7c24ea1 100644
--- a/lib/smbios.c
+++ b/lib/smbios.c
@@ -22,6 +22,7 @@
 #include <cpu.h>
 #include <dm/uclass-internal.h>
 #endif
+#include <linux/sizes.h>
 
 /* Safeguard for checking that U_BOOT_VERSION_NUM macros are compatible with U_BOOT_DMI */
 #if U_BOOT_VERSION_NUM < 2000 || U_BOOT_VERSION_NUM > 2099 || \
@@ -348,7 +349,13 @@
 #endif
 	t->bios_release_date = smbios_add_prop(ctx, NULL, U_BOOT_DMI_DATE);
 #ifdef CONFIG_ROM_SIZE
-	t->bios_rom_size = (CONFIG_ROM_SIZE / 65536) - 1;
+	if (CONFIG_ROM_SIZE < SZ_16M) {
+		t->bios_rom_size = (CONFIG_ROM_SIZE / 65536) - 1;
+	} else {
+		/* CONFIG_ROM_SIZE < 8 GiB */
+		t->bios_rom_size = 0xff;
+		t->extended_bios_rom_size = CONFIG_ROM_SIZE >> 20;
+	}
 #endif
 	t->bios_characteristics = BIOS_CHARACTERISTICS_PCI_SUPPORTED |
 				  BIOS_CHARACTERISTICS_SELECTABLE_BOOT |
diff --git a/test/dm/bus.c b/test/dm/bus.c
index a338c7f..95326f2 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -14,6 +14,7 @@
 #include <dm/test.h>
 #include <dm/uclass-internal.h>
 #include <dm/util.h>
+#include <linux/list.h>
 #include <test/test.h>
 #include <test/ut.h>
 
@@ -27,14 +28,14 @@
 	struct uclass *uc;
 
 	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
-	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
+	ut_asserteq(num_devices, list_count_nodes(&uc->dev_head));
 
 	/* Probe the bus, which should yield 3 more devices */
 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
 	num_devices += 3;
 
 	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
-	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
+	ut_asserteq(num_devices, list_count_nodes(&uc->dev_head));
 
 	ut_assert(!dm_check_devices(uts, num_devices));
 
diff --git a/test/dm/core.c b/test/dm/core.c
index dbad1b3..5bc5e8e 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -16,6 +16,7 @@
 #include <dm/util.h>
 #include <dm/test.h>
 #include <dm/uclass-internal.h>
+#include <linux/list.h>
 #include <test/test.h>
 #include <test/ut.h>
 
@@ -123,15 +124,15 @@
 	 * device with no children.
 	 */
 	ut_assert(uts->root);
-	ut_asserteq(1, list_count_items(gd->uclass_root));
-	ut_asserteq(0, list_count_items(&gd->dm_root->child_head));
+	ut_asserteq(1, list_count_nodes(gd->uclass_root));
+	ut_asserteq(0, list_count_nodes(&gd->dm_root->child_head));
 	ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]);
 
 	ut_assertok(dm_scan_plat(false));
 
 	/* We should have our test class now at least, plus more children */
-	ut_assert(1 < list_count_items(gd->uclass_root));
-	ut_assert(0 < list_count_items(&gd->dm_root->child_head));
+	ut_assert(1 < list_count_nodes(gd->uclass_root));
+	ut_assert(0 < list_count_nodes(&gd->dm_root->child_head));
 
 	/* Our 3 dm_test_infox children should be bound to the test uclass */
 	ut_asserteq(3, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 18c89ee..31effff 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -19,6 +19,7 @@
 #include <dm/util.h>
 #include <dm/of_access.h>
 #include <linux/ioport.h>
+#include <linux/list.h>
 #include <test/test.h>
 #include <test/ut.h>
 
@@ -162,7 +163,7 @@
 	ut_assert(!ret);
 
 	/* These are num_devices compatible root-level device tree nodes */
-	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
+	ut_asserteq(num_devices, list_count_nodes(&uc->dev_head));
 
 	/* Each should have platform data but no private data */
 	for (i = 0; i < num_devices; i++) {
@@ -217,7 +218,7 @@
 	 * one with "bootph-all" property (a-test node), and the other
 	 * one whose driver marked with DM_FLAG_PRE_RELOC flag (h-test node).
 	 */
-	ut_asserteq(2, list_count_items(&uc->dev_head));
+	ut_asserteq(2, list_count_nodes(&uc->dev_head));
 
 	return 0;
 }