When loading a device tree using the "mach dtb" command, give firmware
authorkettenis <kettenis@openbsd.org>
Mon, 17 Jun 2024 09:12:45 +0000 (09:12 +0000)
committerkettenis <kettenis@openbsd.org>
Mon, 17 Jun 2024 09:12:45 +0000 (09:12 +0000)
a chance to make modifications (such as applying memory reservations)
by using the EFI devicetree fixup protocol.

ok jca@

sys/arch/armv7/stand/efiboot/conf.c
sys/arch/armv7/stand/efiboot/efiboot.c
sys/arch/armv7/stand/efiboot/efidt.h [new file with mode: 0644]
sys/arch/riscv64/stand/efiboot/conf.c
sys/arch/riscv64/stand/efiboot/efiboot.c
sys/arch/riscv64/stand/efiboot/efidt.h [new file with mode: 0644]

index de536fb..4143b4f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.35 2024/03/10 15:37:54 kettenis Exp $      */
+/*     $OpenBSD: conf.c,v 1.36 2024/06/17 09:12:45 kettenis Exp $      */
 
 /*
  * Copyright (c) 1996 Michael Shalayeff
@@ -42,7 +42,7 @@
 #include "efidev.h"
 #include "efipxe.h"
 
-const char version[] = "1.22";
+const char version[] = "1.23";
 int    debug = 0;
 
 struct fs_ops file_system[] = {
index c6bf950..0e5ac7d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: efiboot.c,v 1.40 2022/12/22 15:44:02 kettenis Exp $   */
+/*     $OpenBSD: efiboot.c,v 1.41 2024/06/17 09:12:45 kettenis Exp $   */
 
 /*
  * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -36,6 +36,7 @@
 
 #include "efidev.h"
 #include "efiboot.h"
+#include "efidt.h"
 #include "fdt.h"
 
 EFI_SYSTEM_TABLE       *ST;
@@ -59,6 +60,7 @@ static EFI_GUID                blkio_guid = BLOCK_IO_PROTOCOL;
 static EFI_GUID                 devp_guid = DEVICE_PATH_PROTOCOL;
 static EFI_GUID                 gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
 static EFI_GUID                 fdt_guid = FDT_TABLE_GUID;
+static EFI_GUID                 dt_fixup_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
 
 #define efi_guidcmp(_a, _b)    memcmp((_a), (_b), sizeof(EFI_GUID))
 
@@ -1004,12 +1006,18 @@ efi_fdt(void)
        return fdt_sys;
 }
 
+#define EXTRA_DT_SPACE (32 * 1024)
+
 int
 fdt_load_override(char *file)
 {
+       EFI_DT_FIXUP_PROTOCOL *dt_fixup;
        EFI_PHYSICAL_ADDRESS addr;
        char path[MAXPATHLEN];
+       EFI_STATUS status;
        struct stat sb;
+       size_t dt_size;
+       UINTN sz;
        int fd;
 
        if (file == NULL && fdt_override) {
@@ -1027,7 +1035,8 @@ fdt_load_override(char *file)
                printf("cannot open %s\n", path);
                return 0;
        }
-       if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size),
+       dt_size = sb.st_size + EXTRA_DT_SPACE;
+       if (efi_memprobe_find(EFI_SIZE_TO_PAGES(dt_size),
            PAGE_SIZE, EfiLoaderData, &addr) != EFI_SUCCESS) {
                printf("cannot allocate memory for %s\n", path);
                return 0;
@@ -1037,9 +1046,18 @@ fdt_load_override(char *file)
                return 0;
        }
 
+       status = BS->LocateProtocol(&dt_fixup_guid, NULL, (void **)&dt_fixup);
+       if (status == EFI_SUCCESS) {
+               sz = dt_size;
+               status = dt_fixup->Fixup(dt_fixup, (void *)addr, &sz,
+                   EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
+               if (status != EFI_SUCCESS)
+                       panic("DT fixup failed: 0x%lx", status);
+       }
+
        if (!fdt_init((void *)addr)) {
                printf("invalid device tree\n");
-               BS->FreePages(addr, EFI_SIZE_TO_PAGES(sb.st_size));
+               BS->FreePages(addr, EFI_SIZE_TO_PAGES(dt_size));
                return 0;
        }
 
@@ -1050,7 +1068,7 @@ fdt_load_override(char *file)
        }
 
        fdt_override = (void *)addr;
-       fdt_override_size = sb.st_size;
+       fdt_override_size = dt_size;
        return 0;
 }
 
diff --git a/sys/arch/armv7/stand/efiboot/efidt.h b/sys/arch/armv7/stand/efiboot/efidt.h
new file mode 100644 (file)
index 0000000..8a2ab0d
--- /dev/null
@@ -0,0 +1,44 @@
+/*     $OpenBSD: efidt.h,v 1.1 2024/06/17 09:12:45 kettenis Exp $      */
+
+/*
+ * Copyright (c) 2024 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+
+#include <efi.h>
+#include <efiapi.h>
+
+#define EFI_DT_FIXUP_PROTOCOL_GUID             \
+  { 0xe617d64c, 0xfe08, 0x46da, \
+    { 0xf4, 0xdc, 0xbb, 0xd5, 0x87, 0x0c, 0x73, 0x00 } }
+
+INTERFACE_DECL(_EFI_DT_FIXUP_PROTOCOL);
+
+typedef EFI_STATUS
+(EFIAPI *EFI_DT_FIXUP) (
+    IN struct _EFI_DT_FIXUP_PROTOCOL   *This,
+    IN VOID                            *Fdt,
+    IN OUT UINTN                       *BufferSize,
+    IN UINT32                          Flags
+    );
+
+#define EFI_DT_APPLY_FIXUPS    0x00000001
+#define EFI_DT_RESERVE_MEMORY  0x00000002
+
+typedef struct _EFI_DT_FIXUP_PROTOCOL {
+       UINT64                  Revision;
+       EFI_DT_FIXUP            Fixup;
+} EFI_DT_FIXUP_PROTOCOL;
index 3396162..2e1985e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.3 2024/03/26 22:26:04 kettenis Exp $       */
+/*     $OpenBSD: conf.c,v 1.4 2024/06/17 09:12:45 kettenis Exp $       */
 
 /*
  * Copyright (c) 1996 Michael Shalayeff
@@ -46,7 +46,7 @@
 #include "efipxe.h"
 #include "softraid_riscv64.h"
 
-const char version[] = "1.6";
+const char version[] = "1.7";
 int    debug = 0;
 
 struct fs_ops file_system[] = {
index 38321fe..ba319d6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: efiboot.c,v 1.7 2024/03/26 22:26:04 kettenis Exp $    */
+/*     $OpenBSD: efiboot.c,v 1.8 2024/06/17 09:12:45 kettenis Exp $    */
 
 /*
  * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
 
 #include "efidev.h"
 #include "efiboot.h"
+#include "efidt.h"
 #include "fdt.h"
 
 EFI_SYSTEM_TABLE       *ST;
 EFI_BOOT_SERVICES      *BS;
 EFI_RUNTIME_SERVICES   *RS;
 EFI_HANDLE              IH, efi_bootdp;
+void                   *fdt_sys = NULL;
+void                   *fdt_override = NULL;
+size_t                  fdt_override_size;
 
 EFI_PHYSICAL_ADDRESS    heap;
 UINTN                   heapsiz = 1 * 1024 * 1024;
@@ -60,6 +64,10 @@ static EFI_GUID               imgp_guid = LOADED_IMAGE_PROTOCOL;
 static EFI_GUID                 blkio_guid = BLOCK_IO_PROTOCOL;
 static EFI_GUID                 devp_guid = DEVICE_PATH_PROTOCOL;
 static EFI_GUID                 gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+static EFI_GUID                 fdt_guid = FDT_TABLE_GUID;
+static EFI_GUID                 dt_fixup_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
+
+#define efi_guidcmp(_a, _b)    memcmp((_a), (_b), sizeof(EFI_GUID))
 
 int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
 int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
@@ -68,6 +76,8 @@ static void efi_memprobe_internal(void);
 static void efi_timer_init(void);
 static void efi_timer_cleanup(void);
 static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *);
+void *efi_fdt(void);
+int fdt_load_override(char *);
 
 EFI_STATUS
 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
@@ -76,6 +86,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
        EFI_LOADED_IMAGE        *imgp;
        EFI_DEVICE_PATH         *dp = NULL;
        EFI_STATUS               status;
+       int                      i;
 
        ST = systab;
        BS = ST->BootServices;
@@ -93,6 +104,13 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
        if (status == EFI_SUCCESS)
                efi_bootdp = dp;
 
+       for (i = 0; i < ST->NumberOfTableEntries; i++) {
+               if (efi_guidcmp(&fdt_guid,
+                   &ST->ConfigurationTable[i].VendorGuid) == 0)
+                       fdt_sys = ST->ConfigurationTable[i].VendorTable;
+       }
+       fdt_init(fdt_sys);
+
        progname = "BOOTRISCV64";
 
        boot(0);
@@ -478,11 +496,7 @@ efi_dma_constraint(void)
            dma_constraint, sizeof(dma_constraint));
 }
 
-void *fdt = NULL;
 char *bootmac = NULL;
-static EFI_GUID fdt_guid = FDT_TABLE_GUID;
-
-#define        efi_guidcmp(_a, _b)     memcmp((_a), (_b), sizeof(EFI_GUID))
 
 void *
 efi_makebootargs(char *bootargs, int howto)
@@ -494,17 +508,12 @@ efi_makebootargs(char *bootargs, int howto)
        uint32_t boothowto = htobe32(howto);
        int32_t hartid;
        EFI_PHYSICAL_ADDRESS addr;
-       void *node;
+       void *node, *fdt;
        size_t len;
-       int i;
 
-       if (fdt == NULL) {
-               for (i = 0; i < ST->NumberOfTableEntries; i++) {
-                       if (efi_guidcmp(&fdt_guid,
-                           &ST->ConfigurationTable[i].VendorGuid) == 0)
-                               fdt = ST->ConfigurationTable[i].VendorTable;
-               }
-       }
+       fdt = efi_fdt();
+       if (fdt == NULL)
+               return NULL;
 
        if (!fdt_get_size(fdt))
                return NULL;
@@ -520,10 +529,15 @@ efi_makebootargs(char *bootargs, int howto)
        if (!fdt_init(fdt))
                return NULL;
 
+       /* Create common nodes which might not exist when using mach dtb */
+       node = fdt_find_node("/aliases");
+       if (node == NULL)
+               fdt_node_add_node(fdt_find_node("/"), "aliases", &node);
        node = fdt_find_node("/chosen");
-       if (!node)
-               return NULL;
+       if (node == NULL)
+               fdt_node_add_node(fdt_find_node("/"), "chosen", &node);
 
+       node = fdt_find_node("/chosen");
        hartid = efi_get_boot_hart_id();
        if (hartid >= 0) {
                hartid = htobe32(hartid);
@@ -960,53 +974,111 @@ efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr)
        return EFI_OUT_OF_RESOURCES;
 }
 
-/*
- * Commands
- */
+void *
+efi_fdt(void)
+{
+       /* 'mach dtb' has precedence */
+       if (fdt_override != NULL)
+               return fdt_override;
 
-int Xdtb_efi(void);
-int Xexit_efi(void);
-int Xpoweroff_efi(void);
+       return fdt_sys;
+}
 
-const struct cmd_table cmd_machine[] = {
-       { "dtb",        CMDT_CMD, Xdtb_efi },
-       { "exit",       CMDT_CMD, Xexit_efi },
-       { "poweroff",   CMDT_CMD, Xpoweroff_efi },
-       { NULL, 0 }
-};
+#define EXTRA_DT_SPACE (32 * 1024)
 
 int
-Xdtb_efi(void)
+fdt_load_override(char *file)
 {
+       EFI_DT_FIXUP_PROTOCOL *dt_fixup;
        EFI_PHYSICAL_ADDRESS addr;
        char path[MAXPATHLEN];
+       EFI_STATUS status;
        struct stat sb;
+       size_t dt_size;
+       UINTN sz;
        int fd;
 
-       if (cmd.argc != 2) {
-               printf("dtb file\n");
-               return (0);
+       if (file == NULL && fdt_override) {
+               BS->FreePages((uint64_t)fdt_override,
+                   EFI_SIZE_TO_PAGES(fdt_override_size));
+               fdt_override = NULL;
+               fdt_init(fdt_sys);
+               return 0;
        }
 
-       snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, cmd.argv[1]);
+       snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, file);
 
        fd = open(path, O_RDONLY);
        if (fd < 0 || fstat(fd, &sb) == -1) {
                printf("cannot open %s\n", path);
-               return (0);
+               return 0;
        }
-       if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size),
-           0x1000, &addr) != EFI_SUCCESS) {
+       dt_size = sb.st_size + EXTRA_DT_SPACE;
+       if (efi_memprobe_find(EFI_SIZE_TO_PAGES(dt_size),
+           PAGE_SIZE, &addr) != EFI_SUCCESS) {
                printf("cannot allocate memory for %s\n", path);
-               return (0);
+               return 0;
        }
        if (read(fd, (void *)addr, sb.st_size) != sb.st_size) {
                printf("cannot read from %s\n", path);
+               return 0;
+       }
+
+       status = BS->LocateProtocol(&dt_fixup_guid, NULL, (void **)&dt_fixup);
+       if (status == EFI_SUCCESS) {
+               sz = dt_size;
+               status = dt_fixup->Fixup(dt_fixup, (void *)addr, &sz,
+                   EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
+               if (status != EFI_SUCCESS)
+                       panic("DT fixup failed: 0x%lx", status);
+       }
+
+       if (!fdt_init((void *)addr)) {
+               printf("invalid device tree\n");
+               BS->FreePages(addr, EFI_SIZE_TO_PAGES(dt_size));
+               return 0;
+       }
+
+       if (fdt_override) {
+               BS->FreePages((uint64_t)fdt_override,
+                   EFI_SIZE_TO_PAGES(fdt_override_size));
+               fdt_override = NULL;
+       }
+
+       fdt_override = (void *)addr;
+       fdt_override_size = dt_size;
+       return 0;
+}
+
+/*
+ * Commands
+ */
+
+int Xdtb_efi(void);
+int Xexit_efi(void);
+int Xpoweroff_efi(void);
+
+const struct cmd_table cmd_machine[] = {
+       { "dtb",        CMDT_CMD, Xdtb_efi },
+       { "exit",       CMDT_CMD, Xexit_efi },
+       { "poweroff",   CMDT_CMD, Xpoweroff_efi },
+       { NULL, 0 }
+};
+
+int
+Xdtb_efi(void)
+{
+       if (cmd.argc == 1) {
+               fdt_load_override(NULL);
                return (0);
        }
 
-       fdt = (void *)addr;
-       return (0);
+       if (cmd.argc != 2) {
+               printf("dtb file\n");
+               return (0);
+       }
+
+       return fdt_load_override(cmd.argv[1]);
 }
 
 int
diff --git a/sys/arch/riscv64/stand/efiboot/efidt.h b/sys/arch/riscv64/stand/efiboot/efidt.h
new file mode 100644 (file)
index 0000000..8a2ab0d
--- /dev/null
@@ -0,0 +1,44 @@
+/*     $OpenBSD: efidt.h,v 1.1 2024/06/17 09:12:45 kettenis Exp $      */
+
+/*
+ * Copyright (c) 2024 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+
+#include <efi.h>
+#include <efiapi.h>
+
+#define EFI_DT_FIXUP_PROTOCOL_GUID             \
+  { 0xe617d64c, 0xfe08, 0x46da, \
+    { 0xf4, 0xdc, 0xbb, 0xd5, 0x87, 0x0c, 0x73, 0x00 } }
+
+INTERFACE_DECL(_EFI_DT_FIXUP_PROTOCOL);
+
+typedef EFI_STATUS
+(EFIAPI *EFI_DT_FIXUP) (
+    IN struct _EFI_DT_FIXUP_PROTOCOL   *This,
+    IN VOID                            *Fdt,
+    IN OUT UINTN                       *BufferSize,
+    IN UINT32                          Flags
+    );
+
+#define EFI_DT_APPLY_FIXUPS    0x00000001
+#define EFI_DT_RESERVE_MEMORY  0x00000002
+
+typedef struct _EFI_DT_FIXUP_PROTOCOL {
+       UINT64                  Revision;
+       EFI_DT_FIXUP            Fixup;
+} EFI_DT_FIXUP_PROTOCOL;