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, &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