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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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);