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);

Reply via email to