hi Malte, On Fri, 16 Jun 2023 at 18:42, Schmidt, Malte <malte.schmidt-...@weidmueller.com> wrote: > > Hi sughosh, > > Am 16.06.2023 um 08:35 schrieb Sughosh Ganu: > > On Fri, 16 Jun 2023 at 10:48, Takahiro Akashi > <takahiro.aka...@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.aka...@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.aka...@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.aka...@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.aka...@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 Ganu <sughosh.g...@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 >
<snip> > 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 > > } > > ? I am aware of these additional brackets and the "Payloads" keyword that is used in the EDK2 json file. Adding this should not be a big effort. However, the reason I did not add this is that I did not see any value in adding this. I believe the EDK2 json file also is used for providing information about additional files, like optional driver images. But we don't support that with the u-boot tool. So will we be adding any value by putting these additional brackets. The other question is, in case of a single capsule file consisting of multiple payloads, how do we pass the name of the output capsule file. I see two options, one is having a field like "capsule" outside of all the payloads. The other is passing this through the command line. In any case, changes for extending this for supporting a single capsule should be sent along with your change of adding support for a single capsule file. I can work on adding this, but it would be good to get this in as part of your patches. -sughosh > > 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 > >