Module Name: src Committed By: jmcneill Date: Fri Sep 7 17:30:59 UTC 2018
Modified Files: src/sys/stand/efiboot: boot.c efiboot.h efifdt.c efifdt.h exec.c Log Message: Add initrd support. To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 src/sys/stand/efiboot/boot.c cvs rdiff -u -r1.3 -r1.4 src/sys/stand/efiboot/efiboot.h \ src/sys/stand/efiboot/exec.c cvs rdiff -u -r1.7 -r1.8 src/sys/stand/efiboot/efifdt.c cvs rdiff -u -r1.2 -r1.3 src/sys/stand/efiboot/efifdt.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/stand/efiboot/boot.c diff -u src/sys/stand/efiboot/boot.c:1.5 src/sys/stand/efiboot/boot.c:1.6 --- src/sys/stand/efiboot/boot.c:1.5 Mon Sep 3 00:17:00 2018 +++ src/sys/stand/efiboot/boot.c Fri Sep 7 17:30:58 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: boot.c,v 1.5 2018/09/03 00:17:00 jmcneill Exp $ */ +/* $NetBSD: boot.c,v 1.6 2018/09/07 17:30:58 jmcneill Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -53,17 +53,20 @@ static const char * const names[][2] = { #define DEFTIMEOUT 5 static char default_device[32]; +static char initrd_path[255]; void command_boot(char *); void command_dev(char *); +void command_initrd(char *); void command_ls(char *); void command_reset(char *); void command_version(char *); void command_quit(char *); const struct boot_command commands[] = { - { "boot", command_boot, "boot [fsN:][filename] [args]\n (ex. \"fs0:\\netbsd.old -s\"" }, + { "boot", command_boot, "boot [dev:][filename] [args]\n (ex. \"hd0a:\\netbsd.old -s\"" }, { "dev", command_dev, "dev" }, + { "initrd", command_initrd, "initrd [dev:][filename]" }, { "ls", command_ls, "ls [hdNn:/path]" }, { "version", command_version, "version" }, { "help", command_help, "help|?" }, @@ -111,6 +114,12 @@ command_dev(char *arg) } void +command_initrd(char *arg) +{ + set_initrd_path(arg); +} + +void command_ls(char *arg) { ls(arg); @@ -157,6 +166,21 @@ get_default_device(void) return default_device; } +int +set_initrd_path(char *arg) +{ + if (strlen(arg) + 1 > sizeof(initrd_path)) + return ERANGE; + strcpy(initrd_path, arg); + return 0; +} + +char * +get_initrd_path(void) +{ + return initrd_path; +} + void print_banner(void) { Index: src/sys/stand/efiboot/efiboot.h diff -u src/sys/stand/efiboot/efiboot.h:1.3 src/sys/stand/efiboot/efiboot.h:1.4 --- src/sys/stand/efiboot/efiboot.h:1.3 Mon Sep 3 00:04:02 2018 +++ src/sys/stand/efiboot/efiboot.h Fri Sep 7 17:30:58 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efiboot.h,v 1.3 2018/09/03 00:04:02 jmcneill Exp $ */ +/* $NetBSD: efiboot.h,v 1.4 2018/09/07 17:30:58 jmcneill Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -52,6 +52,8 @@ extern const struct boot_command command void command_help(char *); int set_default_device(char *); char *get_default_device(void); +int set_initrd_path(char *); +char *get_initrd_path(void); /* console.c */ int ischar(void); Index: src/sys/stand/efiboot/exec.c diff -u src/sys/stand/efiboot/exec.c:1.3 src/sys/stand/efiboot/exec.c:1.4 --- src/sys/stand/efiboot/exec.c:1.3 Sun Sep 2 23:50:23 2018 +++ src/sys/stand/efiboot/exec.c Fri Sep 7 17:30:58 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: exec.c,v 1.3 2018/09/02 23:50:23 jmcneill Exp $ */ +/* $NetBSD: exec.c,v 1.4 2018/09/07 17:30:58 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -33,6 +33,78 @@ u_long load_offset = 0; +#define FDT_SPACE (4 * 1024 * 1024) +#define FDT_ALIGN ((2 * 1024 * 1024) - 1) + +static EFI_PHYSICAL_ADDRESS initrd_addr; +static u_long initrd_size = 0; + +static int +load_initrd(void) +{ + EFI_STATUS status; + struct stat st; + ssize_t len; + char *path; + int fd; + + path = get_initrd_path(); + if (strlen(path) == 0) + return 0; + + fd = open(path, 0); + if (fd < 0) { + printf("boot: failed to open %s: %s\n", path, strerror(errno)); + return errno; + } + if (fstat(fd, &st) < 0) { + printf("boot: failed to fstat %s: %s\n", path, strerror(errno)); + close(fd); + return errno; + } + if (st.st_size == 0) { + printf("boot: empty initrd %s\n", path); + close(fd); + return EINVAL; + } + + initrd_size = st.st_size; + +#ifdef EFIBOOT_ALLOCATE_MAX_ADDRESS + initrd_addr = EFIBOOT_ALLOCATE_MAX_ADDRESS; + status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData, + EFI_SIZE_TO_PAGES(initrd_size), &initrd_addr); +#else + initrd_addr = 0; + status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(initrd_size), &initrd_addr); +#endif + if (EFI_ERROR(status)) { + printf("Failed to allocate %lu bytes for initrd image (error %lu)\n", + initrd_size, status); + close(fd); + return ENOMEM; + } + + printf("boot: loading %s ", path); + len = read(fd, (void *)initrd_addr, initrd_size); + close(fd); + + if (len != initrd_size) { + if (len < 0) + printf(": %s\n", strerror(errno)); + else + printf(": returned %ld (expected %ld)\n", len, initrd_size); + return EIO; + } + + printf("done.\n"); + + efi_dcache_flush(initrd_addr, initrd_size); + + return 0; +} + int exec_netbsd(const char *fname, const char *args) { @@ -41,6 +113,8 @@ exec_netbsd(const char *fname, const cha EFI_STATUS status; int fd; + load_initrd(); + memset(marks, 0, sizeof(marks)); fd = loadfile(fname, marks, COUNT_KERNEL | LOAD_NOTE); if (fd < 0) { @@ -49,7 +123,7 @@ exec_netbsd(const char *fname, const cha } close(fd); marks[MARK_END] = (((u_long) marks[MARK_END] + sizeof(int) - 1)) & (-sizeof(int)); - alloc_size = marks[MARK_END] - marks[MARK_START] + EFIBOOT_ALIGN; + alloc_size = marks[MARK_END] - marks[MARK_START] + FDT_SPACE + EFIBOOT_ALIGN; #ifdef EFIBOOT_ALLOCATE_MAX_ADDRESS addr = EFIBOOT_ALLOCATE_MAX_ADDRESS; @@ -77,8 +151,11 @@ exec_netbsd(const char *fname, const cha load_offset = 0; if (efi_fdt_size() > 0) { + efi_fdt_init((marks[MARK_END] + FDT_ALIGN) & ~FDT_ALIGN, FDT_ALIGN + 1); + efi_fdt_initrd(initrd_addr, initrd_size); efi_fdt_bootargs(args); - efi_fdt_memory_map(); + efi_fdt_memory_map(); + efi_fdt_fini(); } efi_cleanup(); @@ -89,5 +166,10 @@ exec_netbsd(const char *fname, const cha cleanup: uefi_call_wrapper(BS->FreePages, 2, addr, EFI_SIZE_TO_PAGES(alloc_size)); + if (initrd_addr) { + uefi_call_wrapper(BS->FreePages, 2, initrd_addr, EFI_SIZE_TO_PAGES(initrd_size)); + initrd_addr = 0; + initrd_size = 0; + } return EIO; } Index: src/sys/stand/efiboot/efifdt.c diff -u src/sys/stand/efiboot/efifdt.c:1.7 src/sys/stand/efiboot/efifdt.c:1.8 --- src/sys/stand/efiboot/efifdt.c:1.7 Mon Sep 3 00:17:00 2018 +++ src/sys/stand/efiboot/efifdt.c Fri Sep 7 17:30:58 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efifdt.c,v 1.7 2018/09/03 00:17:00 jmcneill Exp $ */ +/* $NetBSD: efifdt.c,v 1.8 2018/09/07 17:30:58 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -78,6 +78,28 @@ efi_fdt_size(void) } void +efi_fdt_init(u_long addr, u_long len) +{ + int error; + + error = fdt_open_into(fdt_data, (void *)addr, len); + if (error < 0) + panic("fdt_open_into failed: %d", error); + + fdt_data = (void *)addr; +} + +void +efi_fdt_fini(void) +{ + int error; + + error = fdt_pack(fdt_data); + if (error < 0) + panic("fdt_pack failed: %d", error); +} + +void efi_fdt_show(void) { const char *model, *compat; @@ -194,3 +216,21 @@ efi_fdt_bootargs(const char *bootargs) } } } + +void +efi_fdt_initrd(u_long initrd_addr, u_long initrd_size) +{ + int chosen; + + if (initrd_size == 0) + return; + + chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH); + if (chosen < 0) + chosen = fdt_add_subnode(fdt_data, fdt_path_offset(fdt_data, "/"), FDT_CHOSEN_NODE_NAME); + if (chosen < 0) + panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node"); + + fdt_setprop_u64(fdt_data, chosen, "linux,initrd-start", initrd_addr); + fdt_setprop_u64(fdt_data, chosen, "linux,initrd-end", initrd_addr + initrd_size); +} Index: src/sys/stand/efiboot/efifdt.h diff -u src/sys/stand/efiboot/efifdt.h:1.2 src/sys/stand/efiboot/efifdt.h:1.3 --- src/sys/stand/efiboot/efifdt.h:1.2 Mon Sep 3 00:17:00 2018 +++ src/sys/stand/efiboot/efifdt.h Fri Sep 7 17:30:58 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efifdt.h,v 1.2 2018/09/03 00:17:00 jmcneill Exp $ */ +/* $NetBSD: efifdt.h,v 1.3 2018/09/07 17:30:58 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -32,3 +32,6 @@ void *efi_fdt_data(void); int efi_fdt_size(void); void efi_fdt_show(void); void efi_fdt_bootargs(const char *); +void efi_fdt_initrd(u_long, u_long); +void efi_fdt_init(u_long, u_long); +void efi_fdt_fini(void);