[PATCH 4/7] tools: mkeficapsule: Add support for parsing capsule params from config file

Takahiro Akashi takahiro.akashi at linaro.org
Wed Jun 14 05:39:30 CEST 2023


Hi Sughosh,

I think this is a good extension to mkeficapsule, but

On Tue, Jun 13, 2023 at 04:08:03PM +0530, Sughosh Ganu wrote:
> Add support for specifying the parameters needed for capsule
> generation through a config file, instead of passing them through
> command-line. Parameters for more than a single capsule file can be
> specified, resulting in generation of multiple capsules through a
> single invocation of the command.
> 
> This path is to be used for generating capsules through a make target,
> with the parameters being parsed from the config file.
> 
> Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org>
> ---
>  tools/Kconfig              |   9 +
>  tools/Makefile             |   1 +
>  tools/eficapsule.h         | 110 ++++++++++++
>  tools/mkeficapsule.c       | 106 +++++++-----
>  tools/mkeficapsule_parse.c | 345 +++++++++++++++++++++++++++++++++++++
>  5 files changed, 531 insertions(+), 40 deletions(-)
>  create mode 100644 tools/mkeficapsule_parse.c
> 
> diff --git a/tools/Kconfig b/tools/Kconfig
> index 539708f277..95f27b7c45 100644
> --- a/tools/Kconfig
> +++ b/tools/Kconfig
> @@ -98,6 +98,15 @@ config TOOLS_MKEFICAPSULE
>  	  optionally sign that file. If you want to enable UEFI capsule
>  	  update feature on your target, you certainly need this.
>  
> +config EFI_CAPSULE_CFG_FILE
> +	string "Path to the EFI Capsule Config File"
> +	default ""
> +	help
> +	  Path to the EFI capsule config file which provides the
> +	  parameters needed to build capsule(s). Parameters can be
> +	  provided for multiple payloads resulting in corresponding
> +	  capsule images being generated.
> +
>  menuconfig FSPI_CONF_HEADER
>  	bool "FlexSPI Header Configuration"
>  	help
> diff --git a/tools/Makefile b/tools/Makefile
> index d793cf3bec..ef366f3d61 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -250,6 +250,7 @@ HOSTLDLIBS_mkeficapsule += \
>  HOSTLDLIBS_mkeficapsule += \
>  	$(shell pkg-config --libs uuid 2> /dev/null || echo "-luuid")
>  hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
> +mkeficapsule-objs := mkeficapsule.o mkeficapsule_parse.o
>  
>  # We build some files with extra pedantic flags to try to minimize things
>  # that won't build on some weird host compiler -- though there are lots of
> diff --git a/tools/eficapsule.h b/tools/eficapsule.h
> index 072a4b5598..42e66c6d6a 100644
> --- a/tools/eficapsule.h
> +++ b/tools/eficapsule.h
> @@ -52,6 +52,38 @@ typedef struct {
>  /* flags */
>  #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET      0x00010000
>  
> +enum capsule_type {
> +	CAPSULE_NORMAL_BLOB = 0,
> +	CAPSULE_ACCEPT,
> +	CAPSULE_REVERT,
> +};
> +
> +/**
> + * struct efi_capsule_params - Capsule parameters
> + * @image_guid: Guid value of the payload input image
> + * @image_index: Image index value
> + * @hardware_instance: Hardware instance to be used for the image
> + * @monotonic_count: Monotonic count value to be used for signed capsule
> + * @privkey_file: Path to private key used in capsule signing
> + * @cert_file: Path to public key certificate used in capsule signing
> + * @input_file: Path to payload input image
> + * @capsule_file: Path to the output capsule file
> + * @oemflags: Oemflags to be populated in the capsule header
> + * @capsule: Capsule Type, normal or accept or revert
> + */
> +struct efi_capsule_params {
> +	efi_guid_t *image_guid;
> +	unsigned long image_index;
> +	unsigned long hardware_instance;
> +	uint64_t monotonic_count;
> +	char *privkey_file;
> +	char *cert_file;
> +	char *input_file;
> +	char *capsule_file;
> +	unsigned long oemflags;
> +	enum capsule_type capsule;
> +};
> +
>  struct efi_capsule_header {
>  	efi_guid_t capsule_guid;
>  	uint32_t header_size;
> @@ -113,4 +145,82 @@ struct efi_firmware_image_authentication {
>  	struct win_certificate_uefi_guid auth_info;
>  } __packed;
>  
> +/**
> + * capsule_with_cfg_file() - Generate capsule from config file
> + * @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.
> + *
> + * Return: None
> + *
> + */
> +void capsule_with_cfg_file(const char *cfg_file);
> +
> +/**
> + * convert_uuid_to_guid() - convert UUID to GUID
> + * @buf:	UUID binary
> + *
> + * UUID and GUID have the same data structure, but their binary
> + * formats are different due to the endianness. See lib/uuid.c.
> + * Since uuid_parse() can handle only UUID, this function must
> + * be called to get correct data for GUID when parsing a string.
> + *
> + * The correct data will be returned in @buf.
> + */
> +void convert_uuid_to_guid(unsigned char *buf);
> +
> +/**
> + * create_empty_capsule() - Generate an empty capsule
> + * @path: Path to the empty capsule file to be generated
> + * @guid: Guid value of the image for which empty capsule is generated
> + * @fw_accept: Flag to specify whether to generate accept or revert capsule
> + *
> + * Generate an empty capsule, either an accept or a revert capsule to be
> + * used to flag acceptance or rejection of an earlier executed firmware
> + * update operation. Being used in the FWU Multi Bank firmware update
> + * feature.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept);
> +
> +/**
> + * create_fwbin - create an uefi capsule file
> + * @path:	Path to a created capsule file
> + * @bin:	Path to a firmware binary to encapsulate
> + * @guid:	GUID of related FMP driver
> + * @index:	Index number in capsule
> + * @instance:	Instance number in capsule
> + * @mcount:	Monotonic count in authentication information
> + * @private_file:	Path to a private key file
> + * @cert_file:	Path to a certificate file
> + * @oemflags:  Capsule OEM Flags, bits 0-15
> + *
> + * This function actually does the job of creating an uefi capsule file.
> + * All the arguments must be supplied.
> + * If either @private_file ror @cert_file is NULL, the capsule file
> + * won't be signed.
> + *
> + * Return:
> + * * 0  - on success
> + * * -1 - on failure
> + */
> +int create_fwbin(char *path, char *bin, efi_guid_t *guid,
> +		 unsigned long index, unsigned long instance,
> +		 uint64_t mcount, char *privkey_file, char *cert_file,
> +		 uint16_t oemflags);
> +
> +/**
> + * print_usage() - Print the command usage string
> + *
> + * Prints the standard command usage string. Called in the case
> + * of incorrect parameters being passed to the tool.
> + *
> + * Return: None
> + *
> + */
> +void print_usage(void);
> +
>  #endif /* _EFI_CAPSULE_H */
> diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
> index b71537beee..711adf0439 100644
> --- a/tools/mkeficapsule.c
> +++ b/tools/mkeficapsule.c
> @@ -31,12 +31,6 @@ efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
>  
>  static const char *opts_short = "g:i:I:v:p:c:m:o:dhAR";
>  
> -enum {
> -	CAPSULE_NORMAL_BLOB = 0,
> -	CAPSULE_ACCEPT,
> -	CAPSULE_REVERT,
> -} capsule_type;
> -
>  static struct option options[] = {
>  	{"guid", required_argument, NULL, 'g'},
>  	{"index", required_argument, NULL, 'i'},
> @@ -52,7 +46,16 @@ static struct option options[] = {
>  	{NULL, 0, NULL, 0},
>  };
>  
> -static void print_usage(void)
> +/**
> + * print_usage() - Print the command usage string
> + *
> + * Prints the standard command usage string. Called in the case
> + * of incorrect parameters being passed to the tool.
> + *
> + * Return: None
> + *
> + */
> +void print_usage(void)
>  {
>  	fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
>  		"Options:\n"
> @@ -400,10 +403,10 @@ static void free_sig_data(struct auth_context *ctx)
>   * * 0  - on success
>   * * -1 - on failure
>   */
> -static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
> -			unsigned long index, unsigned long instance,
> -			uint64_t mcount, char *privkey_file, char *cert_file,
> -			uint16_t oemflags)
> +int create_fwbin(char *path, char *bin, efi_guid_t *guid,
> +		 unsigned long index, unsigned long instance,
> +		 uint64_t mcount, char *privkey_file, char *cert_file,
> +		 uint16_t oemflags)
>  {
>  	struct efi_capsule_header header;
>  	struct efi_firmware_management_capsule_header capsule;
> @@ -580,7 +583,21 @@ void convert_uuid_to_guid(unsigned char *buf)
>  	buf[7] = c;
>  }
>  
> -static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
> +/**
> + * create_empty_capsule() - Generate an empty capsule
> + * @path: Path to the empty capsule file to be generated
> + * @guid: Guid value of the image for which empty capsule is generated
> + * @fw_accept: Flag to specify whether to generate accept or revert capsule
> + *
> + * Generate an empty capsule, either an accept or a revert capsule to be
> + * used to flag acceptance or rejection of an earlier executed firmware
> + * update operation. Being used in the FWU Multi Bank firmware update
> + * feature.
> + *
> + * Return: 0 if OK, -ve on error
> + *
> + */
> +int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
>  {
>  	struct efi_capsule_header header = { 0 };
>  	FILE *f = NULL;
> @@ -623,19 +640,7 @@ err:
>  	return ret;
>  }
>  
> -/**
> - * main - main entry function of mkeficapsule
> - * @argc:	Number of arguments
> - * @argv:	Array of pointers to arguments
> - *
> - * Create an uefi capsule file, optionally signing it.
> - * Parse all the arguments and pass them on to create_fwbin().
> - *
> - * Return:
> - * * 0  - on success
> - * * -1 - on failure
> - */
> -int main(int argc, char **argv)
> +static void capsule_with_cmdline_params(int argc, char **argv)
>  {
>  	efi_guid_t *guid;
>  	unsigned char uuid_buf[16];
> @@ -643,6 +648,7 @@ int main(int argc, char **argv)
>  	uint64_t mcount;
>  	unsigned long oemflags;
>  	char *privkey_file, *cert_file;
> +	enum capsule_type capsule;
>  	int c, idx;
>  
>  	guid = NULL;
> @@ -652,7 +658,7 @@ int main(int argc, char **argv)
>  	privkey_file = NULL;
>  	cert_file = NULL;
>  	dump_sig = 0;
> -	capsule_type = CAPSULE_NORMAL_BLOB;
> +	capsule = CAPSULE_NORMAL_BLOB;
>  	oemflags = 0;
>  	for (;;) {
>  		c = getopt_long(argc, argv, opts_short, options, &idx);
> @@ -702,20 +708,20 @@ int main(int argc, char **argv)
>  			dump_sig = 1;
>  			break;
>  		case 'A':
> -			if (capsule_type) {
> +			if (capsule) {
>  				fprintf(stderr,
>  					"Select either of Accept or Revert capsule generation\n");
>  				exit(1);
>  			}
> -			capsule_type = CAPSULE_ACCEPT;
> +			capsule = CAPSULE_ACCEPT;
>  			break;
>  		case 'R':
> -			if (capsule_type) {
> +			if (capsule) {
>  				fprintf(stderr,
>  					"Select either of Accept or Revert capsule generation\n");
>  				exit(1);
>  			}
> -			capsule_type = CAPSULE_REVERT;
> +			capsule = CAPSULE_REVERT;
>  			break;
>  		case 'o':
>  			oemflags = strtoul(optarg, NULL, 0);
> @@ -732,21 +738,21 @@ int main(int argc, char **argv)
>  	}
>  
>  	/* check necessary parameters */
> -	if ((capsule_type == CAPSULE_NORMAL_BLOB &&
> -	    ((argc != optind + 2) || !guid ||
> -	     ((privkey_file && !cert_file) ||
> -	      (!privkey_file && cert_file)))) ||
> -	    (capsule_type != CAPSULE_NORMAL_BLOB &&
> -	    ((argc != optind + 1) ||
> -	     ((capsule_type == CAPSULE_ACCEPT) && !guid) ||
> -	     ((capsule_type == CAPSULE_REVERT) && guid)))) {
> +	if ((capsule == CAPSULE_NORMAL_BLOB &&
> +	     ((argc != optind + 2) || !guid ||
> +	      ((privkey_file && !cert_file) ||
> +	       (!privkey_file && cert_file)))) ||
> +	    (capsule != CAPSULE_NORMAL_BLOB &&
> +	     ((argc != optind + 1) ||
> +	      (capsule == CAPSULE_ACCEPT && !guid) ||
> +	      (capsule == CAPSULE_REVERT && guid)))) {
>  		print_usage();
>  		exit(EXIT_FAILURE);
>  	}
>  
> -	if (capsule_type != CAPSULE_NORMAL_BLOB) {
> +	if (capsule != CAPSULE_NORMAL_BLOB) {
>  		if (create_empty_capsule(argv[argc - 1], guid,
> -					 capsule_type == CAPSULE_ACCEPT) < 0) {
> +					 capsule == CAPSULE_ACCEPT) < 0) {
>  			fprintf(stderr, "Creating empty capsule failed\n");
>  			exit(EXIT_FAILURE);
>  		}
> @@ -756,6 +762,26 @@ int main(int argc, char **argv)
>  		fprintf(stderr, "Creating firmware capsule failed\n");
>  		exit(EXIT_FAILURE);
>  	}
> +}
> +
> +/**
> + * main - main entry function of mkeficapsule
> + * @argc:	Number of arguments
> + * @argv:	Array of pointers to arguments
> + *
> + * Create an uefi capsule file, optionally signing it.
> + * Parse all the arguments and pass them on to create_fwbin().
> + *
> + * Return:
> + * * 0  - on success
> + * * -1 - on failure
> + */
> +int main(int argc, char **argv)
> +{
> +	if (!strcmp(CONFIG_EFI_CAPSULE_CFG_FILE, ""))
> +		capsule_with_cmdline_params(argc, argv);
> +	else
> +		capsule_with_cfg_file(CONFIG_EFI_CAPSULE_CFG_FILE);

I don't know where the macro, CONFIG_EFI_CAPSULE_CFG_FILE, comes from.
Anyhow, as a general rule, any host tool must be as generic as it should not
depend on a target's config.
(I was told so before.)

So I would suggest that you add another command line, say "--config-file <file>",
to make the command generic.

-Takahiro Akashi


>  
>  	exit(EXIT_SUCCESS);
>  }
> diff --git a/tools/mkeficapsule_parse.c b/tools/mkeficapsule_parse.c
> new file mode 100644
> index 0000000000..ef4f3f6705
> --- /dev/null
> +++ b/tools/mkeficapsule_parse.c
> @@ -0,0 +1,345 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2023 Linaro Limited
> + */
> +
> +/*
> + * The code in this file adds parsing ability to the mkeficapsule
> + * tool. This allows specifying parameters needed to build the capsule
> + * through the config file instead of specifying them on the command-line.
> + * Parameters can be specified for more than one payload, generating the
> + * corresponding capsule files.
> + *
> + * The parameters are specified in a "key:value" pair. All the parameters
> + * that are currently supported by the mkeficapsule tool can be specified
> + * in the config file.
> + *
> + * The example below shows four payloads. The first payload is an example
> + * of generating a signed capsule. The second payload is an example of
> + * generating an unsigned capsule. The third payload is an accept empty
> + * capsule, while the fourth payload is the revert empty capsule, used
> + * for the multi-bank firmware update feature.
> + *
> + * This functionality can be easily extended to generate a single capsule
> + * comprising multiple payloads.
> +
> +	{
> +	    image-guid: 02f4d760-cfd5-43bd-8e2d-a42acb33c660
> +	    hardware-instance: 0
> +	    monotonic-count: 1
> +	    payload: u-boot.bin
> +	    image-index: 1
> +	    private-key: /path/to/priv/key
> +	    pub-key-cert: /path/to/pub/key
> +	    capsule: u-boot.capsule
> +	}
> +	{
> +	    image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
> +	    hardware-instance: 0
> +	    payload: u-boot.itb
> +	    image-index: 2
> +	    oemflags: 0x8000
> +	    capsule: fit.capsule
> +	}
> +	{
> +	    capsule-type: accept
> +	    image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
> +	    capsule: accept.capsule
> +	}
> +	{
> +	    capsule-type: revert
> +	    capsule: revert.capsule
> +	}
> +*/
> +
> +#include <ctype.h>
> +#include <limits.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <uuid/uuid.h>
> +
> +#include "eficapsule.h"
> +
> +#define PARAMS_START	"{"
> +#define PARAMS_END	"}"
> +
> +#define PSTART		2
> +#define PEND		3
> +
> +#define MALLOC_FAIL_STR		"Unable to allocate memory\n"
> +
> +#define ARRAY_SIZE(x)		(sizeof(x) / sizeof((x)[0]))
> +
> +const char *capsule_params[] = {
> +	"image-guid", "image-index", "private-key",
> +	"pub-key-cert", "payload", "capsule",
> +	"hardware-instance", "monotonic-count",
> +	"capsule-type",	"oemflags" };
> +
> +static unsigned char params_start;
> +static unsigned char params_end;
> +
> +static void print_and_exit(const char *str)
> +{
> +	fprintf(stderr, "%s", str);
> +	exit(EXIT_FAILURE);
> +}
> +
> +static int param_delim_checks(char *line, unsigned char *token)
> +{
> +	if (!strcmp(line, PARAMS_START)) {
> +		if (params_start || !params_end) {
> +			fprintf(stderr, "Earlier params processing still in progress. ");
> +			fprintf(stderr, "Can't start processing a new params.\n");
> +			exit(EXIT_FAILURE);
> +		} else {
> +			params_start = 1;
> +			params_end = 0;
> +			*token = PSTART;
> +			return 1;
> +		}
> +	} else if (!strcmp(line, PARAMS_END)) {
> +		if (!params_start) {
> +			fprintf(stderr, "Cannot put end braces without start braces. ");
> +			fprintf(stderr, "Please check the documentation for reference config file syntax\n");
> +			exit(EXIT_FAILURE);
> +		} else {
> +			params_start = 0;
> +			params_end = 1;
> +			*token = PEND;
> +			return 1;
> +		}
> +	} else if (!params_start) {
> +		fprintf(stderr, "Params should be passed within braces. ");
> +		fprintf(stderr, "Please check the documentation for reference config file syntax\n");
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	return 0;
> +}
> +
> +static void add_guid(efi_guid_t **guid_param, char *guid)
> +{
> +	unsigned char uuid_buf[16];
> +
> +	*guid_param = malloc(sizeof(efi_guid_t));
> +	if (!*guid_param)
> +		print_and_exit(MALLOC_FAIL_STR);
> +
> +	if (uuid_parse(guid, uuid_buf))
> +		print_and_exit("Wrong guid format\n");
> +
> +	convert_uuid_to_guid(uuid_buf);
> +	memcpy(*guid_param, uuid_buf, sizeof(efi_guid_t));
> +}
> +
> +static void add_string(char **dst, char *val)
> +{
> +	*dst = strdup(val);
> +	if (!*dst)
> +		print_and_exit(MALLOC_FAIL_STR);
> +}
> +
> +static void match_and_populate_param(char *key, char *val,
> +				     struct efi_capsule_params *param)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(capsule_params); i++) {
> +		if (!strcmp(key, capsule_params[i])) {
> +			switch (i) {
> +			case 0:
> +				add_guid(&param->image_guid, val);
> +				return;
> +			case 1:
> +				param->image_index = strtoul(val, NULL, 0);
> +				if (param->image_index == ULONG_MAX)
> +					print_and_exit("Enter a valid value of index bewtween 1-255");
> +				return;
> +			case 2:
> +				add_string(&param->privkey_file, val);
> +				return;
> +			case 3:
> +				add_string(&param->cert_file, val);
> +				return;
> +			case 4:
> +				add_string(&param->input_file, val);
> +				return;
> +			case 5:
> +				add_string(&param->capsule_file, val);
> +				return;
> +			case 6:
> +				param->hardware_instance = strtoul(val, NULL, 0);
> +				if (param->hardware_instance == ULONG_MAX)
> +					print_and_exit("Enter a valid hardware instance value");
> +				return;
> +			case 7:
> +				param->monotonic_count = strtoull(val, NULL, 0);
> +				if (param->monotonic_count == ULLONG_MAX)
> +					print_and_exit("Enter a valid monotonic count value");
> +				return;
> +			case 8:
> +				if (!strcmp(val, "normal"))
> +					param->capsule = CAPSULE_NORMAL_BLOB;
> +				else if (!strcmp(val, "accept"))
> +					param->capsule = CAPSULE_ACCEPT;
> +				else if (!strcmp(val, "revert"))
> +					param->capsule = CAPSULE_REVERT;
> +				else
> +					print_and_exit("Invalid type of capsule");
> +
> +				return;
> +			case 9:
> +				param->oemflags = strtoul(val, NULL, 0);
> +				if (param->oemflags > 0xffff)
> +					print_and_exit("OemFlags must be between 0x0 and 0xffff\n");
> +				return;
> +			}
> +		}
> +	}
> +
> +	fprintf(stderr, "Undefined param %s specified. ", key);
> +	fprintf(stderr, "Please check the documentation for reference config file syntax\n");
> +	exit(EXIT_FAILURE);
> +}
> +
> +static int get_capsule_params(char *line, struct efi_capsule_params *params)
> +{
> +	char *key = NULL;
> +	char *val = NULL;
> +	unsigned char token;
> +
> +	if (param_delim_checks(line, &token))
> +		return token;
> +
> +	key = strtok(line, ":");
> +	if (key)
> +		val = strtok(NULL, "\0");
> +	else
> +		print_and_exit("Expect the params in a key:value pair\n");
> +
> +	match_and_populate_param(key, val, params);
> +
> +	return 0;
> +}
> +
> +static char *skip_whitespace(char *line)
> +{
> +	char *ptr, *newline;
> +
> +	ptr = malloc(strlen(line) + 1);
> +	if (!ptr)
> +		print_and_exit(MALLOC_FAIL_STR);
> +
> +	for (newline = ptr; *line; line++)
> +		if (!isblank(*line))
> +			*ptr++ = *line;
> +	*ptr = '\0';
> +	return newline;
> +}
> +
> +static int parse_capsule_payload_params(FILE *fp, struct efi_capsule_params *params)
> +{
> +	char *line = NULL;
> +	char *newline;
> +	size_t n = 0;
> +	ssize_t len;
> +
> +	while ((len = getline(&line, &n, fp)) != -1) {
> +		if (len == 1 && line[len - 1] == '\n')
> +			continue;
> +
> +		line[len - 1] = '\0';
> +
> +		newline = skip_whitespace(line);
> +
> +		if (newline[0] == '#')
> +			continue;
> +
> +		if (get_capsule_params(newline, params) == PEND)
> +			return 0;
> +	}
> +
> +	if (errno == EINVAL || errno == ENOMEM) {
> +		fprintf(stderr, "getline() returned an error %s reading the line\n",
> +			strerror(errno));
> +		exit(EXIT_FAILURE);
> +	} else if (params_start == 1 || params_end == 0) {
> +		fprintf(stderr, "Params should be passed within braces. ");
> +		fprintf(stderr, "Please check the documentation for reference config file syntax\n");
> +		exit(EXIT_FAILURE);
> +	} else {
> +		return -1;
> +	}
> +}
> +
> +static void params_dependency_check(struct efi_capsule_params *params)
> +{
> +	/* check necessary parameters */
> +	if ((params->capsule == CAPSULE_NORMAL_BLOB &&
> +	     ((!params->input_file || !params->capsule_file ||
> +	       !params->image_guid) ||
> +	      ((params->privkey_file && !params->cert_file) ||
> +	       (!params->privkey_file && params->cert_file)))) ||
> +	    (params->capsule != CAPSULE_NORMAL_BLOB &&
> +	     (!params->capsule_file ||
> +	      (params->capsule == CAPSULE_ACCEPT && !params->image_guid) ||
> +	      (params->capsule == CAPSULE_REVERT && params->image_guid)))) {
> +		print_usage();
> +		exit(EXIT_FAILURE);
> +	}
> +}
> +
> +static void generate_capsule(struct efi_capsule_params *params)
> +{
> +	if (params->capsule != CAPSULE_NORMAL_BLOB) {
> +		if (create_empty_capsule(params->capsule_file,
> +					 params->image_guid,
> +					 params->capsule ==
> +					 CAPSULE_ACCEPT) < 0)
> +			print_and_exit("Creating empty capsule failed\n");
> +	} else if (create_fwbin(params->capsule_file, params->input_file,
> +			      params->image_guid, params->image_index,
> +			      params->hardware_instance,
> +			      params->monotonic_count,
> +			      params->privkey_file,
> +			      params->cert_file,
> +			      (uint16_t)params->oemflags) < 0) {
> +		print_and_exit("Creating firmware capsule failed\n");
> +	}
> +}
> +
> +/**
> + * capsule_with_cfg_file() - Generate capsule from config file
> + * @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.
> + *
> + * Return: None
> + *
> + */
> +void capsule_with_cfg_file(const char *cfg_file)
> +{
> +	FILE *fp;
> +	struct efi_capsule_params params = { 0 };
> +
> +	fp = fopen(cfg_file, "r");
> +	if (!fp) {
> +		fprintf(stderr, "Unable to open the capsule config file %s\n",
> +			cfg_file);
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	params_start = 0;
> +	params_end = 1;
> +
> +	while (parse_capsule_payload_params(fp, &params) != -1) {
> +		params_dependency_check(&params);
> +		generate_capsule(&params);
> +
> +		memset(&params, 0, sizeof(struct efi_capsule_params));
> +	}
> +}
> -- 
> 2.34.1
> 


More information about the U-Boot mailing list