-/* $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>
#include "efidev.h"
#include "efiboot.h"
+#include "efidt.h"
#include "fdt.h"
EFI_SYSTEM_TABLE *ST;
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))
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) {
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;
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;
}
}
fdt_override = (void *)addr;
- fdt_override_size = sb.st_size;
+ fdt_override_size = dt_size;
return 0;
}
--- /dev/null
+/* $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;
-/* $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;
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);
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)
EFI_LOADED_IMAGE *imgp;
EFI_DEVICE_PATH *dp = NULL;
EFI_STATUS status;
+ int i;
ST = systab;
BS = ST->BootServices;
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);
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)
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;
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);
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
--- /dev/null
+/* $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;