hi Stefan, On Fri, 16 Jun 2023 at 17:04, Stefan Herbrechtsmeier <stefan.herbrechtsmeier-...@weidmueller.com> wrote: > > From: Malte Schmidt <malte.schm...@weidmueller.com> > > The UEFI [1] specification allows multiple payloads inside the capsule > body. Add support for this. The command line arguments are kept > backwards-compatible. > > [1] https://uefi.org/specs/UEFI/2.10/index.html
I am trying to upstream support for specifying the capsule parameters for multiple payloads through a config file [1]. This is on similar lines to the support in the Edk2 GenerateCapule tool where multiple payloads can be specified through a json file. I think you can base your changes on my series. -sughosh [1] - https://lore.kernel.org/u-boot/20230613103806.812065-1-sughosh.g...@linaro.org/T/#mc8c0500863bd3a1580c572679370a565f8d7f2c8 > > Signed-off-by: Malte Schmidt <malte.schm...@weidmueller.com> > Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsme...@weidmueller.com> > --- > > tools/eficapsule.h | 5 - > tools/mkeficapsule.c | 636 ++++++++++++++++++++++++++++++++----------- > 2 files changed, 475 insertions(+), 166 deletions(-) > > diff --git a/tools/eficapsule.h b/tools/eficapsule.h > index 753fb73313..001af3217c 100644 > --- a/tools/eficapsule.h > +++ b/tools/eficapsule.h > @@ -138,9 +138,4 @@ struct fmp_payload_header { > uint32_t lowest_supported_version; > }; > > -struct fmp_payload_header_params { > - bool have_header; > - uint32_t fw_version; > -}; > - > #endif /* _EFI_CAPSULE_H */ > diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c > index b8db00b16b..1a4de0f092 100644 > --- a/tools/mkeficapsule.c > +++ b/tools/mkeficapsule.c > @@ -29,7 +29,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:dhAR"; > +static const char *opts_short = "g:i:b:I:v:p:c:m:o:dhAR"; > > enum { > CAPSULE_NORMAL_BLOB = 0, > @@ -40,6 +40,7 @@ enum { > static struct option options[] = { > {"guid", required_argument, NULL, 'g'}, > {"index", required_argument, NULL, 'i'}, > + {"image_blob", required_argument, NULL, 'b'}, > {"instance", required_argument, NULL, 'I'}, > {"fw-version", required_argument, NULL, 'v'}, > {"private-key", required_argument, NULL, 'p'}, > @@ -55,21 +56,22 @@ static struct option options[] = { > > static void print_usage(void) > { > - fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n" > + fprintf(stderr, "Usage: %s [options] [<image blob>] <output file>\n" > "Options:\n" > > - "\t-g, --guid <guid string> guid for image blob type\n" > - "\t-i, --index <index> update image index\n" > - "\t-I, --instance <instance> update hardware instance\n" > - "\t-v, --fw-version <version> firmware version\n" > - "\t-p, --private-key <privkey file> private key file\n" > - "\t-c, --certificate <cert file> signer's certificate > file\n" > - "\t-m, --monotonic-count <count> monotonic count\n" > - "\t-d, --dump_sig dump signature (*.p7)\n" > - "\t-A, --fw-accept firmware accept capsule, requires GUID, > no image blob\n" > - "\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-h, --help print a help message\n", > + "\t-g, --guid <guid list> comma-separated list of > guids for image blob types\n" > + "\t-i, --index <index list> comma-separated list of > update image indices\n" > + "\t-b, --image_blob <blob list> comma-separated list of > image blobs\n" > + "\t-I, --instance <instance list> comma-separated list of > update hardware instances\n" > + "\t-v, --fw-version <version list> comma-separated list of > firmware versions\n" > + "\t-p, --private-key <privkey file> private key > file\n" > + "\t-c, --certificate <cert file> signer's > certificate file\n" > + "\t-m, --monotonic-count <monotonic-count list> > comma-separated list of monotonic counts\n" > + "\t-d, --dump_sig dump > signature (*.p7)\n" > + "\t-A, --fw-accept firmware accept capsule, requires GUID, > no image blob\n" > + "\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-h, --help print a help message\n", > tool_name); > } > > @@ -336,16 +338,18 @@ static int create_auth_data(struct auth_context *ctx) > * @path: Path to a capsule file > * @signature: Signature data > * @sig_size: Size of signature data > + * @index: The payload index the signature belongs to > * > * Signature data pointed to by @signature will be saved into > - * a file whose file name is @path with ".p7" suffix. > + * a file whose file name is @path with "_<index>.p7" suffix. > + * If index is negative the suffix is ".p7" (for backwards compatibility). > * > * Return: > * * 0 - on success > * * -1 - on failure > */ > static int dump_signature(const char *path, const uint8_t *signature, > - size_t sig_size) > + size_t sig_size, int index) > { > char *sig_path; > FILE *f; > @@ -356,7 +360,11 @@ static int dump_signature(const char *path, const > uint8_t *signature, > if (!sig_path) > return ret; > > - sprintf(sig_path, "%s.p7", path); > + if (index < 0) > + sprintf(sig_path, "%s.p7", path); > + else > + sprintf(sig_path, "%s_%d.p7", path, index); > + > f = fopen(sig_path, "w"); > if (!f) > goto err; > @@ -386,14 +394,15 @@ static void free_sig_data(struct auth_context *ctx) > /** > * 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 > + * @bins: Paths to firmware binaries to encapsulate, an array > + * @guids: GUIDs of related FMP drivers, an array > + * @indices: Index numbers in capsule, an array > * @instance: Instance number in capsule > * @mcount: Monotonic count in authentication information > + * @size: Size of the arrays > * @private_file: Path to a private key file > * @cert_file: Path to a certificate file > - * @oemflags: Capsule OEM Flags, bits 0-15 > + * @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. > @@ -404,78 +413,87 @@ static void free_sig_data(struct auth_context *ctx) > * * 0 - on success > * * -1 - on failure > */ > -static int create_fwbin(const char *path, const char *bin, > - const efi_guid_t *guid, unsigned long index, > - unsigned long instance, > - const struct fmp_payload_header_params *fmp_ph_params, > - uint64_t mcount, > - const char *privkey_file, const char *cert_file, > - uint16_t oemflags) > +static int create_fwbin(const char *path, const char **bins, > + const efi_guid_t *guids, const unsigned long *indices, > + const unsigned long *instances, > + const unsigned long *fw_versions, const unsigned long > *mcounts, > + int size, const char *privkey_file, > + const char *cert_file, uint16_t oemflags) > { > struct efi_capsule_header header; > struct efi_firmware_management_capsule_header capsule; > - struct efi_firmware_management_capsule_image_header image; > - struct auth_context auth_context; > + struct efi_firmware_management_capsule_image_header images[size]; > + struct auth_context auth_contexts[size]; > FILE *f; > - uint8_t *data, *new_data, *buf; > - off_t bin_size; > - uint64_t offset; > + uint8_t *data_list[size], *new_data_list[size], *buf_list[size]; > + off_t bin_sizes[size]; > + uint64_t offsets[size]; > int ret; > - struct fmp_payload_header payload_header; > + struct fmp_payload_header payload_headers[size]; > > #ifdef DEBUG > fprintf(stderr, "For output: %s\n", path); > - fprintf(stderr, "\tbin: %s\n\ttype: %pUl\n", bin, guid); > - fprintf(stderr, "\tindex: %lu\n\tinstance: %lu\n", index, instance); > + for (int i = 0; i < size; i++) { > + fprintf(stderr, "\tpayload no: %d\n", i); > + fprintf(stderr, "\t\tbin: %s\n\t\ttype: %pUl\n", bins[i], > guids[i]); > + fprintf(stderr, "\t\tindex: %lu\n\t\tinstance: %lu\n", > indices[i], instances[i]); > + } > #endif > - auth_context.sig_size = 0; > f = NULL; > - data = NULL; > - new_data = NULL; > ret = -1; > > - /* > - * read a firmware binary > - */ > - if (read_bin_file(bin, &data, &bin_size)) > - goto err; > + for (int i = 0; i < size; i++) { > + auth_contexts[i].sig_size = 0; > + data_list[i] = NULL; > + new_data_list[i] = NULL; > + } > > - buf = data; > + for (int i = 0; i < size; i++) { > + int dump_index = (size == 1) ? -1 : i; > > - /* insert fmp payload header right before the payload */ > - if (fmp_ph_params->have_header) { > - new_data = malloc(bin_size + sizeof(payload_header)); > - if (!new_data) > + /* > + * read a firmware binary > + */ > + if (read_bin_file(bins[i], &data_list[i], &bin_sizes[i])) > goto err; > > - payload_header.signature = FMP_PAYLOAD_HDR_SIGNATURE; > - payload_header.header_size = sizeof(payload_header); > - payload_header.fw_version = fmp_ph_params->fw_version; > - payload_header.lowest_supported_version = 0; /* not used */ > - memcpy(new_data, &payload_header, sizeof(payload_header)); > - memcpy(new_data + sizeof(payload_header), data, bin_size); > - buf = new_data; > - bin_size += sizeof(payload_header); > - } > - > - /* first, calculate signature to determine its size */ > - if (privkey_file && cert_file) { > - auth_context.key_file = privkey_file; > - auth_context.cert_file = cert_file; > - auth_context.auth.monotonic_count = mcount; > - auth_context.image_data = buf; > - auth_context.image_size = bin_size; > - > - if (create_auth_data(&auth_context)) { > - fprintf(stderr, "Signing firmware image failed\n"); > - goto err; > + buf_list[i] = data_list[i]; > + /* insert fmp payload header right before the payload */ > + if (fw_versions) { > + new_data_list[i] = malloc(bin_sizes[i] + > sizeof(payload_headers[i])); > + if (!new_data_list[i]) > + goto err; > + > + payload_headers[i].signature = > FMP_PAYLOAD_HDR_SIGNATURE; > + payload_headers[i].header_size = > sizeof(payload_headers[i]); > + payload_headers[i].fw_version = fw_versions[i]; > + payload_headers[i].lowest_supported_version = 0; /* > not used */ > + memcpy(new_data_list[i], (payload_headers + i), > sizeof(payload_headers[i])); > + memcpy(new_data_list[i] + sizeof(payload_headers[i]), > data_list[i], > + bin_sizes[i]); > + buf_list[i] = new_data_list[i]; > + bin_sizes[i] += sizeof(payload_headers[i]); > } > > - if (dump_sig && > - dump_signature(path, auth_context.sig_data, > - auth_context.sig_size)) { > - fprintf(stderr, "Creating signature file failed\n"); > - goto err; > + /* calculate signature to determine its size */ > + if (privkey_file && cert_file) { > + auth_contexts[i].key_file = privkey_file; > + auth_contexts[i].cert_file = cert_file; > + auth_contexts[i].auth.monotonic_count = mcounts[i]; > + auth_contexts[i].image_data = buf_list[i]; > + auth_contexts[i].image_size = bin_sizes[i]; > + > + if (create_auth_data(&auth_contexts[i])) { > + fprintf(stderr, "Signing firmware image > failed\n"); > + goto err; > + } > + > + if (dump_sig && > + dump_signature(path, auth_contexts[i].sig_data, > + auth_contexts[i].sig_size, > dump_index)) { > + fprintf(stderr, "Creating signature file > failed\n"); > + goto err; > + } > } > } > > @@ -498,81 +516,87 @@ static int create_fwbin(const char *path, const char > *bin, > if (oemflags) > header.flags |= oemflags; > header.capsule_image_size = sizeof(header) > - + sizeof(capsule) + sizeof(uint64_t) > - + sizeof(image) > - + bin_size; > - if (auth_context.sig_size) > - header.capsule_image_size += sizeof(auth_context.auth) > - + auth_context.sig_size; > + + sizeof(capsule) > + + size * sizeof(uint64_t); /* size of > item_offset_list */ > + for (int i = 0; i < size; i++) { > + offsets[i] = header.capsule_image_size - sizeof(header); > + header.capsule_image_size += sizeof(images[i]) > + + bin_sizes[i]; > + if (auth_contexts[i].sig_size) > + header.capsule_image_size += > sizeof(auth_contexts[i].auth) > + + auth_contexts[i].sig_size; > + } > if (write_capsule_file(f, &header, sizeof(header), > "Capsule header")) > goto err; > > /* > * firmware capsule header > - * This capsule has only one firmware capsule image. > */ > capsule.version = 0x00000001; > capsule.embedded_driver_count = 0; > - capsule.payload_item_count = 1; > + capsule.payload_item_count = size; > if (write_capsule_file(f, &capsule, sizeof(capsule), > "Firmware capsule header")) > goto err; > > - offset = sizeof(capsule) + sizeof(uint64_t); > - if (write_capsule_file(f, &offset, sizeof(offset), > - "Offset to capsule image")) > + if (write_capsule_file(f, &offsets, size * sizeof(uint64_t), > + "Offsets to capsule images")) > goto err; > > - /* > - * firmware capsule image header > - */ > - image.version = 0x00000003; > - memcpy(&image.update_image_type_id, guid, sizeof(*guid)); > - image.update_image_index = index; > - image.reserved[0] = 0; > - image.reserved[1] = 0; > - image.reserved[2] = 0; > - image.update_image_size = bin_size; > - if (auth_context.sig_size) > - image.update_image_size += sizeof(auth_context.auth) > - + auth_context.sig_size; > - image.update_vendor_code_size = 0; /* none */ > - image.update_hardware_instance = instance; > - image.image_capsule_support = 0; > - if (auth_context.sig_size) > - image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION; > - if (write_capsule_file(f, &image, sizeof(image), > - "Firmware capsule image header")) > - goto err; > - > - /* > - * signature > - */ > - if (auth_context.sig_size) { > - if (write_capsule_file(f, &auth_context.auth, > - sizeof(auth_context.auth), > - "Authentication header")) > + for (int i = 0; i < size; i++) { > + /* > + * firmware capsule image header > + */ > + images[i].version = 0x00000003; > + memcpy(&images[i].update_image_type_id, &guids[i], > sizeof(guids[i])); > + images[i].update_image_index = indices[i]; > + images[i].reserved[0] = 0; > + images[i].reserved[1] = 0; > + images[i].reserved[2] = 0; > + images[i].update_image_size = bin_sizes[i]; > + if (auth_contexts[i].sig_size) > + images[i].update_image_size += > sizeof(auth_contexts[i].auth) > + + auth_contexts[i].sig_size; > + images[i].update_vendor_code_size = 0; /* none */ > + images[i].update_hardware_instance = instances[i]; > + images[i].image_capsule_support = 0; > + if (auth_contexts[i].sig_size) > + images[i].image_capsule_support |= > CAPSULE_SUPPORT_AUTHENTICATION; > + if (write_capsule_file(f, &images[i], sizeof(images[i]), > + "Firmware capsule image header")) > goto err; > > - if (write_capsule_file(f, auth_context.sig_data, > - auth_context.sig_size, "Signature")) > + /* > + * signature > + */ > + if (auth_contexts[i].sig_size) { > + if (write_capsule_file(f, &auth_contexts[i].auth, > + sizeof(auth_contexts[i].auth), > + "Authentication header")) > + goto err; > + > + if (write_capsule_file(f, auth_contexts[i].sig_data, > + auth_contexts[i].sig_size, > "Signature")) > + goto err; > + } > + > + /* > + * firmware binary > + */ > + if (write_capsule_file(f, buf_list[i], bin_sizes[i], > "Firmware binary")) > goto err; > } > > - /* > - * firmware binary > - */ > - if (write_capsule_file(f, buf, bin_size, "Firmware binary")) > - goto err; > - > ret = 0; > err: > if (f) > fclose(f); > - free_sig_data(&auth_context); > - free(data); > - free(new_data); > + for (int i = 0; i < size; i++) { > + free_sig_data(&auth_contexts[i]); > + free(data_list[i]); > + free(new_data_list[i]); > + } > > return ret; > } > @@ -652,6 +676,228 @@ err: > return ret; > } > > +/** > + * count_items - count number of items in list > + * @list: Pointer to a string > + * @separator: Separator used to separate list items > + * > + * Count the number of items in a list. The list items > + * are separated by a separator character inside the string. > + * Trailing white spaces are not allowed except if it is the separator. > + * > + * Return: > + * The item count. > + */ > +int count_items(const char *list, char separator) > +{ > + const char *c; > + int count = 0; > + > + if (!*list) > + return 0; > + > + for (c = list; *c; c++) { > + if (*c == separator) > + count++; > + } > + /* correct count if no trailing separator present */ > + if (*(c - 1) != separator) > + count++; > + > + return count; > +} > + > +/** > + * update_itemcount - update item count > + * @count: The count to be updated > + * @list: The item list > + * @separator: List separator > + * > + * Initialize the count if it is uninitialized (negative value). > + * Check that the list contains at least one item. > + * Check if an already initialized count is consistent with the list count. > + * > + * Return: > + * * 0 - on success > + * * -1 - if a check fails > + */ > +int update_itemcount(int *count, const char *list, char separator) > +{ > + int current_count = count_items(list, separator); > + > + if (*count < 0) > + *count = current_count; > + > + if (*count == 0 || > + *count != current_count) > + return -1; > + > + return 0; > +} > + > +/** > + * split_list - split list into elements > + * @elements: Pointer to string array > + * @size: The array size > + * @list: The item list > + * @separator: List separator > + * > + * Split a comma-separated list into its elements. > + * > + * Return: > + * * 0 - on success > + * * -1 - on failure > + */ > +int split_list(char **elements, int size, char *list, char separator) > +{ > + const char separator_str[] = {separator, '\0'}; > + char *end; > + > + for (int i = 0; i < size; i++) { > + elements[i] = strsep(&list, separator_str); > + if (!elements[i]) > + return -1; > + } > + > + end = strsep(&list, separator_str); /* NULL or empty string expected > */ > + if (end && *end) > + return -1; > + > + return 0; > +} > + > +/** > + * alloc_array - allocate memory for array > + * @count: The number of elements > + * @obj_size: The size of a single element > + * @name: The name of the array > + * > + * This is a wrapper for malloc which prints an error > + * message on failure. > + * > + * Return: > + * * Pointer to the allocated memory on success > + * * NULL on failure > + */ > +void *alloc_array(unsigned int count, size_t obj_size, const char *name) > +{ > + void *array; > + > + array = malloc(count * obj_size); > + if (!array) > + fprintf(stderr, "Could not allocate memory for %s\n", name); > + > + return array; > +} > + > +/** > + * init_guids - populate guid array > + * @elements: String array of elements to be converted > + * @size: The array size > + * @name: The name of the array > + * > + * Allocate and populate an array of guid structs. The list contains the > UUIDs > + * to convert and store in the array. Upon failure an error message is > + * printed. > + * > + * Return: > + * * The initialized GUID array on success > + * * NULL on failure > + */ > +efi_guid_t *init_guids(const char **elements, unsigned int size, > + const char *name) > +{ > + efi_guid_t *guids; > + > + guids = alloc_array(size, sizeof(efi_guid_t), name); > + if (!guids) > + return NULL; > + > + for (int i = 0; i < size; i++) { > + if (uuid_parse(elements[i], (unsigned char *)(guids + i))) { > + fprintf(stderr, "Wrong %s format\n", name); > + free(guids); > + return NULL; > + } > + convert_uuid_to_guid((unsigned char *)(guids + i)); > + } > + > + return guids; > +} > + > +/** > + * init_uls - populate unsigned long array > + * @elements: String array of elements to be converted > + * @size: The array size > + * @name: The name of the array > + * > + * Allocate and populate an array of unsgined longs. Upon failure an > + * error message is printed. > + * > + * Return: > + * * The initialized array on success > + * * NULL on failure > + */ > +unsigned long *init_uls(const char **elements, unsigned int size, > + const char *name) > +{ > + unsigned long *array; > + > + array = alloc_array(size, sizeof(unsigned long), name); > + if (!array) > + return NULL; > + for (int i = 0; i < size; i++) > + array[i] = strtoul(elements[i], NULL, 0); > + > + return array; > +} > + > +/** > + * init_list - parse list and allocate elements > + * @listcount: The list count to be checked and updated > + * @list: The list to be parsed > + * @separator: The list separator > + * @name: The name of the list > + * @multiple_times: List encountered multiple times > + * > + * Routine for command line argument lists. > + * Parse the string list and count the list elements. > + * Initialize the listcount if it is uninitialized (negative value). > + * Check that the list contains at least one item. > + * Check if an already initialized count is consistent with the list count. > + * Allocate the string array and populate it with the list elements. > + * The array should be freed in the calling function. > + * Upon failure an error message is printed and the program exits. > + * > + * Return: > + * * The initialized array on success > + * * NULL on failure > + */ > +char **init_list(int *listcount, char *list, char separator, > + bool multiple_times, char *name) > +{ > + char **elements; > + > + if (multiple_times) { > + fprintf(stderr, "%s specified multiple times\n", name); > + return NULL; > + } > + if (update_itemcount(listcount, list, separator)) { > + fprintf(stderr, "List count not consistent with previous or > list not provided\n"); > + return NULL; > + } > + elements = alloc_array(*listcount, sizeof(char *), name); > + if (!elements) > + return NULL; > + if (split_list(elements, *listcount, list, separator)) { > + fprintf(stderr, "Could not parse %s list\n", name); > + free(elements); > + return NULL; > + } > + > + return elements; > +} > + > /** > * main - main entry function of mkeficapsule > * @argc: Number of arguments > @@ -666,24 +912,27 @@ err: > */ > int main(int argc, char **argv) > { > - efi_guid_t *guid; > - unsigned char uuid_buf[16]; > - unsigned long index, instance; > - uint64_t mcount; > + const char separator = ','; > + const efi_guid_t *guids; /* an array */ > + const unsigned long *indices, *instances, *mcounts, *fw_versions; /* > arrays */ > unsigned long oemflags; > + const char **blob_paths, **elements; /* string arrays */ > const char *privkey_file, *cert_file; > - int c, idx; > - struct fmp_payload_header_params fmp_ph_params = { 0 }; > + int listcount, c, idx; > > - guid = NULL; > - index = 0; > - instance = 0; > - mcount = 0; > + guids = NULL; > + indices = NULL; > + instances = NULL; > + mcounts = NULL; > + oemflags = 0; > + blob_paths = NULL; > privkey_file = NULL; > cert_file = NULL; > + elements = NULL; > + listcount = -1; > + fw_versions = NULL; > dump_sig = 0; > capsule_type = CAPSULE_NORMAL_BLOB; > - oemflags = 0; > for (;;) { > c = getopt_long(argc, argv, opts_short, options, &idx); > if (c == -1) > @@ -691,27 +940,62 @@ int main(int argc, char **argv) > > switch (c) { > case 'g': > - if (guid) { > - fprintf(stderr, > - "Image type already specified\n"); > + elements = (const char **)init_list(&listcount, > optarg, separator, !!guids, > + "GUID"); > + if (!elements) > exit(EXIT_FAILURE); > - } > - if (uuid_parse(optarg, uuid_buf)) { > - fprintf(stderr, "Wrong guid format\n"); > + > + guids = init_guids(elements, listcount, "GUID"); > + if (!guids) > exit(EXIT_FAILURE); > - } > - convert_uuid_to_guid(uuid_buf); > - guid = (efi_guid_t *)uuid_buf; > + > + free(elements); > + elements = NULL; > break; > case 'i': > - index = strtoul(optarg, NULL, 0); > + elements = (const char **)init_list(&listcount, > optarg, separator, > + !!indices, > "index"); > + if (!elements) > + exit(EXIT_FAILURE); > + > + indices = init_uls(elements, listcount, "index"); > + if (!indices) > + exit(EXIT_FAILURE); > + > + free(elements); > + elements = NULL; > + break; > + case 'b': > + blob_paths = (const char **)init_list(&listcount, > optarg, separator, > + !!blob_paths, > "blob path"); > + if (!blob_paths) > + exit(EXIT_FAILURE); > break; > case 'I': > - instance = strtoul(optarg, NULL, 0); > + elements = (const char **)init_list(&listcount, > optarg, separator, > + !!instances, > "instance"); > + if (!elements) > + exit(EXIT_FAILURE); > + > + instances = init_uls(elements, listcount, "instance"); > + if (!instances) > + exit(EXIT_FAILURE); > + > + free(elements); > + elements = NULL; > break; > case 'v': > - fmp_ph_params.fw_version = strtoul(optarg, NULL, 0); > - fmp_ph_params.have_header = true; > + elements = (const char **)init_list(&listcount, > optarg, separator, > + !!fw_versions, > "firmware version"); > + if (!elements) > + exit(EXIT_FAILURE); > + > + fw_versions = init_uls(elements, listcount, "firmware > version"); > + if (!fw_versions) > + exit(EXIT_FAILURE); > + > + free(elements); > + elements = NULL; > break; > case 'p': > if (privkey_file) { > @@ -730,7 +1014,17 @@ int main(int argc, char **argv) > cert_file = optarg; > break; > case 'm': > - mcount = strtoul(optarg, NULL, 0); > + elements = (const char **)init_list(&listcount, > optarg, separator, > + !!mcounts, > "monotonic count"); > + if (!elements) > + exit(EXIT_FAILURE); > + > + mcounts = init_uls(elements, listcount, "monotonic > count"); > + if (!mcounts) > + exit(EXIT_FAILURE); > + > + free(elements); > + elements = NULL; > break; > case 'd': > dump_sig = 1; > @@ -767,26 +1061,46 @@ 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)))) || > + (!((argc != optind + 2) ^ !(blob_paths && argc == optind + 1)) > || !guids || > + ((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)))) { > + ((argc != optind + 1) || > + ((capsule_type == CAPSULE_ACCEPT) && !guids) || > + ((capsule_type == CAPSULE_ACCEPT) && listcount != 1) || > + ((capsule_type == CAPSULE_REVERT) && guids)))) { > print_usage(); > exit(EXIT_FAILURE); > } > > + /* populate blob_paths if image blob was provided as positional > argument */ > + if (capsule_type == CAPSULE_NORMAL_BLOB && !blob_paths) { > + blob_paths = malloc(sizeof(char *)); > + if (!blob_paths) { > + fprintf(stderr, "Could not allocate memory for blob > paths\n"); > + exit(EXIT_FAILURE); > + } > + *blob_paths = argv[argc - 2]; > + } > + > + /* populate arrays with zeros if they are not provided */ > + if (!indices) > + indices = calloc(listcount, sizeof(unsigned long)); > + if (!instances) > + instances = calloc(listcount, sizeof(unsigned long)); > + if (!mcounts) > + mcounts = calloc(listcount, sizeof(uint64_t)); > + > if (capsule_type != CAPSULE_NORMAL_BLOB) { > - if (create_empty_capsule(argv[argc - 1], guid, > + if (create_empty_capsule(argv[argc - 1], guids, > capsule_type == CAPSULE_ACCEPT) < 0) > { > fprintf(stderr, "Creating empty capsule failed\n"); > exit(EXIT_FAILURE); > } > - } else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, > - index, instance, &fmp_ph_params, mcount, > privkey_file, > - cert_file, (uint16_t)oemflags) < 0) { > + } else if (create_fwbin(argv[argc - 1], blob_paths, guids, > + indices, instances, fw_versions, > + mcounts, listcount, privkey_file, > + cert_file, (uint16_t)oemflags) < 0) { > fprintf(stderr, "Creating firmware capsule failed\n"); > exit(EXIT_FAILURE); > } > -- > 2.30.2 >