diff mbox series

[v7,03/11] bootstd: Support booting EFI where multiple options exist

Message ID 20230402140231.v7.3.Ifa423a8f295b3c11e50821222b0db1e869d0c051@changeid
State Superseded
Delegated to: Tom Rini
Headers show
Series [v7,01/11] bootstd: Tweak bootflow logic for device tree | expand

Commit Message

Simon Glass April 2, 2023, 2:02 a.m. UTC
The current EFI implementation has a strange quirk where it watches
loaded files and uses the last-loaded file to determine the device that
is being booted from.

This is confusing with bootstd, where multiple options may exist. Even
loading a device tree will cause it to go wrong. There is no API for
passing this information, since the only entry into booting an EFI image
is the 'bootefi' command.

To work around this, call efi_set_bootdev() for EFI images, if possible,
just before booting.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v5)

Changes in v5:
- Add new patch to support booting EFI where multiple options exist

 boot/bootmeth_efi.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c
index d7e042cf01ee..d8bc7fafd127 100644
--- a/boot/bootmeth_efi.c
+++ b/boot/bootmeth_efi.c
@@ -94,7 +94,7 @@  static int get_efi_pxe_vci(char *str, int max_len)
 	return 0;
 }
 
-static int efiload_read_file(struct blk_desc *desc, struct bootflow *bflow)
+static void set_efi_bootdev(struct blk_desc *desc, struct bootflow *bflow)
 {
 	const struct udevice *media_dev;
 	int size = bflow->size;
@@ -102,11 +102,6 @@  static int efiload_read_file(struct blk_desc *desc, struct bootflow *bflow)
 	char devnum_str[9];
 	char dirname[200];
 	char *last_slash;
-	int ret;
-
-	ret = bootmeth_alloc_file(bflow, 0x2000000, 0x10000);
-	if (ret)
-		return log_msg_ret("read", ret);
 
 	/*
 	 * This is a horrible hack to tell EFI about this boot device. Once we
@@ -117,7 +112,8 @@  static int efiload_read_file(struct blk_desc *desc, struct bootflow *bflow)
 	 * this can go away.
 	 */
 	media_dev = dev_get_parent(bflow->dev);
-	snprintf(devnum_str, sizeof(devnum_str), "%x", dev_seq(media_dev));
+	snprintf(devnum_str, sizeof(devnum_str), "%x:%x", dev_seq(media_dev),
+		 bflow->part);
 
 	strlcpy(dirname, bflow->fname, sizeof(dirname));
 	last_slash = strrchr(dirname, '/');
@@ -130,6 +126,15 @@  static int efiload_read_file(struct blk_desc *desc, struct bootflow *bflow)
 	dev_name = device_get_uclass_id(media_dev) == UCLASS_MASS_STORAGE ?
 		 "usb" : dev_get_uclass_name(media_dev);
 	efi_set_bootdev(dev_name, devnum_str, bflow->fname, bflow->buf, size);
+}
+
+static int efiload_read_file(struct blk_desc *desc, struct bootflow *bflow)
+{
+	int ret;
+
+	ret = bootmeth_alloc_file(bflow, 0x2000000, 0x10000);
+	if (ret)
+		return log_msg_ret("read", ret);
 
 	return 0;
 }
@@ -373,6 +378,13 @@  int distro_efi_boot(struct udevice *dev, struct bootflow *bflow)
 
 	/* A non-zero buffer indicates the kernel is there */
 	if (bflow->buf) {
+		/* Set the EFI bootdev again, since reading an FDT loses it! */
+		if (bflow->blk) {
+			struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
+
+			set_efi_bootdev(desc, bflow);
+		}
+
 		kernel = (ulong)map_to_sysmem(bflow->buf);
 
 		/*