Message ID | 20230927093631.1595494-5-masahisa.kojima@linaro.org |
---|---|
State | New |
Headers | show |
Series | Add EFI HTTP boot support | expand |
Hi Kojima-san, [...] > + > +/** > + * try_load_default_file() - try to load the default file > + * > + * Search the device having EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, > + * then try to load with the default boot file(e.g. EFI/BOOT/BOOTAA64.EFI). > + * > + * @dev pointer to the UCLASS_BLK or UCLASS_PARTITION udevice > + * @image_handle: pointer to handle for newly installed image > + * Return: status code > + */ > +static efi_status_t try_load_default_file(struct udevice *dev, > + efi_handle_t *image_handle) > +{ > + efi_status_t ret; > + efi_handle_t handle; > + struct efi_handler *handler; > + struct efi_device_path *file_path; > + struct efi_device_path *device_path; > + > + if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle)) { > + log_warning("DM_TAG_EFI not found\n"); > + return EFI_INVALID_PARAMETER; > + } > + > + ret = efi_search_protocol(handle, > + &efi_simple_file_system_protocol_guid, &handler); > + if (ret != EFI_SUCCESS) > + return ret; > + > + ret = EFI_CALL(bs->open_protocol(handle, &efi_guid_device_path, > + (void **)&device_path, efi_root, NULL, > + EFI_OPEN_PROTOCOL_GET_PROTOCOL)); > + if (ret != EFI_SUCCESS) > + return ret; > + > + file_path = expand_media_path(device_path); > + ret = EFI_CALL(efi_load_image(true, efi_root, file_path, NULL, 0, > + image_handle)); > + > + efi_free_pool(file_path); > + > + return ret; > +} We've discussed this on v4, but I am replying here, since you sent a v5 in the meantime. What I ideally wanted to do here is - Add the boot option automatically once the disk gets mount (you've already sent a patch for that) - Since the boot option is automatically added we could instead of searching for BOOTAA64.EFI search for matches with a load option of '1234567'. Is there some timing issue that I am missing which doesnt allow us to do that ? [...] Cheers /Ilias
Hi Ilias, On Fri, 29 Sept 2023 at 20:48, Ilias Apalodimas <ilias.apalodimas@linaro.org> wrote: > > Hi Kojima-san, > > > [...] > > > + > > +/** > > + * try_load_default_file() - try to load the default file > > + * > > + * Search the device having EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, > > + * then try to load with the default boot file(e.g. EFI/BOOT/BOOTAA64.EFI). > > + * > > + * @dev pointer to the UCLASS_BLK or UCLASS_PARTITION udevice > > + * @image_handle: pointer to handle for newly installed image > > + * Return: status code > > + */ > > +static efi_status_t try_load_default_file(struct udevice *dev, > > + efi_handle_t *image_handle) > > +{ > > + efi_status_t ret; > > + efi_handle_t handle; > > + struct efi_handler *handler; > > + struct efi_device_path *file_path; > > + struct efi_device_path *device_path; > > + > > + if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle)) { > > + log_warning("DM_TAG_EFI not found\n"); > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + ret = efi_search_protocol(handle, > > + &efi_simple_file_system_protocol_guid, &handler); > > + if (ret != EFI_SUCCESS) > > + return ret; > > + > > + ret = EFI_CALL(bs->open_protocol(handle, &efi_guid_device_path, > > + (void **)&device_path, efi_root, NULL, > > + EFI_OPEN_PROTOCOL_GET_PROTOCOL)); > > + if (ret != EFI_SUCCESS) > > + return ret; > > + > > + file_path = expand_media_path(device_path); > > + ret = EFI_CALL(efi_load_image(true, efi_root, file_path, NULL, 0, > > + image_handle)); > > + > > + efi_free_pool(file_path); > > + > > + return ret; > > +} > > We've discussed this on v4, but I am replying here, since you sent a v5 in > the meantime. > What I ideally wanted to do here is > - Add the boot option automatically once the disk gets mount (you've > already sent a patch for that) > - Since the boot option is automatically added we could instead of > searching for BOOTAA64.EFI search for matches with a load option of > '1234567'. > Is there some timing issue that I am missing which doesnt allow us to do > that ? Sorry, I probably misunderstood your design. What kind of boot option is automatically added when the disk is detected? Could you share your thoughts about the trigger to search for matches with a load option of '1234567'? Thanks, Masahisa Kojima > > [...] > > Cheers > /Ilias
On Fri, 29 Sept 2023 at 14:35, Masahisa Kojima <masahisa.kojima@linaro.org> wrote: > > Hi Ilias, > > On Fri, 29 Sept 2023 at 20:48, Ilias Apalodimas > <ilias.apalodimas@linaro.org> wrote: > > > > Hi Kojima-san, > > > > > > [...] > > > > > + > > > +/** > > > + * try_load_default_file() - try to load the default file > > > + * > > > + * Search the device having EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, > > > + * then try to load with the default boot file(e.g. EFI/BOOT/BOOTAA64.EFI). > > > + * > > > + * @dev pointer to the UCLASS_BLK or UCLASS_PARTITION udevice > > > + * @image_handle: pointer to handle for newly installed image > > > + * Return: status code > > > + */ > > > +static efi_status_t try_load_default_file(struct udevice *dev, > > > + efi_handle_t *image_handle) > > > +{ > > > + efi_status_t ret; > > > + efi_handle_t handle; > > > + struct efi_handler *handler; > > > + struct efi_device_path *file_path; > > > + struct efi_device_path *device_path; > > > + > > > + if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle)) { > > > + log_warning("DM_TAG_EFI not found\n"); > > > + return EFI_INVALID_PARAMETER; > > > + } > > > + > > > + ret = efi_search_protocol(handle, > > > + &efi_simple_file_system_protocol_guid, &handler); > > > + if (ret != EFI_SUCCESS) > > > + return ret; > > > + > > > + ret = EFI_CALL(bs->open_protocol(handle, &efi_guid_device_path, > > > + (void **)&device_path, efi_root, NULL, > > > + EFI_OPEN_PROTOCOL_GET_PROTOCOL)); > > > + if (ret != EFI_SUCCESS) > > > + return ret; > > > + > > > + file_path = expand_media_path(device_path); > > > + ret = EFI_CALL(efi_load_image(true, efi_root, file_path, NULL, 0, > > > + image_handle)); > > > + > > > + efi_free_pool(file_path); > > > + > > > + return ret; > > > +} > > > > We've discussed this on v4, but I am replying here, since you sent a v5 in > > the meantime. > > What I ideally wanted to do here is > > - Add the boot option automatically once the disk gets mount (you've > > already sent a patch for that) > > - Since the boot option is automatically added we could instead of > > searching for BOOTAA64.EFI search for matches with a load option of > > '1234567'. > > Is there some timing issue that I am missing which doesnt allow us to do > > that ? > > Sorry, I probably misunderstood your design. > What kind of boot option is automatically added when the disk is detected? > Could you share your thoughts about the trigger to search for matches > with a load option of '1234567'? You've recently fixed the CI errors and reported this [0]. Once that gets merged every time a new disk is added, it will be automatically be scanned for BOOTXXX.efi files. If we do find such files, they will be added to the efi bootmgr list of available options. We do mark these with a '1234567' in the optional data. Once that path gets merged, wouldn't it be simpler to just scan for boot options with '1234567' in the load options on the mounted image, instead of rescanning it for BOOTXXX.efi? [0] https://lore.kernel.org/u-boot/20230927010436.1503621-1-masahisa.kojima@linaro.org/ Thanks /Ilias > > Thanks, > Masahisa Kojima > > > > > [...] > > > > Cheers > > /Ilias
diff --git a/include/efi_loader.h b/include/efi_loader.h index 4a29ddaef4..c4207edc91 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -554,6 +554,8 @@ void efi_runtime_detach(void); /* efi_convert_pointer() - convert pointer to virtual address */ efi_status_t EFIAPI efi_convert_pointer(efi_uintn_t debug_disposition, void **address); +/* add reserved memory to memory map */ +void efi_reserve_memory(u64 addr, u64 size, bool nomap); /* Carve out DT reserved memory ranges */ void efi_carve_out_dt_rsv(void *fdt); /* Purge unused kaslr-seed */ diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index a40762c74c..a5030d50c0 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -7,10 +7,14 @@ #define LOG_CATEGORY LOGC_EFI +#include <blk.h> +#include <blkmap.h> #include <common.h> #include <charset.h> +#include <dm.h> #include <log.h> #include <malloc.h> +#include <net.h> #include <efi_default_filename.h> #include <efi_loader.h> #include <efi_variable.h> @@ -168,6 +172,187 @@ out: return ret; } +/** + * mount_image() - mount the image with blkmap + * + * @lo_label u16 label string of load option + * @image_addr: image address + * @image_size image size + * Return: pointer to the UCLASS_BLK udevice, NULL if failed + */ +static struct udevice *mount_image(u16 *lo_label, ulong image_addr, int image_size) +{ + int err; + struct blkmap *bm; + struct udevice *bm_dev; + char *label = NULL, *p; + + label = efi_alloc(utf16_utf8_strlen(lo_label) + 1); + if (!label) + return NULL; + + p = label; + utf16_utf8_strcpy(&p, lo_label); + err = blkmap_create_ramdisk(label, image_addr, image_size, &bm_dev); + if (err) { + efi_free_pool(label); + return NULL; + } + bm = dev_get_plat(bm_dev); + + efi_free_pool(label); + + return bm->blk; +} + +/** + * try_load_default_file() - try to load the default file + * + * Search the device having EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, + * then try to load with the default boot file(e.g. EFI/BOOT/BOOTAA64.EFI). + * + * @dev pointer to the UCLASS_BLK or UCLASS_PARTITION udevice + * @image_handle: pointer to handle for newly installed image + * Return: status code + */ +static efi_status_t try_load_default_file(struct udevice *dev, + efi_handle_t *image_handle) +{ + efi_status_t ret; + efi_handle_t handle; + struct efi_handler *handler; + struct efi_device_path *file_path; + struct efi_device_path *device_path; + + if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle)) { + log_warning("DM_TAG_EFI not found\n"); + return EFI_INVALID_PARAMETER; + } + + ret = efi_search_protocol(handle, + &efi_simple_file_system_protocol_guid, &handler); + if (ret != EFI_SUCCESS) + return ret; + + ret = EFI_CALL(bs->open_protocol(handle, &efi_guid_device_path, + (void **)&device_path, efi_root, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL)); + if (ret != EFI_SUCCESS) + return ret; + + file_path = expand_media_path(device_path); + ret = EFI_CALL(efi_load_image(true, efi_root, file_path, NULL, 0, + image_handle)); + + efi_free_pool(file_path); + + return ret; +} + +/** + * load_default_file_from_blk_dev() - load the default file + * + * @blk pointer to the UCLASS_BLK udevice + * @handle: pointer to handle for newly installed image + * Return: status code + */ +static efi_status_t load_default_file_from_blk_dev(struct udevice *blk, + efi_handle_t *handle) +{ + efi_status_t ret; + struct udevice *partition; + + /* image that has no partition table but a file system */ + ret = try_load_default_file(blk, handle); + if (ret == EFI_SUCCESS) + return ret; + + /* try the partitions */ + device_foreach_child(partition, blk) { + enum uclass_id id; + + id = device_get_uclass_id(partition); + if (id != UCLASS_PARTITION) + continue; + + ret = try_load_default_file(partition, handle); + if (ret == EFI_SUCCESS) + return ret; + } + + return EFI_NOT_FOUND; +} + +/** + * try_load_from_uri_path() - Handle the URI device path + * + * @uridp: uri device path + * @lo_label label of load option + * @handle: pointer to handle for newly installed image + * Return: status code + */ +static efi_status_t try_load_from_uri_path(struct efi_device_path_uri *uridp, + u16 *lo_label, + efi_handle_t *handle) +{ + char *s; + int uri_len; + int image_size; + efi_status_t ret; + ulong image_addr; + + s = env_get("loadaddr"); + if (!s) { + log_err("Error: loadaddr is not set\n"); + return EFI_INVALID_PARAMETER; + } + image_addr = hextoul(s, NULL); + image_size = wget_with_dns(image_addr, uridp->uri); + if (image_size < 0) + return EFI_INVALID_PARAMETER; + + /* + * If the file extension is ".iso" or ".img", mount it and try to load + * the default file. + * If the file is PE-COFF image, load the downloaded file. + */ + uri_len = strlen(uridp->uri); /* todo: directly use uridp->uri */ + if (!strncmp(&uridp->uri[uri_len - 4], ".iso", 4) || + !strncmp(&uridp->uri[uri_len - 4], ".img", 4)) { + struct udevice *blk; + + blk = mount_image(lo_label, image_addr, image_size); + if (!blk) + return EFI_INVALID_PARAMETER; + + ret = load_default_file_from_blk_dev(blk, handle); + if (ret != EFI_SUCCESS) + return ret; + + /* whole ramdisk must be reserved */ + efi_reserve_memory(image_addr, image_size, true); + } else if (efi_check_pe((void *)image_addr, image_size, NULL) == EFI_SUCCESS) { + efi_handle_t mem_handle = NULL; + struct efi_device_path *file_path = NULL; + + file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, + (uintptr_t)image_addr, image_size); + ret = efi_install_multiple_protocol_interfaces( + &mem_handle, &efi_guid_device_path, file_path, NULL); + if (ret != EFI_SUCCESS) + return EFI_INVALID_PARAMETER; + + ret = EFI_CALL(efi_load_image(false, efi_root, file_path, + (void *)image_addr, image_size, + handle)); + } else { + log_err("Error: file type is not supported\n"); + return EFI_INVALID_PARAMETER; + } + + return ret; +} + /** * try_load_entry() - try to load image for boot option * @@ -185,7 +370,7 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle, { struct efi_load_option lo; u16 varname[9]; - void *load_option; + void *load_option = NULL; efi_uintn_t size; efi_status_t ret; @@ -211,6 +396,17 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle, if (EFI_DP_TYPE(lo.file_path, MEDIA_DEVICE, FILE_PATH)) { /* file_path doesn't contain a device path */ ret = try_load_from_short_path(lo.file_path, handle); + } else if (EFI_DP_TYPE(lo.file_path, MESSAGING_DEVICE, MSG_URI)) { + if (IS_ENABLED(CONFIG_BLKMAP) && + IS_ENABLED(CONFIG_CMD_WGET) && + IS_ENABLED(CONFIG_CMD_DNS)) { + ret = try_load_from_uri_path( + (struct efi_device_path_uri *) + lo.file_path, + lo.label, handle); + } else { + ret = EFI_LOAD_ERROR; + } } else { file_path = expand_media_path(lo.file_path); ret = EFI_CALL(efi_load_image(true, efi_root, file_path, diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c index 838023c78f..edc515b9ff 100644 --- a/lib/efi_loader/efi_dt_fixup.c +++ b/lib/efi_loader/efi_dt_fixup.c @@ -22,7 +22,7 @@ const efi_guid_t efi_guid_dt_fixup_protocol = EFI_DT_FIXUP_PROTOCOL_GUID; * @nomap: indicates that the memory range shall not be accessed by the * UEFI payload */ -static void efi_reserve_memory(u64 addr, u64 size, bool nomap) +void efi_reserve_memory(u64 addr, u64 size, bool nomap) { int type; efi_uintn_t ret;
This supports to boot from the URI device path. When user selects the URI device path, bootmgr downloads the file using wget into the address specified by loadaddr env variable. If the file is .iso or .img file, mount the image with blkmap then try to boot with the default file(e.g. EFI/BOOT/BOOTAA64.EFI). If the file is PE-COFF file, load and start the downloaded file. The buffer used to download the ISO image file must be reserved to avoid the unintended access to the image. For PE-COFF file case, this memory reservation is done in LoadImage Boot Service. Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org> --- include/efi_loader.h | 2 + lib/efi_loader/efi_bootmgr.c | 198 +++++++++++++++++++++++++++++++++- lib/efi_loader/efi_dt_fixup.c | 2 +- 3 files changed, 200 insertions(+), 2 deletions(-)