]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
tools: mkeficapsule: support generating dynamic GUIDs
authorCaleb Connolly <caleb.connolly@linaro.org>
Fri, 30 Aug 2024 12:34:39 +0000 (13:34 +0100)
committerHeinrich Schuchardt <heinrich.schuchardt@canonical.com>
Thu, 12 Sep 2024 15:35:37 +0000 (17:35 +0200)
Add support for generating GUIDs that match those generated internally
by U-Boot for capsule update fw_images when using dynamic UUIDs.

Dynamic UUIDs in U-Boot work by taking a namespace UUID and hashing it
with the board compatible and fw_image name. This feature just provides
a way to determine the UUIDs for a particular board without having to
actually boot U-Boot on it.

Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
doc/mkeficapsule.1
tools/mkeficapsule.c

index c3d0f21488ad7065e5b5e1ece592619b5f08c117..a5545f7898a8f3c0e5e83accacfa2df56fb522ee 100644 (file)
@@ -10,6 +10,9 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
 .B mkeficapsule
 .RI [ options ] " " [ image-blob ] " " capsule-file
 
+.B mkeficapsule
+.RI guidgen " " [ GUID ] " " DTB " " IMAGE_NAME...
+
 .SH "DESCRIPTION"
 The
 .B mkeficapsule
@@ -42,6 +45,10 @@ multiple binary blobs in a single capsule file.
 This type of image file can be generated by
 .BR mkimage .
 
+mkeficapsule can also be used to simulate the dynamic GUID generation used to
+identify firmware images in capsule updates by providing the namespace guid, dtb
+for the board, and a list of firmware images.
+
 .SH "OPTIONS"
 
 .TP
@@ -117,6 +124,22 @@ at every firmware update.
 .B "-d\fR,\fB --dump_sig"
 Dump signature data into *.p7 file
 
+.SH "GUIDGEN OPTIONS"
+
+.TP
+.B "[GUID]"
+The namespace/salt GUID, by default this is EFI_CAPSULE_NAMESPACE_GUID.
+The format is:
+    xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+
+.TP
+.B DTB
+The device tree blob file for the board.
+
+.TP
+.B IMAGE_NAME...
+The names of the firmware images to generate GUIDs for.
+
 .PP
 .SH FILES
 .TP
index ede9de2bef799e22cb1e2a1dbe5a086a521f337c..49f5b7849e48f2fdcf3c2238ac1fe7163a5e6ea4 100644 (file)
 #include <gnutls/abstract.h>
 
 #include <version.h>
+#include <libfdt.h>
 #include <u-boot/uuid.h>
 
 #include "eficapsule.h"
 
+// Matches CONFIG_EFI_CAPSULE_NAMESPACE_GUID
+#define DEFAULT_NAMESPACE_GUID "8c9f137e-91dc-427b-b2d6-b420faebaf2a"
+
 static const char *tool_name = "mkeficapsule";
 
 efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
@@ -56,9 +60,20 @@ static struct option options[] = {
        {NULL, 0, NULL, 0},
 };
 
-static void print_usage(void)
+static void print_usage_guidgen(void)
+{
+       fprintf(stderr, "%s guidgen [GUID] DTB IMAGE_NAME...\n"
+               "Options:\n"
+
+               "\tGUID                        Namespace GUID (default: %s)\n"
+               "\tDTB                         Device Tree Blob\n"
+               "\tIMAGE_NAME...               One or more names of fw_images to generate GUIDs for\n",
+               tool_name, DEFAULT_NAMESPACE_GUID);
+}
+
+static void print_usage_mkeficapsule(void)
 {
-       fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
+       fprintf(stderr, "Usage:\n\n%s [options] <image blob> <output file>\n"
                "Options:\n"
 
                "\t-g, --guid <guid string>    guid for image blob type\n"
@@ -74,8 +89,9 @@ static void print_usage(void)
                "\t-o, --capoemflag Capsule OEM Flag, an integer between 0x0000 and 0xffff\n"
                "\t-D, --dump-capsule          dump the contents of the capsule headers\n"
                "\t-V, --version               show version number\n"
-               "\t-h, --help                  print a help message\n",
+               "\t-h, --help                  print a help message\n\n",
                tool_name);
+       print_usage_guidgen();
 }
 
 /**
@@ -820,6 +836,129 @@ static void dump_capsule_contents(char *capsule_file)
        }
 }
 
+static struct fdt_header *load_dtb(const char *path)
+{
+       struct fdt_header *dtb;
+       ssize_t dtb_size;
+       FILE *f;
+
+       /* Open and parse DTB */
+       f = fopen(path, "r");
+       if (!f) {
+               fprintf(stderr, "Cannot open %s\n", path);
+               return NULL;
+       }
+
+       if (fseek(f, 0, SEEK_END)) {
+               fprintf(stderr, "Cannot seek to the end of %s: %s\n",
+                       path, strerror(errno));
+               return NULL;
+       }
+
+       dtb_size = ftell(f);
+       if (dtb_size < 0) {
+               fprintf(stderr, "Cannot ftell %s: %s\n",
+                       path, strerror(errno));
+               return NULL;
+       }
+
+       fseek(f, 0, SEEK_SET);
+
+       dtb = malloc(dtb_size);
+       if (!dtb) {
+               fprintf(stderr, "Can't allocated %ld\n", dtb_size);
+               return NULL;
+       }
+
+       if (fread(dtb, dtb_size, 1, f) != 1) {
+               fprintf(stderr, "Can't read %ld bytes from %s\n",
+                       dtb_size, path);
+               free(dtb);
+               return NULL;
+       }
+
+       fclose(f);
+
+       return dtb;
+}
+
+#define MAX_IMAGE_NAME_LEN 128
+static int genguid(int argc, char **argv)
+{
+       int idx = 2, ret;
+       unsigned char namespace[16];
+       struct efi_guid image_type_id;
+       const char *dtb_path;
+       struct fdt_header *dtb;
+       const char *compatible;
+       int compatlen, namelen;
+       uint16_t fw_image[MAX_IMAGE_NAME_LEN];
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage: ");
+               print_usage_guidgen();
+               return -1;
+       }
+
+       if (uuid_str_to_bin(argv[1], namespace, UUID_STR_FORMAT_GUID)) {
+               uuid_str_to_bin(DEFAULT_NAMESPACE_GUID, namespace, UUID_STR_FORMAT_GUID);
+               dtb_path = argv[1];
+       } else {
+               dtb_path = argv[2];
+               idx = 3;
+       }
+
+       if (idx == argc) {
+               fprintf(stderr, "Usage: ");
+               print_usage_guidgen();
+               return -1;
+       }
+
+       dtb = load_dtb(dtb_path);
+       if (!dtb)
+               return -1;
+
+       ret = fdt_check_header(dtb);
+       if (ret) {
+               fprintf(stderr, "Invalid DTB header: %d\n", ret);
+               return -1;
+       }
+
+       compatible = fdt_getprop(dtb, 0, "compatible", &compatlen);
+       if (!compatible) {
+               fprintf(stderr, "No compatible string found in DTB\n");
+               return -1;
+       }
+       if (strnlen(compatible, compatlen) >= compatlen) {
+               fprintf(stderr, "Compatible string not null-terminated\n");
+               return -1;
+       }
+
+       printf("Generating GUIDs for %s with namespace %s:\n",
+              compatible, DEFAULT_NAMESPACE_GUID);
+       for (; idx < argc; idx++) {
+               memset(fw_image, 0, sizeof(fw_image));
+               namelen = strlen(argv[idx]);
+               if (namelen > MAX_IMAGE_NAME_LEN) {
+                       fprintf(stderr, "Image name too long: %s\n", argv[idx]);
+                       return -1;
+               }
+
+               for (int i = 0; i < namelen; i++)
+                       fw_image[i] = (uint16_t)argv[idx][i];
+
+               gen_v5_guid((struct uuid *)&namespace, &image_type_id,
+                           compatible, strlen(compatible),
+                           fw_image, namelen * sizeof(uint16_t),
+                           NULL);
+
+               printf("%s: ", argv[idx]);
+               print_guid(&image_type_id);
+       }
+
+       return 0;
+}
+
 /**
  * main - main entry function of mkeficapsule
  * @argc:      Number of arguments
@@ -844,6 +983,13 @@ int main(int argc, char **argv)
        int c, idx;
        struct fmp_payload_header_params fmp_ph_params = { 0 };
 
+       /* Generate dynamic GUIDs */
+       if (argc > 1 && !strcmp(argv[1], "guidgen")) {
+               if (genguid(argc - 1, argv + 1))
+                       exit(EXIT_FAILURE);
+               exit(EXIT_SUCCESS);
+       }
+
        guid = NULL;
        index = 0;
        instance = 0;
@@ -935,7 +1081,7 @@ int main(int argc, char **argv)
                        printf("mkeficapsule version %s\n", PLAIN_VERSION);
                        exit(EXIT_SUCCESS);
                default:
-                       print_usage();
+                       print_usage_mkeficapsule();
                        exit(EXIT_FAILURE);
                }
        }
@@ -958,7 +1104,7 @@ int main(int argc, char **argv)
            ((argc != optind + 1) ||
             ((capsule_type == CAPSULE_ACCEPT) && !guid) ||
             ((capsule_type == CAPSULE_REVERT) && guid)))) {
-               print_usage();
+               print_usage_mkeficapsule();
                exit(EXIT_FAILURE);
        }