On Mon Jul 27, 2026 at 6:56 PM EEST, Balaji Selvanathan wrote:
> Extend the config file parser to automatically group multiple payloads
> with the same capsule filename into a single multi-payload capsule.
>
> The parser now operates in two phases:
> 1. Parse all payload entries and group by capsule filename
> 2. Generate capsules based on grouping:
>    - Single payload: use existing generation path
>    - Multiple normal payloads: create multi-payload capsule
>    - Mixed/non-normal types: generate separate capsules with warning

I think we should just remote the third option and exit with an error. We can't
predict all the mistakes users do and correct them

>
> This allows users to specify multiple firmware images for the same
> capsule file in the config, and the tool will automatically create
> an optimized multi-payload capsule when possible.
>
> Example config usage:
>   [capsule1]
>   image-guid: <guid1>
>   hardware-instance: 0
>   image-index: 1
>   payload: payload1.bin
>   capsule: update.capsule

Why is 'update.capsule' needed? This seems a command line option

>
>   [capsule1]
>   image-guid: <guid2>
>   hardware-instance: 0
>   image-index: 2
>   payload: payload2.bin
>   capsule: update.capsule
>
> This will generate a single update.capsule containing both payloads.
>
> Signed-off-by: Balaji Selvanathan <[email protected]>
> ---
>  tools/mkeficapsule_parse.c | 115 
> ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 113 insertions(+), 2 deletions(-)
>
> diff --git a/tools/mkeficapsule_parse.c b/tools/mkeficapsule_parse.c
> index 12f5f04b824..4a07006e2f8 100644
> --- a/tools/mkeficapsule_parse.c
> +++ b/tools/mkeficapsule_parse.c
> @@ -299,6 +299,63 @@ static void params_dependency_check(struct 
> efi_capsule_params *params)
>       }
>  }
>
> +#define MAX_CAPSULE_GROUPS 32
> +
> +struct capsule_group {
> +     char *capsule_filename;
> +     struct efi_capsule_params_array params_array;
> +};
> +
> +static struct capsule_group groups[MAX_CAPSULE_GROUPS];
> +static int group_count;
> +
> +static struct capsule_group *find_or_create_group(const char 
> *capsule_filename)
> +{
> +     int i;
> +
> +     /* Search for existing group */
> +     for (i = 0; i < group_count; i++) {
> +             if (groups[i].capsule_filename &&
> +                 !strcmp(groups[i].capsule_filename, capsule_filename)) {
> +                     return &groups[i];
> +             }
> +     }
> +
> +     /* Create new group */
> +     if (group_count >= MAX_CAPSULE_GROUPS) {
> +             fprintf(stderr, "Too many capsule groups (max %d)\n",
> +                     MAX_CAPSULE_GROUPS);
> +             exit(EXIT_FAILURE);
> +     }
> +
> +     groups[group_count].capsule_filename = strdup(capsule_filename);
> +     if (!groups[group_count].capsule_filename)
> +             print_and_exit(MALLOC_FAIL_STR);
> +
> +     groups[group_count].params_array.count = 0;
> +     return &groups[group_count++];
> +}
> +
> +static void add_to_group(struct capsule_group *group,
> +                      struct efi_capsule_params *params)
> +{
> +     struct efi_capsule_params *new_params;
> +
> +     if (group->params_array.count >= MAX_PAYLOADS_PER_CAPSULE) {
> +             fprintf(stderr, "Too many payloads for capsule %s (max %d)\n",
> +                     group->capsule_filename, MAX_PAYLOADS_PER_CAPSULE);
> +             exit(EXIT_FAILURE);
> +     }
> +
> +     /* Allocate and copy params */
> +     new_params = malloc(sizeof(struct efi_capsule_params));
> +     if (!new_params)
> +             print_and_exit(MALLOC_FAIL_STR);
> +
> +     memcpy(new_params, params, sizeof(struct efi_capsule_params));
> +     group->params_array.params[group->params_array.count++] = new_params;
> +}
> +
>  static void generate_capsule(struct efi_capsule_params *params)
>  {
>       if (params->capsule != CAPSULE_NORMAL_BLOB) {
> @@ -324,7 +381,8 @@ static void generate_capsule(struct efi_capsule_params 
> *params)
>   * @cfg_file: Path to the config file
>   *
>   * Parse the capsule parameters from the config file and use the
> - * parameters for generating one or more capsules.
> + * parameters for generating one or more capsules. Payloads with the
> + * same capsule filename are grouped into a single multi-payload capsule.
>   *
>   * Return: None
>   *
> @@ -333,6 +391,8 @@ void capsule_with_cfg_file(const char *cfg_file)
>  {
>       FILE *fp;
>       struct efi_capsule_params params = { 0 };
> +     struct capsule_group *group;
> +     int i;
>
>       fp = fopen(cfg_file, "r");
>       if (!fp) {
> @@ -343,11 +403,62 @@ void capsule_with_cfg_file(const char *cfg_file)
>
>       params_start = 0;
>       params_end = 1;
> +     group_count = 0;
>
> +     /* Phase 1: Parse all payloads and group by capsule filename */
>       while (parse_capsule_payload_params(fp, &params) != -1) {
>               params_dependency_check(&params);
> -             generate_capsule(&params);
> +
> +             /* Find or create group for this capsule */
> +             group = find_or_create_group(params.capsule_file);
> +             add_to_group(group, &params);
>
>               memset(&params, 0, sizeof(struct efi_capsule_params));
>       }
> +
> +     fclose(fp);
> +
> +     /* Phase 2: Generate capsules */
> +     for (i = 0; i < group_count; i++) {
> +             group = &groups[i];
> +
> +             /* Check if all payloads in group are normal blobs */
> +             int all_normal = 1;
> +             int j;
> +
> +             for (j = 0; j < group->params_array.count; j++) {
> +                     if (group->params_array.params[j]->capsule != 
> CAPSULE_NORMAL_BLOB) {
> +                             all_normal = 0;
> +                             break;
> +                     }
> +             }
> +
> +             if (group->params_array.count == 1) {
> +                     /* Single payload - use existing function */
> +                     printf("Generating single-payload capsule: %s\n",
> +                            group->capsule_filename);
> +                     generate_capsule(group->params_array.params[0]);
> +             } else if (all_normal) {
> +                     /* Multiple normal payloads - use multi-payload 
> function */
> +                     printf("Generating multi-payload capsule: %s (%d 
> payloads)\n",
> +                            group->capsule_filename, 
> group->params_array.count);
> +                     if (create_multi_payload_fwbin(group->capsule_filename,
> +                                                    &group->params_array) < 
> 0) {
> +                             print_and_exit("Creating multi-payload capsule 
> failed\n");
> +                     }
> +             } else {
> +                     /* Mixed or non-normal capsules - generate separately */
> +                     fprintf(stderr, "Warning: Cannot combine non-normal 
> capsules. ");
> +                     fprintf(stderr, "Generating separate capsules for %s\n",
> +                             group->capsule_filename);
> +                     for (j = 0; j < group->params_array.count; j++) {
> +                             char temp_name[256];
> +
> +                             snprintf(temp_name, sizeof(temp_name), "%s.%d",
> +                                      group->capsule_filename, j);
> +                             group->params_array.params[j]->capsule_file = 
> temp_name;
> +                             generate_capsule(group->params_array.params[j]);
> +                     }
> +             }
> +     }
>  }

Thanks
/Ilias

Reply via email to