Module Name:    src
Committed By:   thorpej
Date:           Sun Apr 21 22:30:41 UTC 2019

Modified Files:
        src/sys/stand/efiboot: Makefile.efiboot boot.c efiboot.c efiboot.h
            efienv.c efienv.h efifdt.c efifdt.h exec.c version

Log Message:
- Add support for a boot configuration file, defaulting to /etc/efiboot.plist.
- Add support for pre-loading EFI environment variables from efiboot.plist.
- Add support for device tree overlays specified in efiboot.plist.

(Man page for efiboot forthcoming.)


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/stand/efiboot/Makefile.efiboot
cvs rdiff -u -r1.17 -r1.18 src/sys/stand/efiboot/boot.c
cvs rdiff -u -r1.15 -r1.16 src/sys/stand/efiboot/efiboot.c
cvs rdiff -u -r1.9 -r1.10 src/sys/stand/efiboot/efiboot.h \
    src/sys/stand/efiboot/exec.c src/sys/stand/efiboot/version
cvs rdiff -u -r1.3 -r1.4 src/sys/stand/efiboot/efienv.c
cvs rdiff -u -r1.1 -r1.2 src/sys/stand/efiboot/efienv.h
cvs rdiff -u -r1.14 -r1.15 src/sys/stand/efiboot/efifdt.c
cvs rdiff -u -r1.4 -r1.5 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/Makefile.efiboot
diff -u src/sys/stand/efiboot/Makefile.efiboot:1.6 src/sys/stand/efiboot/Makefile.efiboot:1.7
--- src/sys/stand/efiboot/Makefile.efiboot:1.6	Fri Oct 12 22:08:04 2018
+++ src/sys/stand/efiboot/Makefile.efiboot	Sun Apr 21 22:30:41 2019
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.efiboot,v 1.6 2018/10/12 22:08:04 jmcneill Exp $
+# $NetBSD: Makefile.efiboot,v 1.7 2019/04/21 22:30:41 thorpej Exp $
 
 S=		${.CURDIR}/../../..
 
@@ -26,7 +26,7 @@ SOURCES+=	efiboot.c efichar.c efidev.c e
 
 .PATH: ${S}/external/bsd/libfdt/dist
 CPPFLAGS+=	-I${S}/external/bsd/libfdt/dist
-SOURCES+=	fdt.c fdt_addresses.c fdt_empty_tree.c
+SOURCES+=	fdt.c fdt_addresses.c fdt_empty_tree.c fdt_overlay.c
 SOURCES+=	fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c fdt_wip.c
 
 SRCS= ${SOURCES} ${EXTRA_SOURCES}
@@ -51,6 +51,7 @@ LDFLAGS+= -nostdlib -T${LDSCRIPT} -Bsymb
 CPPFLAGS+= -I$S -I${.CURDIR} -I${.CURDIR}/../common -I$S/lib/libsa
 CPPFLAGS+= -I${.OBJDIR}
 CPPFLAGS+= -I${.CURDIR}/../../lib
+CPPFLAGS+= -I${S}/../common/include
 
 COPTS+=	-fpic -g -O2
 COPTS+=	-fshort-wchar -fno-strict-aliasing
@@ -77,6 +78,7 @@ CPPFLAGS+= -DSUPPORT_DHCP
 CPPFLAGS+= -DSUPPORT_TFTP
 CPPFLAGS+= -DLIBSA_ENABLE_LS_OP
 
+#CPPFLAGS+= -DEFIBOOT_DEBUG
 #CPPFLAGS+= -DARP_DEBUG
 #CPPFLAGS+= -DBOOTP_DEBUG
 #CPPFLAGS+= -DNET_DEBUG

Index: src/sys/stand/efiboot/boot.c
diff -u src/sys/stand/efiboot/boot.c:1.17 src/sys/stand/efiboot/boot.c:1.18
--- src/sys/stand/efiboot/boot.c:1.17	Sat Apr 20 11:28:53 2019
+++ src/sys/stand/efiboot/boot.c	Sun Apr 21 22:30:41 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: boot.c,v 1.17 2019/04/20 11:28:53 jmcneill Exp $	*/
+/*	$NetBSD: boot.c,v 1.18 2019/04/21 22:30:41 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -72,6 +72,7 @@ static const char *efi_memory_type[] = {
 static char default_device[32];
 static char initrd_path[255];
 static char dtb_path[255];
+static char efibootplist_path[255];
 static char netbsd_path[255];
 static char netbsd_args[255];
 
@@ -84,6 +85,7 @@ int	set_bootargs(const char *);
 void	command_boot(char *);
 void	command_dev(char *);
 void	command_dtb(char *);
+void	command_plist(char *);
 void	command_initrd(char *);
 void	command_ls(char *);
 void	command_mem(char *);
@@ -99,6 +101,7 @@ const struct boot_command commands[] = {
 	{ "boot",	command_boot,		"boot [dev:][filename] [args]\n     (ex. \"hd0a:\\netbsd.old -s\"" },
 	{ "dev",	command_dev,		"dev" },
 	{ "dtb",	command_dtb,		"dtb [dev:][filename]" },
+	{ "plist",	command_plist,		"plist [dev:][filename]" },
 	{ "initrd",	command_initrd,		"initrd [dev:][filename]" },
 	{ "ls",		command_ls,		"ls [hdNn:/path]" },
 	{ "mem",	command_mem,		"mem" },
@@ -166,6 +169,13 @@ command_dtb(char *arg)
 }
 
 void
+command_plist(char *arg)
+{
+	if (set_efibootplist_path(arg) == 0)
+		load_efibootplist(false);
+}
+
+void
 command_initrd(char *arg)
 {
 	set_initrd_path(arg);
@@ -324,6 +334,20 @@ get_dtb_path(void)
 }
 
 int
+set_efibootplist_path(const char *arg)
+{
+	if (strlen(arg) + 1 > sizeof(efibootplist_path))
+		return ERANGE;
+	strcpy(efibootplist_path, arg);
+	return 0;
+}
+
+char *get_efibootplist_path(void)
+{
+	return efibootplist_path;
+}
+
+int
 set_bootfile(const char *arg)
 {
 	if (strlen(arg) + 1 > sizeof(netbsd_path))
@@ -354,6 +378,21 @@ read_env(void)
 {
 	char *s;
 
+	s = efi_env_get("efibootplist");
+	if (s) {
+#ifdef EFIBOOT_DEBUG
+		printf(">> Setting efiboot.plist path to '%s' from environment\n", s);
+#endif
+		set_efibootplist_path(s);
+		FreePool(s);
+	}
+
+	/*
+	 * Read the efiboot.plist now as it may contain additional
+	 * environment variables.
+	 */
+	load_efibootplist(true);
+
 	s = efi_env_get("fdtfile");
 	if (s) {
 #ifdef EFIBOOT_DEBUG

Index: src/sys/stand/efiboot/efiboot.c
diff -u src/sys/stand/efiboot/efiboot.c:1.15 src/sys/stand/efiboot/efiboot.c:1.16
--- src/sys/stand/efiboot/efiboot.c:1.15	Sat Apr 20 11:23:16 2019
+++ src/sys/stand/efiboot/efiboot.c	Sun Apr 21 22:30:41 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: efiboot.c,v 1.15 2019/04/20 11:23:16 jmcneill Exp $ */
+/* $NetBSD: efiboot.c,v 1.16 2019/04/21 22:30:41 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -56,6 +56,8 @@ static EFI_EVENT delay_ev = 0;
 
 EFI_STATUS EFIAPI efi_main(EFI_HANDLE, EFI_SYSTEM_TABLE *);
 
+prop_dictionary_t efibootplist;
+
 EFI_STATUS EFIAPI
 efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE *systemTable)
 {
@@ -180,6 +182,10 @@ efi_cleanup(void)
 	UINTN nentries, mapkey, descsize;
 	UINT32 descver;
 
+	if (efibootplist) {
+		prop_object_release(efibootplist);
+	}
+
 	memmap = LibMemoryMap(&nentries, &mapkey, &descsize, &descver);
 
 	status = uefi_call_wrapper(BS->ExitBootServices, 2, IH, mapkey);

Index: src/sys/stand/efiboot/efiboot.h
diff -u src/sys/stand/efiboot/efiboot.h:1.9 src/sys/stand/efiboot/efiboot.h:1.10
--- src/sys/stand/efiboot/efiboot.h:1.9	Thu Nov 15 23:52:33 2018
+++ src/sys/stand/efiboot/efiboot.h	Sun Apr 21 22:30:41 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: efiboot.h,v 1.9 2018/11/15 23:52:33 jmcneill Exp $	*/
+/*	$NetBSD: efiboot.h,v 1.10 2019/04/21 22:30:41 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -35,6 +35,8 @@
 #include <loadfile.h>
 #include <net.h>
 
+#include <prop/proplib.h>
+
 #include "efiboot_machdep.h"
 
 struct boot_command {
@@ -60,6 +62,8 @@ int set_initrd_path(const char *);
 char *get_initrd_path(void);
 int set_dtb_path(const char *);
 char *get_dtb_path(void);
+int set_efibootplist_path(const char *);
+char *get_efibootplist_path(void);
 
 /* console.c */
 int ischar(void);
@@ -73,6 +77,7 @@ void efi_exit(void);
 void efi_delay(int);
 void efi_reboot(void);
 extern int howto;
+extern prop_dictionary_t efibootplist;
 
 /* efichar.c */
 size_t ucs2len(const CHAR16 *);
@@ -101,6 +106,7 @@ bool efi_pxe_match_booted_interface(cons
 
 /* exec.c */
 int exec_netbsd(const char *, const char *);
+void load_efibootplist(bool);
 
 /* panic.c */
 __dead VOID Panic(IN CHAR16 *, ...);
Index: src/sys/stand/efiboot/exec.c
diff -u src/sys/stand/efiboot/exec.c:1.9 src/sys/stand/efiboot/exec.c:1.10
--- src/sys/stand/efiboot/exec.c:1.9	Sat Mar 30 12:47:53 2019
+++ src/sys/stand/efiboot/exec.c	Sun Apr 21 22:30:41 2019
@@ -1,6 +1,7 @@
-/* $NetBSD: exec.c,v 1.9 2019/03/30 12:47:53 jmcneill Exp $ */
+/* $NetBSD: exec.c,v 1.10 2019/04/21 22:30:41 thorpej Exp $ */
 
 /*-
+ * Copyright (c) 2019 Jason R. Thorpe
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
  * All rights reserved.
  *
@@ -27,6 +28,7 @@
  */
 
 #include "efiboot.h"
+#include "efienv.h"
 #include "efifdt.h"
 #include "efiacpi.h"
 
@@ -41,11 +43,13 @@ static EFI_PHYSICAL_ADDRESS initrd_addr,
 static u_long initrd_size = 0, dtb_size = 0;
 
 static int
-load_file(char *path, EFI_PHYSICAL_ADDRESS *paddr, u_long *psize)
+load_file(const char *path, u_long extra, bool quiet_errors,
+    EFI_PHYSICAL_ADDRESS *paddr, u_long *psize)
 {
 	EFI_STATUS status;
 	struct stat st;
 	ssize_t len;
+	ssize_t expectedlen;
 	int fd;
 
 	if (strlen(path) == 0)
@@ -53,7 +57,10 @@ load_file(char *path, EFI_PHYSICAL_ADDRE
 
 	fd = open(path, 0);
 	if (fd < 0) {
-		printf("boot: failed to open %s: %s\n", path, strerror(errno));
+		if (!quiet_errors) {
+			printf("boot: failed to open %s: %s\n", path,
+			    strerror(errno));
+		}
 		return errno;
 	}
 	if (fstat(fd, &st) < 0) {
@@ -62,12 +69,15 @@ load_file(char *path, EFI_PHYSICAL_ADDRE
 		return errno;
 	}
 	if (st.st_size == 0) {
-		printf("boot: empty file %s\n", path);
+		if (!quiet_errors) {
+			printf("boot: empty file %s\n", path);
+		}
 		close(fd);
 		return EINVAL;
 	}
 
-	*psize = st.st_size;
+	expectedlen = st.st_size;
+	*psize = st.st_size + extra;
 
 #ifdef EFIBOOT_ALLOCATE_MAX_ADDRESS
 	*paddr = EFIBOOT_ALLOCATE_MAX_ADDRESS;
@@ -82,18 +92,21 @@ load_file(char *path, EFI_PHYSICAL_ADDRE
 		printf("Failed to allocate %lu bytes for %s (error %lu)\n",
 		    *psize, path, (u_long)status);
 		close(fd);
+		*paddr = 0;
 		return ENOMEM;
 	}
 
 	printf("boot: loading %s ", path);
-	len = read(fd, (void *)(uintptr_t)*paddr, *psize);
+	len = read(fd, (void *)(uintptr_t)*paddr, expectedlen);
 	close(fd);
 
-	if (len != *psize) {
-		if (len < 0)
+	if (len != expectedlen) {
+		if (len < 0) {
 			printf(": %s\n", strerror(errno));
-		else
-			printf(": returned %ld (expected %ld)\n", len, *psize);
+		} else {
+			printf(": returned %ld (expected %ld)\n", len,
+			    expectedlen);
+		}
 		return EIO;
 	}
 
@@ -104,6 +117,155 @@ load_file(char *path, EFI_PHYSICAL_ADDRE
 	return 0;
 }
 
+static const char default_efibootplist_path[] = "/etc/efiboot.plist";
+
+/* This is here because load_file() is here. */
+void
+load_efibootplist(bool default_fallback)
+{
+	EFI_PHYSICAL_ADDRESS plist_addr = 0;
+	u_long plist_size = 0;
+	prop_dictionary_t plist = NULL, oplist = NULL;
+	bool load_quietly = false;
+
+	const char *path = get_efibootplist_path();
+	if (path == NULL || strlen(path) == 0) {
+		if (!default_fallback)
+			return;
+		path = default_efibootplist_path;
+		load_quietly = true;
+	}
+
+	/*
+	 * Fudge the size so we can ensure the resulting buffer
+	 * is NUL-terminated for convenience.
+	 */
+	if (load_file(path, 1, load_quietly, &plist_addr, &plist_size) != 0 ||
+	    plist_addr == 0) {
+		/* Error messages have already been displayed. */
+		goto out;
+	}
+	char *plist_buf = (char *)((uintptr_t)plist_addr);
+	plist_buf[plist_size - 1] = '\0';
+
+	plist = prop_dictionary_internalize(plist_buf);
+	if (plist == NULL) {
+		printf("boot: unable to parse plist '%s'\n", path);
+		goto out;
+	}
+
+out:
+	oplist = efibootplist;
+
+	/*
+	 * If we had a failure, create an empty one for
+	 * convenience.  But a failure should not clobber
+	 * an in-memory plist we already have.
+	 */
+	if (plist == NULL &&
+	    (oplist == NULL || prop_dictionary_count(oplist) == 0))
+		plist = prop_dictionary_create();
+
+#ifdef EFIBOOT_DEBUG
+	printf(">> load_efibootplist: oplist = 0x%lx, plist = 0x%lx\n",
+	    (u_long)oplist, (u_long)plist);
+#endif
+
+	if (plist_addr) {
+		uefi_call_wrapper(BS->FreePages, 2, plist_addr,
+		    EFI_SIZE_TO_PAGES(plist_size));
+	}
+
+	if (plist) {
+		efibootplist = plist;
+		efi_env_from_efibootplist();
+
+		if (oplist)
+			prop_object_release(oplist);
+	}
+}
+
+static void
+apply_overlay(void *dtbo)
+{
+
+	if (!efi_fdt_overlay_is_compatible(dtbo)) {
+		printf("boot: incompatible overlay\n");
+	}
+
+	int fdterr;
+
+	if (efi_fdt_overlay_apply(dtbo, &fdterr) != 0) {
+		printf("boot: error %d applying overlay\n", fdterr);
+	}
+}
+
+static void
+apply_overlay_file(const char *path)
+{
+	EFI_PHYSICAL_ADDRESS dtbo_addr;
+	u_long dtbo_size;
+
+	if (strlen(path) == 0)
+		return;
+
+	if (load_file(path, 0, false, &dtbo_addr, &dtbo_size) != 0 ||
+	    dtbo_addr == 0) {
+		/* Error messages have already been displayed. */
+		goto out;
+	}
+
+	apply_overlay((void *)(uintptr_t)dtbo_addr);
+
+out:
+	if (dtbo_addr) {
+		uefi_call_wrapper(BS->FreePages, 2, dtbo_addr,
+		    EFI_SIZE_TO_PAGES(dtbo_size));
+	}
+}
+
+#define	DT_OVERLAYS_PROP	"device-tree-overlays"
+
+static void
+load_fdt_overlays(void)
+{
+	/*
+	 * We support loading device tree overlays specified in efiboot.plist
+	 * using the following schema:
+	 *
+	 *	<key>device-tree-overlays</key>
+	 *	<array>
+	 *		<string>/path/to/some/overlay.dtbo</string>
+	 *		<string>hd0e:/some/other/overlay.dtbo</string>
+	 *	</array>
+	 *
+	 * The overlays are loaded in array order.
+	 */
+	prop_array_t overlays = prop_dictionary_get(efibootplist,
+	    DT_OVERLAYS_PROP);
+	if (overlays == NULL) {
+#ifdef EFIBOOT_DEBUG
+		printf("boot: no device-tree-overlays\n");
+#endif
+		return;
+	}
+	if (prop_object_type(overlays) != PROP_TYPE_ARRAY) {
+		printf("boot: invalid %s\n", DT_OVERLAYS_PROP);
+		return;
+	}
+
+	prop_object_iterator_t iter = prop_array_iterator(overlays);
+	prop_string_t pathobj;
+	while ((pathobj = prop_object_iterator_next(iter)) != NULL) {
+		if (prop_object_type(pathobj) != PROP_TYPE_STRING) {
+			printf("boot: invalid %s entry\n", DT_OVERLAYS_PROP);
+			continue;
+		}
+		apply_overlay_file(prop_string_cstring_nocopy(pathobj));
+	}
+	prop_object_iterator_release(iter);
+}
+
 int
 exec_netbsd(const char *fname, const char *args)
 {
@@ -112,8 +274,8 @@ exec_netbsd(const char *fname, const cha
 	EFI_STATUS status;
 	int fd, ohowto;
 
-	load_file(get_initrd_path(), &initrd_addr, &initrd_size);
-	load_file(get_dtb_path(), &dtb_addr, &dtb_size);
+	load_file(get_initrd_path(), 0, false, &initrd_addr, &initrd_size);
+	load_file(get_dtb_path(), 0, false, &dtb_addr, &dtb_size);
 
 	memset(marks, 0, sizeof(marks));
 	ohowto = howto;
@@ -165,6 +327,7 @@ exec_netbsd(const char *fname, const cha
 
 	if (efi_fdt_size() > 0) {
 		efi_fdt_init((marks[MARK_END] + FDT_ALIGN) & ~FDT_ALIGN, FDT_ALIGN + 1);
+		load_fdt_overlays();
 		efi_fdt_initrd(initrd_addr, initrd_size);
 		efi_fdt_bootargs(args);
 		efi_fdt_memory_map();
Index: src/sys/stand/efiboot/version
diff -u src/sys/stand/efiboot/version:1.9 src/sys/stand/efiboot/version:1.10
--- src/sys/stand/efiboot/version:1.9	Fri Jan 18 19:41:03 2019
+++ src/sys/stand/efiboot/version	Sun Apr 21 22:30:41 2019
@@ -1,4 +1,4 @@
-$NetBSD: version,v 1.9 2019/01/18 19:41:03 skrll Exp $
+$NetBSD: version,v 1.10 2019/04/21 22:30:41 thorpej Exp $
 
 NOTE ANY CHANGES YOU MAKE TO THE EFI BOOTLOADER HERE.  The format of this
 file is important - make sure the entries are appended on end, last item
@@ -13,3 +13,4 @@ is taken as the current.
 1.6:	Add GPT support.
 1.7:	Add NFS support.
 1.8:	Add support for "bootargs" environment variable.
+1.9:	Add support for efiboot.plist and loading device tree overlays.

Index: src/sys/stand/efiboot/efienv.c
diff -u src/sys/stand/efiboot/efienv.c:1.3 src/sys/stand/efiboot/efienv.c:1.4
--- src/sys/stand/efiboot/efienv.c:1.3	Sat Mar 30 12:47:53 2019
+++ src/sys/stand/efiboot/efienv.c	Sun Apr 21 22:30:41 2019
@@ -1,6 +1,7 @@
-/* $NetBSD: efienv.c,v 1.3 2019/03/30 12:47:53 jmcneill Exp $ */
+/* $NetBSD: efienv.c,v 1.4 2019/04/21 22:30:41 thorpej Exp $ */
 
 /*-
+ * Copyright (c) 2019 Jason R. Thorpe
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
  * All rights reserved.
  *
@@ -35,6 +36,69 @@
 static EFI_GUID EfibootVendorGuid = EFIBOOT_VENDOR_GUID;
 
 void
+efi_env_from_efibootplist(void)
+{
+	/*
+	 * We support pre-loading the EFI environment from efiboot.plist
+	 * using the following schema:
+	 *
+	 *	<key>environment-variables</key>
+	 *	<dict>
+	 *		<key>varname1</key>
+	 *		<string>value_for_varname1</string>
+	 *		<key>varname2</key>
+	 *		<string>value_for_varname2</string>
+	 *	</dict>
+	 *
+	 * Only string values are supported.
+	 */
+	prop_dictionary_t environment;
+	prop_dictionary_keysym_t key;
+	prop_string_t value;
+	prop_object_iterator_t iter;
+
+	const char *env_key;
+	char *env_value;
+
+	environment = prop_dictionary_get(efibootplist,
+	    "environment-variables");
+	if (environment == NULL)
+		return;
+
+	iter = prop_dictionary_iterator(environment);
+	if (iter == NULL)
+		goto failed;
+
+	while ((key = prop_object_iterator_next(iter)) != NULL) {
+		value = prop_dictionary_get_keysym(environment, key);
+		if (value == NULL) {
+			printf("boot: env: failed to get value for '%s'\n",
+			    prop_dictionary_keysym_cstring_nocopy(key));
+			continue;
+		}
+		if (prop_object_type(value) != PROP_TYPE_STRING) {
+			printf("boot: env: value for '%s' is not a string\n",
+			    prop_dictionary_keysym_cstring_nocopy(key));
+			continue;
+		}
+		/* XXX __UNCONST because gnuefi */
+		env_key = prop_dictionary_keysym_cstring_nocopy(key);;
+		env_value = __UNCONST(prop_string_cstring_nocopy(value));;
+#ifdef EFIBOOT_DEBUG
+		printf(">> efiboot.plist env: '%s' = '%s'\n", env_key,
+		    env_value);
+#endif
+		efi_env_set(env_key, env_value);
+	}
+	prop_object_iterator_release(iter);
+
+	return;
+
+ failed:
+	printf("boot: failed to load environment from efiboot.plist");
+}
+
+void
 efi_env_set(const char *key, char *val)
 {
 	EFI_STATUS status;

Index: src/sys/stand/efiboot/efienv.h
diff -u src/sys/stand/efiboot/efienv.h:1.1 src/sys/stand/efiboot/efienv.h:1.2
--- src/sys/stand/efiboot/efienv.h:1.1	Sun Sep  9 17:55:22 2018
+++ src/sys/stand/efiboot/efienv.h	Sun Apr 21 22:30:41 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: efienv.h,v 1.1 2018/09/09 17:55:22 jmcneill Exp $ */
+/* $NetBSD: efienv.h,v 1.2 2019/04/21 22:30:41 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+void efi_env_from_efibootplist(void);
 void efi_env_set(const char *, char *);
 char *efi_env_get(const char *);
 void efi_env_clear(const char *);

Index: src/sys/stand/efiboot/efifdt.c
diff -u src/sys/stand/efiboot/efifdt.c:1.14 src/sys/stand/efiboot/efifdt.c:1.15
--- src/sys/stand/efiboot/efifdt.c:1.14	Thu Nov 15 23:52:33 2018
+++ src/sys/stand/efiboot/efifdt.c	Sun Apr 21 22:30:41 2019
@@ -1,6 +1,7 @@
-/* $NetBSD: efifdt.c,v 1.14 2018/11/15 23:52:33 jmcneill Exp $ */
+/* $NetBSD: efifdt.c,v 1.15 2019/04/21 22:30:41 thorpej Exp $ */
 
 /*-
+ * Copyright (c) 2019 Jason R. Thorpe
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
  * All rights reserved.
  *
@@ -87,6 +88,53 @@ efi_fdt_size(void)
 	return fdt_data == NULL ? 0 : fdt_totalsize(fdt_data);
 }
 
+bool
+efi_fdt_overlay_is_compatible(void *dtbo)
+{
+	const int system_root = fdt_path_offset(fdt_data, "/");
+	const int overlay_root = fdt_path_offset(dtbo, "/");
+
+	if (system_root < 0 || overlay_root < 0)
+		return false;
+
+	const int system_ncompat = fdt_stringlist_count(fdt_data, system_root,
+	    "compatible");
+	const int overlay_ncompat = fdt_stringlist_count(dtbo, overlay_root,
+	    "compatible");
+
+	if (system_ncompat <= 0 || overlay_ncompat <= 0)
+		return false;
+
+	const char *system_compatible, *overlay_compatible;
+	int si, oi;
+
+	for (si = 0; si < system_ncompat; si++) {
+		system_compatible = fdt_stringlist_get(fdt_data,
+		    system_root, "compatible", si, NULL);
+		if (system_compatible == NULL)
+			continue;
+		for (oi = 0; oi < overlay_ncompat; oi++) {
+			overlay_compatible = fdt_stringlist_get(dtbo,
+			    overlay_root, "compatible", oi, NULL);
+			if (overlay_compatible == NULL)
+				continue;
+			if (strcmp(system_compatible, overlay_compatible) == 0)
+				return true;
+		}
+	}
+
+	return false;
+}
+
+int
+efi_fdt_overlay_apply(void *dtbo, int *fdterr)
+{
+	int err = fdt_overlay_apply(fdt_data, dtbo);
+	if (fdterr)
+		*fdterr = err;
+	return err == 0 ? 0 : EIO;
+}
+
 void
 efi_fdt_init(u_long addr, u_long len)
 {

Index: src/sys/stand/efiboot/efifdt.h
diff -u src/sys/stand/efiboot/efifdt.h:1.4 src/sys/stand/efiboot/efifdt.h:1.5
--- src/sys/stand/efiboot/efifdt.h:1.4	Sun Sep  9 13:37:54 2018
+++ src/sys/stand/efiboot/efifdt.h	Sun Apr 21 22:30:41 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: efifdt.h,v 1.4 2018/09/09 13:37:54 jmcneill Exp $ */
+/* $NetBSD: efifdt.h,v 1.5 2019/04/21 22:30:41 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -31,6 +31,8 @@ void efi_fdt_memory_map(void);
 int efi_fdt_set_data(void *);
 void *efi_fdt_data(void);
 int efi_fdt_size(void);
+bool efi_fdt_overlay_is_compatible(void *);
+int efi_fdt_overlay_apply(void *, int *);
 void efi_fdt_show(void);
 void efi_fdt_bootargs(const char *);
 void efi_fdt_initrd(u_long, u_long);

Reply via email to