From 6a8c2f9781cede2a7cb2b95ee6310cd53b1c20e2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 26 Jul 2023 21:01:23 -0600 Subject: [PATCH] bootstd: Avoid allocating memory for the EFI file MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The current bootflow-iteration algorithm reads the bootflow file into an allocated memory buffer so it can be examined. This works well in most cases. However, while the common case is that the first bootflow is immediately booted, it is also possible just to scan for available bootflows, perhaps selecting one to boot later. Even with the common case, EFI bootflows can be quite large. It doesn't make sense to read it into an allocated buffer when we have kernel_addr_t providing a suitable address for it. Even if we do have plenty of malloc() space available, it is a violation of U-Boot's lazy-init principle to read the bootflow before it is needed. So overall it seems better to make a change. Adjust the logic to read just the size of the EFI file at first. Later, when the bootflow is booted, read the rest of the file into the designated kernel buffer. Signed-off-by: Simon Glass Reported-by: Da Xue Reported-by: Vincent Stehlé --- boot/bootmeth_efi.c | 50 ++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index e88e171ccc..bceec0d12e 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -143,13 +143,24 @@ static void set_efi_bootdev(struct blk_desc *desc, struct bootflow *bflow) efi_set_bootdev(dev_name, devnum_str, bflow->fname, bflow->buf, size); } -static int efiload_read_file(struct blk_desc *desc, struct bootflow *bflow) +static int efiload_read_file(struct bootflow *bflow, ulong addr) { + struct blk_desc *desc = NULL; + loff_t bytes_read; int ret; - ret = bootmeth_alloc_file(bflow, 0x2000000, 0x10000); + if (bflow->blk) + desc = dev_get_uclass_plat(bflow->blk); + ret = bootmeth_setup_fs(bflow, desc); + if (ret) + return log_msg_ret("set", ret); + + ret = fs_read(bflow->fname, addr, 0, bflow->size, &bytes_read); if (ret) return log_msg_ret("read", ret); + bflow->buf = map_sysmem(addr, bflow->size); + + set_efi_bootdev(desc, bflow); return 0; } @@ -223,7 +234,18 @@ static int distro_efi_get_fdt_name(char *fname, int size, int seq) return 0; } -static int distro_efi_read_bootflow_file(struct udevice *dev, +/* + * distro_efi_try_bootflow_files() - Check that files are present + * + * This reads any FDT file and checks whether the bootflow file is present, for + * later reading. We avoid reading the bootflow now, since it is likely large, + * it may take a long time and we want to avoid needing to allocate memory for + * it + * + * @dev: bootmeth device to use + * @bflow: bootflow to update + */ +static int distro_efi_try_bootflow_files(struct udevice *dev, struct bootflow *bflow) { struct blk_desc *desc = NULL; @@ -247,9 +269,8 @@ static int distro_efi_read_bootflow_file(struct udevice *dev, if (ret) return log_msg_ret("try", ret); - ret = efiload_read_file(desc, bflow); - if (ret) - return log_msg_ret("read", ret); + /* Since we can access the file, let's call it ready */ + bflow->state = BOOTFLOWST_READY; fdt_addr = env_get_hex("fdt_addr_r", 0); @@ -376,7 +397,7 @@ static int distro_efi_read_bootflow(struct udevice *dev, struct bootflow *bflow) if (ret) return log_msg_ret("net", ret); } else { - ret = distro_efi_read_bootflow_file(dev, bflow); + ret = distro_efi_try_bootflow_files(dev, bflow); if (ret) return log_msg_ret("blk", ret); } @@ -388,17 +409,13 @@ int distro_efi_boot(struct udevice *dev, struct bootflow *bflow) { ulong kernel, fdt; char cmd[50]; + int ret; - /* A non-zero buffer indicates the kernel is there */ + kernel = env_get_hex("kernel_addr_r", 0); if (!bootmeth_uses_network(bflow)) { - /* 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); + ret = efiload_read_file(bflow, kernel); + if (ret) + return log_msg_ret("read", ret); /* * use the provided device tree if available, else fall back to @@ -417,7 +434,6 @@ int distro_efi_boot(struct udevice *dev, struct bootflow *bflow) * But this is the same behaviour for distro boot, so it can be * fixed here. */ - kernel = env_get_hex("kernel_addr_r", 0); fdt = env_get_hex("fdt_addr_r", 0); } -- 2.39.5