Re: [PATCH 3/8] tools: mkeficapsule: Enable multi-payload grouping in config parser
"Ilias Apalodimas" <[email protected]> Mon, 03 Aug 2026 12:32:58 +0300
| Newsgroups | gmane.comp.boot-loaders.u-boot |
|---|---|
| Message-ID | <[email protected]> |
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, ¶ms) != -1) { > params_dependency_check(¶ms); > - generate_capsule(¶ms); > + > + /* Find or create group for this capsule */ > + group = find_or_create_group(params.capsule_file); > + add_to_group(group, ¶ms); > > memset(¶ms, 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