[RFC 06/14] efi_loader: capsule: add capsule_on_disk support

AKASHI Takahiro takahiro.akashi at linaro.org
Mon Mar 30 09:43:02 CEST 2020


On Thu, Mar 19, 2020 at 06:08:15PM +0100, Heinrich Schuchardt wrote:
> On 3/18/20 9:55 AM, Heinrich Schuchardt wrote:
> > On 3/17/20 3:12 AM, 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 identified only if they
> >> are located in a specific directory on a device that is determined
> >> by "BootXXXX" variables.
> > 
> > We have efi_set_bootdev() defining the boot device. So why do you refer
> > to BootXXXX?
> > 
> > Please, add Sphinx style comments to the functions describing
> > functionality and parameters.
> > 
> >>
> >> Signed-off-by: AKASHI Takahiro <takahiro.akashi at linaro.org>
> >> ---
> >>   include/efi_loader.h          |  18 ++
> >>   lib/efi_loader/Kconfig        |   7 +
> >>   lib/efi_loader/efi_boottime.c |   3 +
> >>   lib/efi_loader/efi_capsule.c  | 548 ++++++++++++++++++++++++++++++++++
> >>   lib/efi_loader/efi_setup.c    |   6 +
> >>   5 files changed, 582 insertions(+)
> >>
> >> diff --git a/include/efi_loader.h b/include/efi_loader.h
> >> index c3cb7735bf50..c701672e18db 100644
> >> --- a/include/efi_loader.h
> >> +++ b/include/efi_loader.h
> >> @@ -178,6 +178,8 @@ extern const efi_guid_t
> >> efi_guid_hii_config_routing_protocol;
> >>   extern const efi_guid_t efi_guid_hii_config_access_protocol;
> >>   extern const efi_guid_t efi_guid_hii_database_protocol;
> >>   extern const efi_guid_t efi_guid_hii_string_protocol;
> >> +/* GUID of capsule update result */
> >> +extern const efi_guid_t efi_guid_capsule_report;
> >>
> >>   /* GUID of RNG protocol */
> >>   extern const efi_guid_t efi_guid_rng_protocol;
> >> @@ -690,6 +692,22 @@ efi_status_t EFIAPI efi_query_capsule_caps(
> >>           u64 *maximum_capsule_size,
> >>           u32 *reset_type);
> >>
> >> +#ifdef CONFIG_EFI_CAPSULE_ON_DISK
> >> +#define EFI_CAPSULE_DIR L"\\EFI\\UpdateCapsule\\"
> >> +
> >> +/* Hook at initialization */
> >> +efi_status_t efi_launch_capsules(void);
> >> +/* Notify ExitBootServices() is called */
> >> +void efi_capsule_boot_exit_notify(void);
> >> +#else
> >> +static inline efi_status_t efi_launch_capsules(void)
> >> +{
> >> +    return EFI_SUCCESS;
> >> +}
> >> +
> >> +static inline efi_capsule_boot_exit_notify(void) {}
> >> +#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 */
> >> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> >> index 2ef6cb124f3a..95e10f7d981b 100644
> >> --- a/lib/efi_loader/Kconfig
> >> +++ b/lib/efi_loader/Kconfig
> >> @@ -97,6 +97,13 @@ config EFI_CAPSULE_UPDATE
> >>         Select this option if you want to use capsule update feature,
> >>         including firmware updates and variable updates.
> >>
> >> +config EFI_CAPSULE_ON_DISK
> >> +    bool "Enable capsule-on-disk support"
> >> +    depends on EFI_CAPSULE_UPDATE
> >> +    default n
> >> +    help
> >> +      Select this option if you want to use capsule-on-disk feature.
> >> +
> >>   config EFI_LOADER_BOUNCE_BUFFER
> >>       bool "EFI Applications use bounce buffers for DMA operations"
> >>       depends on ARM64
> >> diff --git a/lib/efi_loader/efi_boottime.c
> >> b/lib/efi_loader/efi_boottime.c
> >> index 9860d5047502..c2a789b4f910 100644
> >> --- a/lib/efi_loader/efi_boottime.c
> >> +++ b/lib/efi_loader/efi_boottime.c
> >> @@ -1981,6 +1981,9 @@ static efi_status_t EFIAPI
> >> efi_exit_boot_services(efi_handle_t image_handle,
> >>       /* Notify variable services */
> >>       efi_variables_boot_exit_notify();
> >>
> >> +    /* Notify capsule services */
> >> +    efi_capsule_boot_exit_notify();
> >> +
> >>       /* Remove all events except EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE */
> >>       list_for_each_entry_safe(evt, next_event, &efi_events, link) {
> >>           if (evt->type != EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)
> >> diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
> >> index d3f931910d10..f3e2a555a6b9 100644
> >> --- a/lib/efi_loader/efi_capsule.c
> >> +++ b/lib/efi_loader/efi_capsule.c
> >> @@ -10,8 +10,14 @@
> >>   #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;
> >> +
> >> +/* for file system access */
> >> +static struct efi_file_handle *bootdev_root;
> >> +
> >>   /*
> >>    * Launch a capsule
> >>    */
> >> @@ -96,3 +102,545 @@ efi_status_t EFIAPI efi_query_capsule_caps(
> >>   out:
> >>       return EFI_EXIT(ret);
> >>   }
> >> +
> >> +#ifdef CONFIG_EFI_CAPSULE_ON_DISK
> >> +static void efi_capsule_result_variable(int num,
> >> +                    struct efi_capsule_header *capsule,
> >> +                    efi_status_t return_status)
> >> +{
> >> +    char variable_name[12];
> >> +    u16 variable_name16[12], *p;
> >> +    struct efi_capsule_result_variable_header result;
> >> +    struct efi_time time;
> >> +    efi_status_t ret;
> >> +
> >> +    sprintf(variable_name, "Capsule%04X", num);
> >> +    p = variableame16;
> >> +    utf8_utf16_strncpy(&p, variable_name, 11);
> >> +    result.variable_total_size = sizeof(result);
> >> +    result.capsule_guid = capsule->capsule_guid;
> >> +    ret = EFI_CALL((*efi_runtime_services.get_time)(&time, NULL));
> >> +    if (ret == EFI_SUCCESS)
> >> +        memcpy(&result.capsule_processed, &time, sizeof(time));
> >> +    else
> >> +        memset(&result.capsule_processed, 0, sizeof(time));
> >> +    result.capsule_status = return_status;
> >> +    ret = EFI_CALL(efi_set_variable(variable_name16,
> >> +                    &efi_guid_capsule_report,
> >> +                    EFI_VARIABLE_NON_VOLATILE |
> >> +                    EFI_VARIABLE_BOOTSERVICE_ACCESS |
> >> +                    EFI_VARIABLE_RUNTIME_ACCESS,
> >> +                    sizeof(result), &result));
> >> +    if (ret)
> >> +        EFI_PRINT("EFI Capsule: creating %s failed\n", variable_name);
> > 
> > I think this is an error that should always be reported to the user.
> > Please, use printf().
> > 
> > After https://patchwork.ozlabs.org/patch/1245322/ is merged we can move
> > to log().
> > 
> >> +}
> >> +
> >> +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);
> >> +
> >> +    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;
> >> +}
> >> +
> >> +static bool device_is_present(struct efi_device_path *dp)
> >> +{
> >> +    efi_handle_t handle;
> >> +    struct efi_handler *handler;
> >> +    efi_status_t ret;
> >> +
> >> +    handle = efi_dp_find_obj(dp, NULL);
> >> +    if (!handle)
> >> +        return false;
> >> +
> >> +    /* check if this is a block device */
> >> +    ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
> >> +    if (ret != EFI_SUCCESS)
> >> +        return false;
> >> +
> >> +    return true;
> >> +}
> >> +
> >> +static efi_status_t find_boot_device(void)
> 
> Please, use the EFI system partition, cf.
> 
> [PATCH 0/2] efi_loader: detect EFI system partition
> https://lists.denx.de/pipermail/u-boot/2020-March/403560.htm
> https://patchwork.ozlabs.org/project/uboot/list/?series=165417

No.
UEFI specification, section 8.5.5, clearly requires that a device
must be determined by BootNext/BootOrder variables.
*Additionally*, we should check if the device path points to EFI system
partition on the device.
===8<===
The device to be checked for \EFI\UpdateCapsule is identified by reference
to FilePathList field within the selected active Boot#### variable.
===>8===

-Takahiro Akashi


> 
> Best regards
> 
> Heinrich
> 
> >> +{
> >> +    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",
> >> +                    (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);
> >> +
> >> +        ret = get_dp_device(boot_var16, &boot_dev);
> >> +        if (ret == EFI_SUCCESS) {
> >> +            if (device_is_present(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(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;
> >> +}
> >> +
> >> +/*
> >> + * Traverse a capsule directory in boot device
> >> + * Called by initialization code, and returns an array of capsule file
> >> + * names in @files
> >> + */
> >> +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;
> >> +}
> >> +
> >> +/*
> >> + * Read in a capsule file
> >> + */
> >> +static efi_status_t efi_capsule_read_file(u16 *filename,
> >> +                      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;
> >> +}
> >> +
> >> +static efi_status_t efi_capsule_delete_file(u16 *filename)
> >> +{
> >> +    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;
> >> +}
> >> +
> >> +static void efi_capsule_scan_done(void)
> >> +{
> >> +    EFI_CALL((*bootdev_root->close)(bootdev_root));
> >> +    bootdev_root = NULL;
> >> +}
> >> +
> >> +efi_status_t __weak arch_efi_load_capsule_drivers(void)
> >> +{
> >> +    return EFI_SUCCESS;
> >> +}
> >> +
> >> +static int get_last_capsule(void)
> >> +{
> >> +    u16 value16[11]; /* "CapsuleXXXX": non-null-terminated */
> >> +    char value[11], *p;
> >> +    efi_uintn_t size;
> >> +    unsigned long num = 0xffff;
> >> +    efi_status_t ret;
> >> +
> >> +    size = sizeof(value16);
> >> +    ret = EFI_CALL(efi_get_variable(L"CapsuleLast",
> >> +                    &efi_guid_capsule_report,
> >> +                    NULL, &size, value16));
> >> +    if (ret != EFI_SUCCESS || u16_strncmp(value16, L"Capsule", 7))
> >> +        goto err;
> >> +
> >> +    p = value;
> >> +    utf16_utf8_strcpy(&p, value16);
> >> +    strict_strtoul(&value[7], 16, &num);
> >> +err:
> >> +    return (int)num;
> >> +}
> >> +
> >> +/*
> >> + * Launch all the capsules in system at boot time
> >> + *
> >> + * Called by efi init code
> >> + */
> >> +efi_status_t efi_launch_capsules(void)
> >> +{
> >> +    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;
> >> +
> >> +    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("EFI 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)
> >> +                EFI_PRINT("EFI Capsule update failed at %ls\n",
> >> +                      files[i]);
> > 
> > Isn't this an error that should always be presented to the user?
> > 
> >> +
> >> +            free(capsule);
> >> +        } else {
> >> +            EFI_PRINT("EFI Capsule read failed\n");
> > 
> > Same here.
> > 
> >> +        }
> >> +        /* create CapsuleXXXX */
> >> +        efi_capsule_result_variable(num, capsule, ret);
> >> +
> >> +        /* delete a capsule either in case of success or failure */
> >> +        ret = efi_capsule_delete_file(files[i]);
> >> +        if (ret != EFI_SUCCESS)
> >> +            EFI_PRINT("EFI Capsule deletion of capsule failed at %ls\n",
> >> +                  files[i]);
> > 
> > Same here.
> > 
> >> +    }
> >> +    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));
> >> +
> >> +    /* 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,
> >> +                  EFI_VARIABLE_NON_VOLATILE |
> >> +                  EFI_VARIABLE_BOOTSERVICE_ACCESS |
> >> +                  EFI_VARIABLE_RUNTIME_ACCESS,
> >> +                  22, variable_name16));
> >> +
> >> +    return ret;
> >> +}
> >> +
> >> +/*
> >> + * Dummy functions after ExitBootServices()
> >> + */
> >> +efi_status_t EFIAPI efi_update_capsule_runtime(
> >> +        struct efi_capsule_header **capsule_header_array,
> >> +        efi_uintn_t capsule_count,
> >> +        u64 scatter_gather_list)
> >> +{
> >> +    return EFI_UNSUPPORTED;
> >> +}
> >> +
> >> +efi_status_t EFIAPI efi_query_capsule_caps_runtime(
> >> +        struct efi_capsule_header **capsule_header_array,
> >> +        efi_uintn_t capsule_count,
> >> +        u64 *maximum_capsule_size,
> >> +        u32 *reset_type)
> >> +{
> >> +    return EFI_UNSUPPORTED;
> >> +}
> >> +
> >> +/**
> >> + * efi_capsule_boot_exit_notify() - notify ExitBootServices() is called
> >> + */
> >> +void efi_capsule_boot_exit_notify(void)
> > 
> > Shouldn't we put this into efi_runtime_detach() to reduce code size?
> > 
> > The rest looks good at first sight.
> > 
> > Best regards
> > 
> > Heinrich
> > 
> >> +{
> >> +    efi_runtime_services.update_capsule = efi_update_capsule_runtime;
> >> +    efi_runtime_services.query_capsule_caps =
> >> +                efi_query_capsule_caps_runtime;
> >> +    efi_update_table_header_crc32(&efi_runtime_services.hdr);
> >> +}
> >> +#else
> >> +/*
> >> + * Dummy functions for runtime services
> >> + */
> >> +efi_status_t EFIAPI efi_update_capsule(
> >> +        struct efi_capsule_header **capsule_header_array,
> >> +        efi_uintn_t capsule_count,
> >> +        u64 scatter_gather_list)
> >> +{
> >> +    return EFI_UNSUPPORTED;
> >> +}
> >> +
> >> +efi_status_t EFIAPI efi_query_capsule_caps(
> >> +        struct efi_capsule_header **capsule_header_array,
> >> +        efi_uintn_t capsule_count,
> >> +        u64 *maximum_capsule_size,
> >> +        u32 *reset_type)
> >> +{
> >> +    return EFI_UNSUPPORTED;
> >> +}
> >> +#endif /* CONFIG_EFI_CAPSULE_ON_DISK */
> >> diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
> >> index c485cad34022..309defc5e40d 100644
> >> --- a/lib/efi_loader/efi_setup.c
> >> +++ b/lib/efi_loader/efi_setup.c
> >> @@ -96,6 +96,10 @@ static efi_status_t efi_init_os_indications(void)
> >>   #ifdef CONFIG_EFI_CAPSULE_UPDATE
> >>       os_indications_supported |=
> >>               EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED;
> >> +#endif
> >> +#ifdef CONFIG_EFI_CAPSULE_ON_DISK
> >> +    os_indications_supported |=
> >> +            EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;
> >>   #endif
> >>       return EFI_CALL(efi_set_variable(L"OsIndicationsSupported",
> >>                        &efi_global_variable_guid,
> >> @@ -196,6 +200,8 @@ efi_status_t efi_init_obj_list(void)
> >>       if (ret != EFI_SUCCESS)
> >>           goto out;
> >>
> >> +    /* Execute capsules after reboot */
> >> +    ret = efi_launch_capsules();
> >>   out:
> >>       efi_obj_list_initialized = ret;
> >>       return ret;
> >>
> > 
> 


More information about the U-Boot mailing list