
Hi sughosh,
Am 16.06.2023 um 08:35 schrieb Sughosh Ganu:
On Fri, 16 Jun 2023 at 10:48, Takahiro Akashi takahiro.akashi@linaro.org wrote:
On Fri, Jun 16, 2023 at 10:37:01AM +0530, Sughosh Ganu wrote:
hi Takahiro,
On Fri, 16 Jun 2023 at 10:16, Takahiro Akashi takahiro.akashi@linaro.org wrote:
Hi Sughosh,
On Fri, Jun 16, 2023 at 09:56:33AM +0530, Sughosh Ganu wrote:
On Thu, 15 Jun 2023 at 11:19, Takahiro Akashi takahiro.akashi@linaro.org wrote:
On Thu, Jun 15, 2023 at 10:09:06AM +0530, Sughosh Ganu wrote: > On Wed, 14 Jun 2023 at 11:23, Takahiro Akashi > takahiro.akashi@linaro.org wrote: >> On Wed, Jun 14, 2023 at 10:56:23AM +0530, Sughosh Ganu wrote: >>> hi Takahiro, >>> >>> On Wed, 14 Jun 2023 at 09:09, Takahiro Akashi >>> takahiro.akashi@linaro.org wrote: >>>> 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 Ganusughosh.ganu@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. >>> Yes, that would be something followed by most of the tools. The reason >>> I did not add a command-line option for the confile file is because I >>> want the capsule generation added as a make target. With the path to >>> the config file specified through the Kconfig symbol, we can invoke >>> 'make capsule', and it would build the capsules by parsing the >>> parameters from the config file, taken from the Kconfig symbol. I know >>> there are ways of specifying options when using a make command, but I >>> don't think that is a clean way of doing things. >> Not sure, but in your [5/7], >> cmd_mkeficapsule = $(objtree)/tools/mkeficapsule --config-file $(CONFIG_EFI_CAPSULE_CFG_FILE) >> >> Doesn't this change work? > So, I tried the above suggested change. But trying to run a make > 'target' does not work without the .config file being present. Not sure what you meant to say here. Why don't you have .config when building U-Boot (or rather 'target')?
Maybe I misunderstood your earlier comment, but I thought you were looking to build capsules without relying on a target config.
Not exactly. The basic requirement, I believe, is that the exact same binary (with the same set of functionalities) should be generated for any host tool whatever a target's config, including tools-only_defconfig, is.
Okay. I think I now understand what you are looking for. However, I believe if you want the same binary for both scenarios, the only way might be to drop the make target to generate capsules, and do it through the --config-file command-line option.
Again not sure what you're trying to do.
Never mind. It works with the cfg-file being passed as a command-line parameter. I will make the change for the next version.
-sughosh
I will check if we can pass the config file as a parameter when building capsules as a target. I could not get it working when I tried it earlier though. If this is indeed not possible, do you have a strong opinion on having the same binary for both scenarios?
I have no reason why you can't. If you see any failure, please give me more details about how you are going to manage so that I can help you.
-Takahiro Akashi
-sughosh
Is it clear now?
-Takahiro Akashi
Which I believe cannot be done for a make target.
-sughosh
-Takahiro Akashi
> FWIW, > the same is the case for building tools as well. I think that is the > reason for the tools-only_defconfig. > > -sughosh > >> -Takahiro Akashi >> >> >>> Given the use case of >>> a make target, I hope we can use the Kconfig symbol for specifying the >>> config file path. >>> >>> -sughosh >>> >>>> -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 >>>>> + } >>>>> +*/ >>>>> +
If i understand it correctly the EDK2 GenerateCapsule tool allows for multiple payloads inside one capsule by specifying a list of payloads in the JSON-file. I think something similar should be done here to support multiple payloads inside one capsule. What about something like this:
{
content: [{ image-guid: 02f4d760-cfd5-43bd-8e2d-a42acb33c660 hardware-instance: 0 monotonic-count: 1 payload: u-boot.bin image-index: 1 },{
image-guid: 02f4d760-cfd5-43bd-8e2d-a42acb33c660 hardware-instance: 1 monotonic-count: 1 payload: boot.bin image-index: 2 }],
private-key: /path/to/priv/key pub-key-cert: /path/to/pub/key capsule: u-boot.capsule
}
?
Best Regards Malte
>>>>> +#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(¶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 >>>>>