From aa1ebb9e1f309b2055bb208eeda988e8dacdf050 Mon Sep 17 00:00:00 2001 From: kettenis Date: Mon, 17 Jun 2024 09:12:45 +0000 Subject: [PATCH] When loading a device tree using the "mach dtb" command, give firmware 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 | 4 +- sys/arch/armv7/stand/efiboot/efiboot.c | 26 +++- sys/arch/armv7/stand/efiboot/efidt.h | 44 +++++++ sys/arch/riscv64/stand/efiboot/conf.c | 4 +- sys/arch/riscv64/stand/efiboot/efiboot.c | 150 +++++++++++++++++------ sys/arch/riscv64/stand/efiboot/efidt.h | 44 +++++++ 6 files changed, 225 insertions(+), 47 deletions(-) create mode 100644 sys/arch/armv7/stand/efiboot/efidt.h create mode 100644 sys/arch/riscv64/stand/efiboot/efidt.h diff --git a/sys/arch/armv7/stand/efiboot/conf.c b/sys/arch/armv7/stand/efiboot/conf.c index de536fb9620..4143b4f5c46 100644 --- a/sys/arch/armv7/stand/efiboot/conf.c +++ b/sys/arch/armv7/stand/efiboot/conf.c @@ -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[] = { diff --git a/sys/arch/armv7/stand/efiboot/efiboot.c b/sys/arch/armv7/stand/efiboot/efiboot.c index c6bf9501ebd..0e5ac7dcaa5 100644 --- a/sys/arch/armv7/stand/efiboot/efiboot.c +++ b/sys/arch/armv7/stand/efiboot/efiboot.c @@ -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 @@ -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 index 00000000000..8a2ab0d2c34 --- /dev/null +++ b/sys/arch/armv7/stand/efiboot/efidt.h @@ -0,0 +1,44 @@ +/* $OpenBSD: efidt.h,v 1.1 2024/06/17 09:12:45 kettenis Exp $ */ + +/* + * Copyright (c) 2024 Mark Kettenis + * + * 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 + +#include +#include + +#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; diff --git a/sys/arch/riscv64/stand/efiboot/conf.c b/sys/arch/riscv64/stand/efiboot/conf.c index 3396162c80f..2e1985e25b9 100644 --- a/sys/arch/riscv64/stand/efiboot/conf.c +++ b/sys/arch/riscv64/stand/efiboot/conf.c @@ -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[] = { diff --git a/sys/arch/riscv64/stand/efiboot/efiboot.c b/sys/arch/riscv64/stand/efiboot/efiboot.c index 38321fe3b27..ba319d673f5 100644 --- a/sys/arch/riscv64/stand/efiboot/efiboot.c +++ b/sys/arch/riscv64/stand/efiboot/efiboot.c @@ -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 @@ -41,12 +41,16 @@ #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 index 00000000000..8a2ab0d2c34 --- /dev/null +++ b/sys/arch/riscv64/stand/efiboot/efidt.h @@ -0,0 +1,44 @@ +/* $OpenBSD: efidt.h,v 1.1 2024/06/17 09:12:45 kettenis Exp $ */ + +/* + * Copyright (c) 2024 Mark Kettenis + * + * 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 + +#include +#include + +#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; -- 2.20.1