From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 35DFDEB64D8 for ; Wed, 14 Jun 2023 03:39:53 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id E445785DFA; Wed, 14 Jun 2023 05:39:45 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="xpvKP3/y"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id D645985E44; Wed, 14 Jun 2023 05:39:43 +0200 (CEST) Received: from mail-pl1-x62e.google.com (mail-pl1-x62e.google.com [IPv6:2607:f8b0:4864:20::62e]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 020A38581B for ; Wed, 14 Jun 2023 05:39:36 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=takahiro.akashi@linaro.org Received: by mail-pl1-x62e.google.com with SMTP id d9443c01a7336-1b3cdc7cfc6so4466155ad.1 for ; Tue, 13 Jun 2023 20:39:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1686713975; x=1689305975; h=in-reply-to:content-disposition:mime-version:references :mail-followup-to:message-id:subject:cc:to:from:date:from:to:cc :subject:date:message-id:reply-to; bh=imKNKbYkk3n799VFsdEoKXqvV6K9qa3wz5VEphQlAMY=; b=xpvKP3/yA8ERrC0KotS9KsccU4U7Z29bPJqRtbZxAjj7//fFZaLJQRJd1iG8nWjYpr EM4uVdr8amlfL4YTqoscOkFJL8+XaOam95U86oP7gkCPKnCDE5dotMBh10pR4YM7qhQu ARkr9zv+dGoVrIy3JeT1qTud+BxtmEZZgS2rCt+yeDTw2+XuSyjF7BNUAg9EIrM9G0EQ EvH7TKjtyO9KFaZ81y5YJZVYUSSjpp1blslM1XLpH0aDtcIvfLIimmU+6FSe0RhHct6b 1oF7Jv+2E599P3zcOsYtwlNZkxG5xi74OMrAGoYRELfgsU99AHGwDYe/JA29eCjRQze+ VR7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686713975; x=1689305975; h=in-reply-to:content-disposition:mime-version:references :mail-followup-to:message-id:subject:cc:to:from:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=imKNKbYkk3n799VFsdEoKXqvV6K9qa3wz5VEphQlAMY=; b=YX5ZT8xW8790GyHem/z8r52C12TtLsmU38eBGFeiDa9OZ7RJv8/VRL7HU8lPaGqfjZ LGJIF59aqSbm5ESgnw8vxxP9fUyDUr0Ig+hxyDb9174SzgfpzJ+bMYOV4tz199x52KNo rs5+zS5iLhlvge2FbPeGCzdibJ97brEqx9FmGoC03vOHI7VctqvPXEu3Otcx2KO/RinV 35cfgL6q27XeLeDBCjeVR7OUbHAN6UbujatRqAoz/1LbixOzp28vNEzCrEGZw9vf37EQ ZnSMM7wyCLjLhwAUTMTHmp6OqasmHZsvT4BxKZKV/o9jBInx9R8NZgH2N9Wwq3m7TkFc K5uw== X-Gm-Message-State: AC+VfDzuP7llf8041Qqn6b6owZF1TBdJSxAT8RmRg2ZVR3t21GlcpT6l wE0WDM1GgQl7KSPcHuB68QhkoQ== X-Google-Smtp-Source: ACHHUZ7Sl7bqwZerwZKd6LC2+I4EY9cX/ZEdI415pnRo5f+rNzDQQSZki3iNdyEGkKiPILC1J0YKMA== X-Received: by 2002:a17:903:2301:b0:1ae:3ff8:7fa7 with SMTP id d1-20020a170903230100b001ae3ff87fa7mr15636504plh.4.1686713974968; Tue, 13 Jun 2023 20:39:34 -0700 (PDT) Received: from laputa ([2400:4050:c3e1:100:fde4:9771:7719:be91]) by smtp.gmail.com with ESMTPSA id t12-20020a170902b20c00b001ac741dfd29sm10904807plr.295.2023.06.13.20.39.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 13 Jun 2023 20:39:34 -0700 (PDT) Date: Wed, 14 Jun 2023 12:39:30 +0900 From: Takahiro Akashi To: Sughosh Ganu Cc: u-boot@lists.denx.de, Heinrich Schuchardt , Ilias Apalodimas , Simon Glass , Michal Simek Subject: Re: [PATCH 4/7] tools: mkeficapsule: Add support for parsing capsule params from config file Message-ID: Mail-Followup-To: Takahiro Akashi , Sughosh Ganu , u-boot@lists.denx.de, Heinrich Schuchardt , Ilias Apalodimas , Simon Glass , Michal Simek References: <20230613103806.812065-1-sughosh.ganu@linaro.org> <20230613103806.812065-5-sughosh.ganu@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20230613103806.812065-5-sughosh.ganu@linaro.org> X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean 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 > --- > 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] \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 ", 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 > +#include > +#include > +#include > +#include > + > +#include > + > +#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(¶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; > + } > + } > + } > + > + 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, ¶ms) != -1) { > + params_dependency_check(¶ms); > + generate_capsule(¶ms); > + > + memset(¶ms, 0, sizeof(struct efi_capsule_params)); > + } > +} > -- > 2.34.1 >