Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/stand/efiboot Add initrd support.



details:   https://anonhg.NetBSD.org/src/rev/2a11fc271261
branches:  trunk
changeset: 433319:2a11fc271261
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Fri Sep 07 17:30:58 2018 +0000

description:
Add initrd support.

diffstat:

 sys/stand/efiboot/boot.c    |  28 +++++++++++++-
 sys/stand/efiboot/efiboot.h |   4 +-
 sys/stand/efiboot/efifdt.c  |  42 ++++++++++++++++++++-
 sys/stand/efiboot/efifdt.h  |   5 ++-
 sys/stand/efiboot/exec.c    |  88 +++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 159 insertions(+), 8 deletions(-)

diffs (290 lines):

diff -r 25021cc541cc -r 2a11fc271261 sys/stand/efiboot/boot.c
--- a/sys/stand/efiboot/boot.c  Fri Sep 07 17:30:32 2018 +0000
+++ b/sys/stand/efiboot/boot.c  Fri Sep 07 17:30:58 2018 +0000
@@ -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 <nonaka%netbsd.org@localhost>
@@ -53,17 +53,20 @@
 #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 @@
 }
 
 void
+command_initrd(char *arg)
+{
+       set_initrd_path(arg);
+}
+
+void
 command_ls(char *arg)
 {
        ls(arg);
@@ -157,6 +166,21 @@
        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)
 {
diff -r 25021cc541cc -r 2a11fc271261 sys/stand/efiboot/efiboot.h
--- a/sys/stand/efiboot/efiboot.h       Fri Sep 07 17:30:32 2018 +0000
+++ b/sys/stand/efiboot/efiboot.h       Fri Sep 07 17:30:58 2018 +0000
@@ -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 <nonaka%netbsd.org@localhost>
@@ -52,6 +52,8 @@
 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);
diff -r 25021cc541cc -r 2a11fc271261 sys/stand/efiboot/efifdt.c
--- a/sys/stand/efiboot/efifdt.c        Fri Sep 07 17:30:32 2018 +0000
+++ b/sys/stand/efiboot/efifdt.c        Fri Sep 07 17:30:58 2018 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -78,6 +78,28 @@
 }
 
 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 @@
                }
        }
 }
+
+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);
+}
diff -r 25021cc541cc -r 2a11fc271261 sys/stand/efiboot/efifdt.h
--- a/sys/stand/efiboot/efifdt.h        Fri Sep 07 17:30:32 2018 +0000
+++ b/sys/stand/efiboot/efifdt.h        Fri Sep 07 17:30:58 2018 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -32,3 +32,6 @@
 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);
diff -r 25021cc541cc -r 2a11fc271261 sys/stand/efiboot/exec.c
--- a/sys/stand/efiboot/exec.c  Fri Sep 07 17:30:32 2018 +0000
+++ b/sys/stand/efiboot/exec.c  Fri Sep 07 17:30:58 2018 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -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 @@
        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 @@
        }
        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 @@
        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 @@
 
 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;
 }



Home | Main Index | Thread Index | Old Index