Message ID | 20240529-b4-dynamic-uuid-v2-6-c26f31057bbe@linaro.org |
---|---|
State | New |
Headers | show |
Series | efi: CapsuleUpdate: support for dynamic UUIDs | expand |
Hi Caleb, On Wed, 29 May 2024 at 08:49, Caleb Connolly <caleb.connolly@linaro.org> 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(+) Where is this tool used? Can you add a man page and test? Regards, Simon
Hi Simon, On 29/05/2024 18:30, Simon Glass wrote: > Hi Caleb, > > On Wed, 29 May 2024 at 08:49, Caleb Connolly <caleb.connolly@linaro.org> 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(+) > > Where is this tool used? Can you add a man page and test? It currently doesn't have any users, it just allows for pre-generating GUIDs ahead of time for a given board. It might be hooked up to vendor tooling or some usecase like that. I've somehow escaped learning Groff before now heh, I can give it a go and write a test. > > Regards, > Simon
Hi Caleb, On Wed, 29 May 2024 at 13:02, Caleb Connolly <caleb.connolly@linaro.org> wrote: > > Hi Simon, > > On 29/05/2024 18:30, Simon Glass wrote: > > Hi Caleb, > > > > On Wed, 29 May 2024 at 08:49, Caleb Connolly <caleb.connolly@linaro.org> 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(+) > > > > Where is this tool used? Can you add a man page and test? > > It currently doesn't have any users, it just allows for pre-generating > GUIDs ahead of time for a given board. It might be hooked up to vendor > tooling or some usecase like that. > > I've somehow escaped learning Groff before now heh, I can give it a go > and write a test. OK (just copy bits of mkimage.1 :-) Re the test, would this be something that binman would use? If so you could put a test there. Regards, Simon
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
Hi Simon, On 29/05/2024 21:45, Simon Glass wrote: > Hi Caleb, > > On Wed, 29 May 2024 at 13:02, Caleb Connolly <caleb.connolly@linaro.org> wrote: >> >> Hi Simon, >> >> On 29/05/2024 18:30, Simon Glass wrote: >>> Hi Caleb, >>> >>> On Wed, 29 May 2024 at 08:49, Caleb Connolly <caleb.connolly@linaro.org> 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(+) >>> >>> Where is this tool used? Can you add a man page and test? >> >> It currently doesn't have any users, it just allows for pre-generating >> GUIDs ahead of time for a given board. It might be hooked up to vendor >> tooling or some usecase like that. >> >> I've somehow escaped learning Groff before now heh, I can give it a go >> and write a test. > > OK (just copy bits of mkimage.1 :-) Right :D > > Re the test, would this be something that binman would use? If so you > could put a test there. This tool is just a wrapper for gen_uuid_v5() which we already test in the dynamic UUID unit tests also introduced in this series. I don't think it's necessary to additionally test this tool. Kind regards, > > Regards, > Simon
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); +} + +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; +} +
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(+)