
On 29.05.2024 16:48, Caleb Connolly wrote:
Add a tool that can generate GUIDs that match those generated internally by U-Boot for capsule update fw_images.
Dynamic UUIDs in U-Boot work by taking a namespace UUID and hashing it with the board model, compatible, and fw_image name.
This tool accepts the same inputs and will produce the same GUID as U-Boot would at runtime.
Signed-off-by: Caleb Connolly caleb.connolly@linaro.org
tools/Makefile | 3 ++ tools/genguid.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+)
diff --git a/tools/Makefile b/tools/Makefile index 6a4280e3668f..7db7723793d5 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -253,8 +253,11 @@ HOSTLDLIBS_mkeficapsule += \ HOSTLDLIBS_mkeficapsule += \ $(shell pkg-config --libs uuid 2> /dev/null || echo "-luuid") hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
+genguid-objs := generated/lib/uuid.o generated/lib/sha1.o genguid.o +hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += genguid
mkfwumdata-objs := mkfwumdata.o generated/lib/crc32.o HOSTLDLIBS_mkfwumdata += -luuid hostprogs-$(CONFIG_TOOLS_MKFWUMDATA) += mkfwumdata
diff --git a/tools/genguid.c b/tools/genguid.c new file mode 100644 index 000000000000..dbac65d42623 --- /dev/null +++ b/tools/genguid.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright 2024 Linaro Ltd.
- Author: Caleb Connolly
- */
+#include <getopt.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <linux/types.h>
+#include <uuid.h>
+static struct option options[] = {
- {"dtb", required_argument, NULL, 'd'},
- {"compat", required_argument, NULL, 'c'},
- {"help", no_argument, NULL, 'h'},
- {"verbose", no_argument, NULL, 'v'},
- {"json", no_argument, NULL, 'j'},
- {NULL, 0, NULL, 0},
+};
+static void usage(const char *progname) +{
- fprintf(stderr, "Usage: %s GUID [-v] -c COMPAT NAME...\n", progname);
- fprintf(stderr,
"Generate a v5 GUID for one of more U-Boot fw_images the same way U-Boot does at runtime.\n");
- fprintf(stderr,
"\nOptions:\n"
" GUID namespace/salt GUID in 8-4-4-4-12 format\n"
" -h, --help display this help and exit\n"
" -c, --compat=COMPAT first compatible property in the board devicetree\n"
" -v, --verbose print debug messages\n"
" -j, --json output in JSON format\n"
" NAME... one or more names of fw_images to generate GUIDs for\n"
- );
- fprintf(stderr, "\nExample:\n");
- fprintf(stderr, " %s 2a5aa852-b856-4d97-baa9-5c5f4421551f \\n"
"\t-c \"qcom,qrb4210-rb2\" \\\n"
"\tQUALCOMM-UBOOT\n", progname);
+}
+size_t u16_strsize(const uint16_t *in) +{
- size_t i = 0, count = UINT16_MAX;
- while (count-- && in[i])
i++;
- return (i + 1) * sizeof(uint16_t);
+}
Hi Caleb,
Consistency-wise, unless you wanted this function (`u16_strsize`) non-static, it would be more consistent to make it static, like the `usage` function.
Otherwise LGTM.
+int main(int argc, char **argv) +{
- struct uuid namespace;
- char *namespace_str;
- char uuid_str[37];
- char **image_uuids;
- char *compatible = NULL;
- uint16_t **images_u16;
- char **images;
- int c, n_images;
- bool debug = false, json = false;
- if (argc < 2) {
usage(argv[0]);
return 1;
- }
- namespace_str = argv[1];
- /* The first arg is the GUID so skip it */
- while ((c = getopt_long(argc, argv, "c:hvj", options, NULL)) != -1) {
switch (c) {
case 'c':
compatible = strdup(optarg);
break;
case 'h':
usage(argv[0]);
return 0;
case 'v':
debug = true;
break;
case 'j':
json = true;
break;
default:
usage(argv[0]);
return 1;
}
- }
- if (!compatible) {
fprintf(stderr, "ERROR: Please specify the compatible property.\n\n");
usage(argv[0]);
return 1;
- }
- if (uuid_str_to_bin(namespace_str, (unsigned char *)&namespace, UUID_STR_FORMAT_GUID)) {
fprintf(stderr, "ERROR: Check that your UUID is formatted correctly.\n");
exit(EXIT_FAILURE);
- }
- /* This is probably not the best way to convert a string to a "u16" string */
- n_images = argc - optind - 1;
- images = argv + optind + 1;
- images_u16 = calloc(n_images, sizeof(char *));
- for (int i = 0; i < n_images; i++) {
images_u16[i] = calloc(1, strlen(images[i]) * 2 + 2);
for (int j = 0; j < strlen(images[i]); j++)
images_u16[i][j] = (uint16_t)images[i][j];
- }
- if (debug) {
fprintf(stderr, "GUID: ");
uuid_bin_to_str((uint8_t *)&namespace, uuid_str, UUID_STR_FORMAT_GUID);
fprintf(stderr, "%s\n", uuid_str);
fprintf(stderr, "Compatible: \"%s\"\n", compatible);
fprintf(stderr, "Images: ");
for (int i = 0; i < n_images; i++)
fprintf(stderr, "\"%s\"%s", argv[optind + i + 1],
i == n_images - 1 ? "\n" : ", ");
- }
- image_uuids = calloc(n_images, sizeof(char *));
- for (int i = 0; i < n_images; i++) {
struct uuid image_type_id;
gen_uuid_v5(&namespace, &image_type_id,
compatible, strlen(compatible),
images_u16[i], u16_strsize(images_u16[i]) - sizeof(uint16_t),
NULL);
uuid_bin_to_str((uint8_t *)&image_type_id, uuid_str, UUID_STR_FORMAT_GUID);
image_uuids[i] = strdup(uuid_str);
- }
- if (json) {
printf("[\n");
for (int i = 0; i < n_images; i++)
printf("\t{\"name\": \"%s\", \"uuid\": \"%s\"}%s\n", images[i], image_uuids[i],
i == n_images - 1 ? "" : ",");
printf("]\n");
- } else {
for (int i = 0; i < n_images; i++)
printf("%-24s| %s\n", images[i], image_uuids[i]);
- }
- return 0;
+}
-- 2.45.0
Best wishes, -- Dom Rodriguez GPG Fingerprint: EB0D 45E6 D0DC 1BA1 A2B5 FC24 72DC F123 1E54 BD43