[PATCH v2 1/4] tools: mkeficapsule: Add support for parsing capsule params from config file
Sughosh Ganu
sughosh.ganu at linaro.org
Tue Apr 23 11:09:18 CEST 2024
hi Heinrich,
On Fri, 19 Apr 2024 at 12:44, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
>
> On 19.04.24 08:55, 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.
> >
> > The config file can be passed to the mkeficapsule tool in such manner
> >
> > $ ./tools/mkeficapsule -f <path/to/the/config/file>
>
> Please, mention the long option.
Okay
>
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org>
> > ---
> > tools/Kconfig | 15 ++
> > tools/Makefile | 1 +
> > tools/eficapsule.h | 114 ++++++++++++
> > tools/mkeficapsule.c | 87 +++++----
> > tools/mkeficapsule_parse.c | 352 +++++++++++++++++++++++++++++++++++++
> > 5 files changed, 538 insertions(+), 31 deletions(-)
> > create mode 100644 tools/mkeficapsule_parse.c
> >
> > diff --git a/tools/Kconfig b/tools/Kconfig
> > index 667807b331..0362ca8e45 100644
> > --- a/tools/Kconfig
> > +++ b/tools/Kconfig
> > @@ -104,6 +104,21 @@ 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"
> > + 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.
>
> This help test does not explain if this is a parameter for binman or
> something built into mkeficapsule.
>
> We should not hard code any path inside mkeficapsule.
>
> I can't see the new CONFIG parameters used within the code changes of
> this patch. Please, add them into the patches where they are needed.
As discussed over IRC, I need these config options only for the CI
testing. I will replace these with hard-coded paths for the tests.
>
> > +
> > +config EFI_USE_CAPSULE_CFG_FILE
> > + bool "Use the config file for generating capsules"
> > + help
> > + Boolean option used to specify if the EFI capsules are to
> > + be generated through parameters specified via the config
> > + file or through command line.
>
> Given this help text I would not know if this option changes how
> mkeficapsule is built or how binman invokes it.
>
> I would expect that mkeficapsule is always built in a way that a
> configuration file can be passed.
>
> Furthermore I would expect binman to invoke mkeficapsule with the
> appropriate command line parameters if you have enabled building capsules.
>
> Why do we need this configuration parameter? Just always build
> mkeficapsule with support for the -f parameter.
Will remove these config flags.
-sughosh
>
> Best regards
>
> Heinrich
>
> > +
> > menuconfig FSPI_CONF_HEADER
> > bool "FlexSPI Header Configuration"
> > help
> > diff --git a/tools/Makefile b/tools/Makefile
> > index 6a4280e366..4311f5914f 100644
> > --- a/tools/Makefile
> > +++ b/tools/Makefile
> > @@ -253,6 +253,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
> >
> > mkfwumdata-objs := mkfwumdata.o generated/lib/crc32.o
> > HOSTLDLIBS_mkfwumdata += -luuid
> > diff --git a/tools/eficapsule.h b/tools/eficapsule.h
> > index 6efd07d2eb..71a08b62e6 100644
> > --- a/tools/eficapsule.h
> > +++ b/tools/eficapsule.h
> > @@ -54,6 +54,12 @@ typedef struct {
> > /* flags */
> > #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000
> >
> > +enum capsule_type {
> > + CAPSULE_NORMAL_BLOB = 0,
> > + CAPSULE_ACCEPT,
> > + CAPSULE_REVERT,
> > +};
> > +
> > struct efi_capsule_header {
> > efi_guid_t capsule_guid;
> > uint32_t header_size;
> > @@ -145,4 +151,112 @@ struct fmp_payload_header_params {
> > uint32_t fw_version;
> > };
> >
> > +/**
> > + * 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
> > + * @fmp: FMP payload header used for storing firmware version
> > + * @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;
> > + struct fmp_payload_header_params fmp;
> > + uint64_t monotonic_count;
> > + char *privkey_file;
> > + char *cert_file;
> > + char *input_file;
> > + char *capsule_file;
> > + unsigned long oemflags;
> > + enum capsule_type capsule;
> > +};
> > +
> > +/**
> > + * 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
> > + * @fmp: FMP header params
> > + * @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,
> > + struct fmp_payload_header_params *fmp_ph_params,
> > + 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 6a261ff549..480cedfa5e 100644
> > --- a/tools/mkeficapsule.c
> > +++ b/tools/mkeficapsule.c
> > @@ -28,13 +28,7 @@ static const char *tool_name = "mkeficapsule";
> > efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
> > 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:dhARD";
> > -
> > -enum {
> > - CAPSULE_NORMAL_BLOB = 0,
> > - CAPSULE_ACCEPT,
> > - CAPSULE_REVERT,
> > -} capsule_type;
> > +static const char *opts_short = "g:i:I:v:p:c:m:o:f:dhARD";
> >
> > static struct option options[] = {
> > {"guid", required_argument, NULL, 'g'},
> > @@ -49,11 +43,21 @@ static struct option options[] = {
> > {"fw-revert", no_argument, NULL, 'R'},
> > {"capoemflag", required_argument, NULL, 'o'},
> > {"dump-capsule", no_argument, NULL, 'D'},
> > + {"cfg-file", required_argument, NULL, 'f'},
> > {"help", no_argument, NULL, 'h'},
> > {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"
> > @@ -70,6 +74,7 @@ static void print_usage(void)
> > "\t-R, --fw-revert firmware revert capsule, takes no GUID, no image blob\n"
> > "\t-o, --capoemflag Capsule OEM Flag, an integer between 0x0000 and 0xffff\n"
> > "\t-D, --dump-capsule dump the contents of the capsule headers\n"
> > + "\t-f, --cfg-file <config file> config file with capsule parameters\n"
> > "\t-h, --help print a help message\n",
> > tool_name);
> > }
> > @@ -389,6 +394,7 @@ static void free_sig_data(struct auth_context *ctx)
> > * @guid: GUID of related FMP driver
> > * @index: Index number in capsule
> > * @instance: Instance number in capsule
> > + * @fmp: FMP header params
> > * @mcount: Monotonic count in authentication information
> > * @private_file: Path to a private key file
> > * @cert_file: Path to a certificate file
> > @@ -403,11 +409,11 @@ 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,
> > - struct fmp_payload_header_params *fmp_ph_params,
> > - 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,
> > + struct fmp_payload_header_params *fmp_ph_params,
> > + uint64_t mcount, char *privkey_file, char *cert_file,
> > + uint16_t oemflags)
> > {
> > struct efi_capsule_header header;
> > struct efi_firmware_management_capsule_header capsule;
> > @@ -605,7 +611,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;
> > @@ -878,6 +898,8 @@ int main(int argc, char **argv)
> > unsigned long oemflags;
> > bool capsule_dump;
> > char *privkey_file, *cert_file;
> > + char *cfg_file;
> > + enum capsule_type capsule;
> > int c, idx;
> > struct fmp_payload_header_params fmp_ph_params = { 0 };
> >
> > @@ -888,8 +910,9 @@ int main(int argc, char **argv)
> > privkey_file = NULL;
> > cert_file = NULL;
> > capsule_dump = false;
> > + cfg_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);
> > @@ -943,20 +966,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);
> > @@ -969,6 +992,10 @@ int main(int argc, char **argv)
> > case 'D':
> > capsule_dump = true;
> > break;
> > + case 'f':
> > + cfg_file = optarg;
> > + capsule_with_cfg_file(cfg_file);
> > + exit(EXIT_SUCCESS);
> > default:
> > print_usage();
> > exit(EXIT_SUCCESS);
> > @@ -985,21 +1012,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);
> > }
> > @@ -1009,6 +1036,4 @@ int main(int argc, char **argv)
> > fprintf(stderr, "Creating firmware capsule failed\n");
> > exit(EXIT_FAILURE);
> > }
> > -
> > - exit(EXIT_SUCCESS);
> > }
> > diff --git a/tools/mkeficapsule_parse.c b/tools/mkeficapsule_parse.c
> > new file mode 100644
> > index 0000000000..0b010706d5
> > --- /dev/null
> > +++ b/tools/mkeficapsule_parse.c
> > @@ -0,0 +1,352 @@
> > +// 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
> > + fw-version: 2
> > + 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
> > + fw-version: 10
> > + 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", "fw-version" };
> > +
> > +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(¶m->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(¶m->privkey_file, val);
> > + return;
> > + case 3:
> > + add_string(¶m->cert_file, val);
> > + return;
> > + case 4:
> > + add_string(¶m->input_file, val);
> > + return;
> > + case 5:
> > + add_string(¶m->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;
> > + case 10:
> > + param->fmp.fw_version = strtoul(val, NULL, 0);
> > + param->fmp.have_header = true;
> > + 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,
> > + ¶ms->fmp,
> > + 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, ¶ms) != -1) {
> > + params_dependency_check(¶ms);
> > + generate_capsule(¶ms);
> > +
> > + memset(¶ms, 0, sizeof(struct efi_capsule_params));
> > + }
> > +}
>
More information about the U-Boot
mailing list