Heinrich, On Thu, Jul 23, 2020 at 05:50:09PM +0200, Heinrich Schuchardt wrote: > On 22.07.20 08:05, AKASHI Takahiro wrote: > > Capsule data can be loaded into the system either via UpdateCapsule > > runtime service or files on a file system (of boot device). > > The latter case is called "capsules on disk", and actual updates will > > take place at the next boot time. > > > > In this commit, we will support capsule on disk mechanism. > > > > Please note that U-Boot itself has no notion of "boot device" and > > all the capsule files to be executed will be detected only if they > > are located in a specific directory, \EFI\UpdateCapsule, on a device > > that is identified as a boot device by "BootXXXX" variables. > > > > Signed-off-by: AKASHI Takahiro <takahiro.aka...@linaro.org> > > --- > > common/main.c | 4 + > > include/efi_loader.h | 16 ++ > > lib/efi_loader/Kconfig | 22 ++ > > lib/efi_loader/efi_capsule.c | 510 +++++++++++++++++++++++++++++++++++ > > lib/efi_loader/efi_setup.c | 8 + > > 5 files changed, 560 insertions(+) > > > > diff --git a/common/main.c b/common/main.c > > index 62ab3344e529..71fb749be4f4 100644 > > --- a/common/main.c > > +++ b/common/main.c > > @@ -16,6 +16,7 @@ > > #include <init.h> > > #include <net.h> > > #include <version.h> > > +#include <efi_loader.h> > > > > static void run_preboot_environment_command(void) > > { > > @@ -50,6 +51,9 @@ void main_loop(void) > > if (IS_ENABLED(CONFIG_USE_PREBOOT)) > > run_preboot_environment_command(); > > > > + if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY)) > > + efi_launch_capsules(); > > + > > s = bootdelay_process(); > > if (cli_process_fdt(&s)) > > cli_secure_boot_cmd(s); > > diff --git a/include/efi_loader.h b/include/efi_loader.h > > index a754fb0ed460..7e00bf3b33f3 100644 > > --- a/include/efi_loader.h > > +++ b/include/efi_loader.h > > @@ -808,6 +808,18 @@ efi_status_t EFIAPI efi_query_capsule_caps( > > u64 *maximum_capsule_size, > > u32 *reset_type); > > > > +#ifdef CONFIG_EFI_CAPSULE_ON_DISK > > This #ifdef seems unnecessary. No code will invoke efi_launch_capsules() > if CONFIG_EFI_CAPSULE_ON_DISK is not set.
Okay, I agree that this kind of #ifdef be removed from a header. > > +#define EFI_CAPSULE_DIR L"\\EFI\\UpdateCapsule\\" > > + > > +/* Hook at initialization */ > > +efi_status_t efi_launch_capsules(void); > > +#else > > +static inline efi_status_t efi_launch_capsules(void) > > +{ > > + return EFI_SUCCESS; > > +} > > +#endif /* CONFIG_EFI_CAPSULE_ON_DISK */ > > + > > #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ > > > > /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out > > */ > > @@ -824,6 +836,10 @@ static inline void efi_set_bootdev(const char *dev, > > const char *devnr, > > const char *path) { } > > static inline void efi_net_set_dhcp_ack(void *pkt, int len) { } > > static inline void efi_print_image_infos(void *pc) { } > > +static inline efi_status_t efi_launch_capsules(void) > > +{ > > + return EFI_SUCCESS; > > +} > > > > #endif /* CONFIG_IS_ENABLED(EFI_LOADER) */ > > > > diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig > > index ee9ebe348ad9..6e35cbe64c7f 100644 > > --- a/lib/efi_loader/Kconfig > > +++ b/lib/efi_loader/Kconfig > > @@ -104,6 +104,28 @@ config EFI_RUNTIME_UPDATE_CAPSULE > > Select this option if you want to use UpdateCapsule and > > QueryCapsuleCapabilities API's. > > > > +config EFI_CAPSULE_ON_DISK > > + bool "Enable capsule-on-disk support" > > + select EFI_HAVE_CAPSULE_SUPPORT > > + default n > > + help > > + Select this option if you want to use capsule-on-disk feature, > > + that is, capsules can be fetched and executed from files > > + under a specific directory on UEFI system partition instead of > > + via UpdateCapsule API. > > + > > +config EFI_CAPSULE_ON_DISK_EARLY > > + bool "Initiate capsule-on-disk at U-Boot boottime" > > + depends on EFI_CAPSULE_ON_DISK > > + default y > > + select EFI_SETUP_EARLY > > + help > > + Normally, without this option enabled, capsules will be > > + executed only at the first time of invoking one of efi command. > > + If this option is enabled, capsules will be enforced to be > > + executed as part of U-Boot initialisation so that they will > > + surely take place whatever is set to distro_bootcmd. > > + > > config EFI_DEVICE_PATH_TO_TEXT > > bool "Device path to text protocol" > > default y > > diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c > > index cfe422bee924..2a224546dd11 100644 > > --- a/lib/efi_loader/efi_capsule.c > > +++ b/lib/efi_loader/efi_capsule.c > > @@ -10,10 +10,16 @@ > > #include <efi_loader.h> > > #include <fs.h> > > #include <malloc.h> > > +#include <mapmem.h> > > #include <sort.h> > > > > const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID; > > > > +#ifdef CONFIG_EFI_CAPSULE_ON_DISK > > +/* for file system access */ > > +static struct efi_file_handle *bootdev_root; > > +#endif > > + > > /** > > * get_last_capsule - get the last capsule number > > * > > @@ -166,3 +172,507 @@ efi_status_t EFIAPI efi_query_capsule_caps( > > out: > > return EFI_EXIT(ret); > > } > > + > > +#ifdef CONFIG_EFI_CAPSULE_ON_DISK > > +/** > > + * get_dp_device - retrieve a device path from boot variable > > + * @boot_var: Boot variable name > > + * @device_dp Device path > > + * > > + * Retrieve a device patch from boot variable, @boot_var. > > + * > > + * Return: status code > > + */ > > +static efi_status_t get_dp_device(u16 *boot_var, > > + struct efi_device_path **device_dp) > > +{ > > + void *buf = NULL; > > + efi_uintn_t size; > > + struct efi_load_option lo; > > + struct efi_device_path *file_dp; > > + efi_status_t ret; > > + > > + size = 0; > > + ret = EFI_CALL(efi_get_variable(boot_var, &efi_global_variable_guid, > > + NULL, &size, NULL)); > > + if (ret == EFI_BUFFER_TOO_SMALL) { > > + buf = malloc(size); > > + if (!buf) > > + return EFI_OUT_OF_RESOURCES; > > + ret = EFI_CALL(efi_get_variable(boot_var, > > + &efi_global_variable_guid, > > + NULL, &size, buf)); > > + } > > + if (ret != EFI_SUCCESS) > > + return ret; > > + > > + efi_deserialize_load_option(&lo, buf, &size); > > + > > + if (lo.attributes & LOAD_OPTION_ACTIVE) { > > + efi_dp_split_file_path(lo.file_path, device_dp, &file_dp); > > + efi_free_pool(file_dp); > > + > > + ret = EFI_SUCCESS; > > + } else { > > + ret = EFI_NOT_FOUND; > > + } > > + > > + free(buf); > > + > > + return ret; > > +} > > + > > +/** > > + * device_is_present_and_system_part - check if a device exists > > + * @dp Device path > > + * > > + * Check if a device pointed to by the device path, @dp, exists and is > > + * located in UEFI system partition. > > + * > > + * Return: true - yes, false - no > > + */ > > +static bool device_is_present_and_system_part(struct efi_device_path *dp) > > +{ > > + efi_handle_t handle; > > + > > + handle = efi_dp_find_obj(dp, NULL); > > + if (!handle) > > + return false; > > + > > + return efi_disk_is_system_part(handle); > > +} > > + > > +/** > > + * find_boot_device - identify the boot device > > + * > > + * Identify the boot device from boot-related variables as UEFI > > + * specification describes and put its handle into bootdev_root. > > If none of the Boot* variables is defined we should still be able to do > a capsule update. Please, use efi_system_partition as fallback. My implementation is fully compliant with 8.5.6. Is there any additional requirement in UEFI specification? > > + * > > + * Return: status code > > + */ > > +static efi_status_t find_boot_device(void) > > +{ > > + char boot_var[9]; > > + u16 boot_var16[9], *p, bootnext, *boot_order = NULL; > > + efi_uintn_t size; > > + int i, num; > > + struct efi_simple_file_system_protocol *volume; > > + struct efi_device_path *boot_dev = NULL; > > + efi_status_t ret; > > + > > + /* find active boot device in BootNext */ > > + bootnext = 0; > > + size = sizeof(bootnext); > > + ret = EFI_CALL(efi_get_variable(L"BootNext", > > > Please, avoid EFI_CALL. Use efi_get_variable_int(). Sure. > > > + (efi_guid_t *)&efi_global_variable_guid, > > + NULL, &size, &bootnext)); > > + if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { > > + /* BootNext does exist here */ > > + if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16)) { > > + printf("BootNext must be 16-bit integer\n"); > > + goto skip; > > + } > > + sprintf((char *)boot_var, "Boot%04X", bootnext); > > + p = boot_var16; > > + utf8_utf16_strcpy(&p, boot_var); > > We have this type of conversion in multiple places. Both for BootXXXX as > well as for CapsuleXXXX. Both in capsule updates as well as in > try_load_entry(). > > Please, provide a libary function. While I don't think it's really worth, but I will try. > > + > > + ret = get_dp_device(boot_var16, &boot_dev); > > + if (ret == EFI_SUCCESS) { > > + if (device_is_present_and_system_part(boot_dev)) { > > + goto out; > > + } else { > > + efi_free_pool(boot_dev); > > + boot_dev = NULL; > > + } > > + } > > + } > > + > > +skip: > > + /* find active boot device in BootOrder */ > > + size = 0; > > + ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid, > > + NULL, &size, NULL)); > > + if (ret == EFI_BUFFER_TOO_SMALL) { > > + boot_order = malloc(size); > > + if (!boot_order) { > > + ret = EFI_OUT_OF_RESOURCES; > > + goto out; > > + } > > + > > + ret = EFI_CALL(efi_get_variable( > > + L"BootOrder", &efi_global_variable_guid, > > + NULL, &size, boot_order)); > > + } > > + if (ret != EFI_SUCCESS) > > + goto out; > > + > > + /* check in higher order */ > > + num = size / sizeof(u16); > > + for (i = 0; i < num; i++) { > > + sprintf((char *)boot_var, "Boot%04X", boot_order[i]); > > + p = boot_var16; > > + utf8_utf16_strcpy(&p, boot_var); > > + ret = get_dp_device(boot_var16, &boot_dev); > > + if (ret != EFI_SUCCESS) > > + continue; > > + > > + if (device_is_present_and_system_part(boot_dev)) > > + break; > > + > > + efi_free_pool(boot_dev); > > + boot_dev = NULL; > > + } > > +out: > > + if (boot_dev) { > > + u16 *path_str; > > + > > + path_str = efi_dp_str(boot_dev); > > + EFI_PRINT("EFI Capsule: bootdev is %ls\n", path_str); > > + efi_free_pool(path_str); > > + > > + volume = efi_fs_from_path(boot_dev); > > + if (!volume) > > + ret = EFI_DEVICE_ERROR; > > + else > > + ret = EFI_CALL(volume->open_volume(volume, > > + &bootdev_root)); > > + efi_free_pool(boot_dev); > > + } else { > > + ret = EFI_NOT_FOUND; > > + } > > + free(boot_order); > > + > > + return ret; > > +} > > + > > +/** > > + * efi_capsule_scan_dir - traverse a capsule directory in boot device > > + * @files: Array of file names > > + * @num: Number of elements in @files > > + * > > + * Traverse a capsule directory in boot device. > > + * Called by initialization code, and returns an array of capsule file > > + * names in @files. > > + * > > + * Return: status code > > + */ > > +static efi_status_t efi_capsule_scan_dir(u16 ***files, int *num) > > +{ > > + struct efi_file_handle *dirh; > > + struct efi_file_info *dirent; > > + efi_uintn_t dirent_size, tmp_size; > > + int count; > > + u16 **tmp_files; > > + efi_status_t ret; > > + > > + ret = find_boot_device(); > > + if (ret == EFI_NOT_FOUND) { > > + EFI_PRINT("EFI Capsule: bootdev is not set\n"); > > + *num = 0; > > + return EFI_SUCCESS; > > + } else if (ret != EFI_SUCCESS) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + /* count capsule files */ > > + ret = EFI_CALL((*bootdev_root->open)(bootdev_root, &dirh, > > + EFI_CAPSULE_DIR, > > + EFI_FILE_MODE_READ, 0)); > > + if (ret != EFI_SUCCESS) { > > + *num = 0; > > + return EFI_SUCCESS; > > + } > > + > > + dirent_size = 256; > > + dirent = malloc(dirent_size); > > + if (!dirent) > > + return EFI_OUT_OF_RESOURCES; > > + > > + count = 0; > > + while (1) { > > + tmp_size = dirent_size; > > + ret = EFI_CALL((*dirh->read)(dirh, &tmp_size, dirent)); > > + if (ret == EFI_BUFFER_TOO_SMALL) { > > + dirent = realloc(dirent, tmp_size); > > + if (!dirent) { > > + ret = EFI_OUT_OF_RESOURCES; > > + goto err; > > + } > > + dirent_size = tmp_size; > > + ret = EFI_CALL((*dirh->read)(dirh, &tmp_size, dirent)); > > + } > > + if (ret != EFI_SUCCESS) > > + goto err; > > + if (!tmp_size) > > + break; > > + > > + if (!(dirent->attribute & EFI_FILE_DIRECTORY) && > > + u16_strcmp(dirent->file_name, L".") && > > + u16_strcmp(dirent->file_name, L"..")) > > + count++; > > + } > > + > > + ret = EFI_CALL((*dirh->setpos)(dirh, 0)); > > + if (ret != EFI_SUCCESS) > > + goto err; > > + > > + /* make a list */ > > + tmp_files = malloc(count * sizeof(*files)); > > + if (!tmp_files) { > > + ret = EFI_OUT_OF_RESOURCES; > > + goto err; > > + } > > + > > + count = 0; > > + while (1) { > > + tmp_size = dirent_size; > > + ret = EFI_CALL((*dirh->read)(dirh, &tmp_size, dirent)); > > + if (ret != EFI_SUCCESS) > > + goto err; > > + if (!tmp_size) > > + break; > > + > > + if (!(dirent->attribute & EFI_FILE_DIRECTORY) && > > + u16_strcmp(dirent->file_name, L".") && > > + u16_strcmp(dirent->file_name, L"..")) > > + tmp_files[count++] = u16_strdup(dirent->file_name); > > + } > > + /* ignore an error */ > > + EFI_CALL((*dirh->close)(dirh)); > > + > > + /* in ascii order */ > > + /* FIXME: u16 version of strcasecmp */ > > + qsort(tmp_files, count, sizeof(*tmp_files), > > + (int (*)(const void *, const void *))strcasecmp); > > + *files = tmp_files; > > + *num = count; > > + ret = EFI_SUCCESS; > > +err: > > + free(dirent); > > + > > + return ret; > > +} > > + > > +/** > > + * efi_capsule_read_file - read in a capsule file > > + * @filename: File name > > + * @capsule: Pointer to buffer for capsule > > + * > > + * Read a capsule file and put its content in @capsule. > > + * > > + * Return: status code > > + */ > > +static efi_status_t efi_capsule_read_file(u16 *filename, > > const u16 *filename Okay. > > + struct efi_capsule_header **capsule) > > +{ > > + struct efi_file_handle *dirh, *fh; > > + struct efi_file_info *file_info = NULL; > > + struct efi_capsule_header *buf = NULL; > > + efi_uintn_t size; > > + efi_status_t ret; > > + > > + ret = EFI_CALL((*bootdev_root->open)(bootdev_root, &dirh, > > + EFI_CAPSULE_DIR, > > + EFI_FILE_MODE_READ, 0)); > > + if (ret != EFI_SUCCESS) > > + return ret; > > + ret = EFI_CALL((*dirh->open)(dirh, &fh, filename, > > + EFI_FILE_MODE_READ, 0)); > > + /* ignore an error */ > > + EFI_CALL((*dirh->close)(dirh)); > > + if (ret != EFI_SUCCESS) > > + return ret; > > + > > + /* file size */ > > + size = 0; > > + ret = EFI_CALL((*fh->getinfo)(fh, &efi_file_info_guid, > > + &size, file_info)); > > + if (ret == EFI_BUFFER_TOO_SMALL) { > > + file_info = malloc(size); > > + if (!file_info) { > > + ret = EFI_OUT_OF_RESOURCES; > > + goto err; > > + } > > + ret = EFI_CALL((*fh->getinfo)(fh, &efi_file_info_guid, > > + &size, file_info)); > > + } > > + if (ret != EFI_SUCCESS) > > + goto err; > > + size = file_info->file_size; > > + free(file_info); > > + buf = malloc(size); > > + if (!buf) { > > + ret = EFI_OUT_OF_RESOURCES; > > + goto err; > > + } > > + > > + /* fetch data */ > > + ret = EFI_CALL((*fh->read)(fh, &size, buf)); > > + if (ret == EFI_SUCCESS) { > > + if (size >= buf->capsule_image_size) { > > + *capsule = buf; > > + } else { > > + free(buf); > > + ret = EFI_INVALID_PARAMETER; > > + } > > + } else { > > + free(buf); > > + } > > +err: > > + EFI_CALL((*fh->close)(fh)); > > + > > + return ret; > > +} > > + > > +/** > > + * efi_capsule_delete_file - delete a capsule file > > + * @filename: File name > > + * > > + * Delete a capsule file from capsule directory. > > + * > > + * Return: status code > > + */ > > +static efi_status_t efi_capsule_delete_file(u16 *filename) > > const u16 *filename Okay. > > > +{ > > + struct efi_file_handle *dirh, *fh; > > + efi_status_t ret; > > + > > + ret = EFI_CALL((*bootdev_root->open)(bootdev_root, &dirh, > > + EFI_CAPSULE_DIR, > > + EFI_FILE_MODE_READ, 0)); > > + if (ret != EFI_SUCCESS) > > + return ret; > > + ret = EFI_CALL((*dirh->open)(dirh, &fh, filename, > > + EFI_FILE_MODE_READ, 0)); > > + /* ignore an error */ > > + EFI_CALL((*dirh->close)(dirh)); > > + > > + ret = EFI_CALL((*fh->delete)(fh)); > > + > > + return ret; > > +} > > + > > +/** > > + * efi_capsule_scan_done - reset a scan help function > > + * > > + * Reset a scan help function > > + */ > > +static void efi_capsule_scan_done(void) > > +{ > > + EFI_CALL((*bootdev_root->close)(bootdev_root)); > > + bootdev_root = NULL; > > +} > > + > > +/** > > + * arch_efi_load_capsule_drivers - initialize capsule drivers > > + * > > + * Architecture or board specific initialization routine > > + * > > + * Return: status code > > + */ > > +efi_status_t __weak arch_efi_load_capsule_drivers(void) > > +{ > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + * efi_launch_capsule - launch capsules > > + * > > + * Launch all the capsules in system at boot time. > > + * Called by efi init code > > + * > > + * Return: status codde > > + */ > > +efi_status_t efi_launch_capsules(void) > > +{ > > + u64 os_indications; > > + efi_uintn_t size; > > + struct efi_capsule_header *capsule = NULL; > > + u16 **files; > > + int nfiles, num, i; > > + char variable_name[12]; > > + u16 variable_name16[12], *p; > > + efi_status_t ret; > > + > > + size = sizeof(os_indications); > > + ret = EFI_CALL(efi_get_variable(L"OsIndications", > > + &efi_global_variable_guid, > > + NULL, &size, &os_indications)); > > + if (ret != EFI_SUCCESS || > > + !(os_indications > > + & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED)) > > + return EFI_SUCCESS; > > + > > + num = get_last_capsule(); > > + > > + /* Load capsule drivers */ > > + ret = arch_efi_load_capsule_drivers(); > > + if (ret != EFI_SUCCESS) > > + return ret; > > + > > + /* > > + * Find capsules on disk. > > + * All the capsules are collected at the beginning because > > + * capsule files will be removed instantly. > > + */ > > + nfiles = 0; > > + files = NULL; > > + ret = efi_capsule_scan_dir(&files, &nfiles); > > + if (ret != EFI_SUCCESS) > > + return ret; > > + if (!nfiles) > > + return EFI_SUCCESS; > > + > > + /* Launch capsules */ > > + for (i = 0, ++num; i < nfiles; i++, num++) { > > + EFI_PRINT("capsule from %ls ...\n", files[i]); > > + if (num > 0xffff) > > + num = 0; > > + ret = efi_capsule_read_file(files[i], &capsule); > > + if (ret == EFI_SUCCESS) { > > + ret = EFI_CALL(efi_update_capsule(&capsule, 1, 0)); > > + if (ret != EFI_SUCCESS) > > + printf("EFI Capsule update failed at %ls\n", > > + files[i]); > > + > > + free(capsule); > > + } else { > > + printf("EFI: reading capsule failed: %ls\n", > > + files[i]); > > + } > > + /* create CapsuleXXXX */ > > + set_capsule_result(num, capsule, ret); > > + > > + /* delete a capsule either in case of success or failure */ > > + ret = efi_capsule_delete_file(files[i]); > > + if (ret != EFI_SUCCESS) > > + printf("EFI: deleting a capsule file failed: %ls\n", > > + files[i]); > > + } > > + efi_capsule_scan_done(); > > + > > + for (i = 0; i < nfiles; i++) > > + free(files[i]); > > + free(files); > > + > > + /* CapsuleMax */ > > + p = variable_name16; > > + utf8_utf16_strncpy(&p, "CapsuleFFFF", 11); > > + EFI_CALL(efi_set_variable(L"CapsuleMax", &efi_guid_capsule_report, > > + EFI_VARIABLE_BOOTSERVICE_ACCESS | > > + EFI_VARIABLE_RUNTIME_ACCESS, > > + 22, variable_name16)); > > The variable must be read-only. Please, use efi_set_variable_int. Okay. > The variable should be set in efi_setup.c. It does not depend on the > execution of capsule updates. No. Since efi_launch_capsules() is only called once (and CapsuleMax is only useful if capsule updates are enabled), moving the code to efi_setup.c doesn't make any difference. > > + > > + /* CapsuleLast */ > > + sprintf(variable_name, "Capsule%04X", num - 1); > > + p = variable_name16; > > + utf8_utf16_strncpy(&p, variable_name, 11); > > + EFI_CALL(efi_set_variable(L"CapsuleLast", &efi_guid_capsule_report, > > The variable must be read-only. Please, use efi_set_variable_int. Okay. -Takahiro Akashi > Best regards > > Heinrich > > > + EFI_VARIABLE_NON_VOLATILE | > > + EFI_VARIABLE_BOOTSERVICE_ACCESS | > > + EFI_VARIABLE_RUNTIME_ACCESS, > > + 22, variable_name16)); > > + > > + return ret; > > +} > > +#endif /* CONFIG_EFI_CAPSULE_ON_DISK */ > > diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c > > index 2fc0c5d091b8..a0eb81f079e1 100644 > > --- a/lib/efi_loader/efi_setup.c > > +++ b/lib/efi_loader/efi_setup.c > > @@ -132,6 +132,10 @@ static efi_status_t efi_init_os_indications(void) > > os_indications_supported |= > > EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED; > > > > + if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK)) > > + os_indications_supported |= > > + EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED; > > + > > return efi_set_variable_int(L"OsIndicationsSupported", > > &efi_global_variable_guid, > > EFI_VARIABLE_BOOTSERVICE_ACCESS | > > @@ -243,6 +247,10 @@ efi_status_t efi_init_obj_list(void) > > if (ret != EFI_SUCCESS) > > goto out; > > > > + /* Execute capsules after reboot */ > > + if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) && > > + !IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY)) > > + ret = efi_launch_capsules(); > > out: > > efi_obj_list_initialized = ret; > > return ret; > > >