Module Name:    src
Committed By:   thorpej
Date:           Tue May  7 05:02:42 UTC 2019

Modified Files:
        src/distrib/sets/lists/base: mi
        src/etc/mtree: NetBSD.dist.base
        src/share: Makefile
        src/tools/installboot: Makefile
        src/usr.sbin/installboot: Makefile installboot.8 installboot.c
            installboot.h machines.c
Added Files:
        src/share/installboot: Makefile
        src/share/installboot/evbarm: Makefile boards.plist
        src/usr.sbin/installboot: evboards.c evboards.h
        src/usr.sbin/installboot/arch: evbarm.c

Log Message:
Add installboot(8) support for evbarm (and, in the future, other evb*)
boards that use u-boot.  A known board database lists boards and their
respective u-boot packages.  u-boot packages are discovered at run-time
(in /usr/pkg/share/u-boot, by default).  These packages contain board
database overlays that describe u-boot installation procedure that's
specific for that board.

Support this as a native tool and as a host tool.  The native tool
will attempt to determine the running board type using OpenFirmware
calls.  Host tool and native tool alike may also specify a board type
directly using the "-o board=xxx option" or have installboot(8) determine
the board type from a device tree blob using "-o dtb=/path/to/board.dtb".
A "-o media=xxx" option is provided for boards that have different u-boot
binaries and/or installation procedures for different media types (e.g.
SDMMC, eMMC, or USB).

This is trivial to extend to other evb* platforms that use u-boot, even if
they don't use FDT for autoconfiguration.


To generate a diff of this commit:
cvs rdiff -u -r1.1203 -r1.1204 src/distrib/sets/lists/base/mi
cvs rdiff -u -r1.196 -r1.197 src/etc/mtree/NetBSD.dist.base
cvs rdiff -u -r1.35 -r1.36 src/share/Makefile
cvs rdiff -u -r0 -r1.1 src/share/installboot/Makefile
cvs rdiff -u -r0 -r1.1 src/share/installboot/evbarm/Makefile \
    src/share/installboot/evbarm/boards.plist
cvs rdiff -u -r1.11 -r1.12 src/tools/installboot/Makefile
cvs rdiff -u -r1.51 -r1.52 src/usr.sbin/installboot/Makefile
cvs rdiff -u -r0 -r1.1 src/usr.sbin/installboot/evboards.c \
    src/usr.sbin/installboot/evboards.h
cvs rdiff -u -r1.95 -r1.96 src/usr.sbin/installboot/installboot.8
cvs rdiff -u -r1.39 -r1.40 src/usr.sbin/installboot/installboot.c \
    src/usr.sbin/installboot/installboot.h \
    src/usr.sbin/installboot/machines.c
cvs rdiff -u -r0 -r1.1 src/usr.sbin/installboot/arch/evbarm.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/distrib/sets/lists/base/mi
diff -u src/distrib/sets/lists/base/mi:1.1203 src/distrib/sets/lists/base/mi:1.1204
--- src/distrib/sets/lists/base/mi:1.1203	Thu Apr 18 03:50:12 2019
+++ src/distrib/sets/lists/base/mi	Tue May  7 05:02:41 2019
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1203 2019/04/18 03:50:12 rin Exp $
+# $NetBSD: mi,v 1.1204 2019/05/07 05:02:41 thorpej Exp $
 #
 # Note:	Don't delete entries from here - mark them as "obsolete" instead,
 #	unless otherwise stated below.
@@ -3054,6 +3054,9 @@
 ./usr/share/i18n/iconv				base-sysutil-share
 ./usr/share/i18n/iconv/iconv.dir		base-sysutil-share	nls
 ./usr/share/info				base-texinfo-share
+./usr/share/installboot				base-sysutil-share
+./usr/share/installboot/evbarm			base-sysutil-share
+./usr/share/installboot/evbarm/boards.plist	base-sysutil-share
 ./usr/share/keymaps				base-sys-share
 ./usr/share/keymaps/amiga			base-sys-share
 ./usr/share/keymaps/atari			base-sys-share

Index: src/etc/mtree/NetBSD.dist.base
diff -u src/etc/mtree/NetBSD.dist.base:1.196 src/etc/mtree/NetBSD.dist.base:1.197
--- src/etc/mtree/NetBSD.dist.base:1.196	Thu Apr 18 03:50:12 2019
+++ src/etc/mtree/NetBSD.dist.base	Tue May  7 05:02:42 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: NetBSD.dist.base,v 1.196 2019/04/18 03:50:12 rin Exp $
+#	$NetBSD: NetBSD.dist.base,v 1.197 2019/05/07 05:02:42 thorpej Exp $
 #	@(#)4.4BSD.dist	8.1 (Berkeley) 6/13/93
 
 # Do not customize this file as it may be overwritten on upgrades.
@@ -472,6 +472,8 @@
 ./usr/share/i18n/esdb/UTF
 ./usr/share/i18n/iconv
 ./usr/share/info
+./usr/share/installboot
+./usr/share/installboot/evbarm
 ./usr/share/keymaps
 ./usr/share/keymaps/amiga
 ./usr/share/keymaps/atari

Index: src/share/Makefile
diff -u src/share/Makefile:1.35 src/share/Makefile:1.36
--- src/share/Makefile:1.35	Sun Jun 10 17:55:11 2018
+++ src/share/Makefile	Tue May  7 05:02:42 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.35 2018/06/10 17:55:11 christos Exp $
+#	$NetBSD: Makefile,v 1.36 2019/05/07 05:02:42 thorpej Exp $
 #	from @(#)Makefile	8.1 (Berkeley) 6/5/93
 
 # Missing:  ms
@@ -7,7 +7,7 @@
 
 .if ${MKSHARE} != "no" || \
 	make(clean) || make(cleandir) || make(distclean) || make(obj)
-SUBDIR=	dict examples legal man me misc mk \
+SUBDIR=	dict examples installboot legal man me misc mk \
 	tabset terminfo tmac wscons xml
 
 .if ${MKGROFF} != "no"

Index: src/tools/installboot/Makefile
diff -u src/tools/installboot/Makefile:1.11 src/tools/installboot/Makefile:1.12
--- src/tools/installboot/Makefile:1.11	Sun Mar  6 18:15:30 2011
+++ src/tools/installboot/Makefile	Tue May  7 05:02:42 2019
@@ -1,11 +1,40 @@
-#	$NetBSD: Makefile,v 1.11 2011/03/06 18:15:30 bouyer Exp $
+#	$NetBSD: Makefile,v 1.12 2019/05/07 05:02:42 thorpej Exp $
+
+.include <bsd.hostinit.mk>
 
 HOSTPROGNAME=	${_TOOL_PREFIX}installboot
 HOST_SRCDIR=	usr.sbin/installboot
 
+LIBPROP_INC=	${.CURDIR}/../../common/include
+HOST_CPPFLAGS+=	-I${LIBPROP_INC}
+
 HOST_CPPFLAGS+=	-I. -I${.CURDIR} -I${.CURDIR}/../mips-elf2ecoff
 HOST_CPPFLAGS+=	-I${TOOLDIR}/include/nbinclude
 
+HOST_CPPFLAGS+=	-DEVBOARDS_PLIST_BASE=\"${TOOLDIR}\"
+
+LIBPROP_OBJ!=	cd ${.CURDIR}/../libprop && ${PRINTOBJDIR}
+LDADD+=		-L${LIBPROP_OBJ} -lprop
+
+SHARE_SRCDIR=	${.CURDIR}/../../share
+HOST_SHAREDIR=	${TOOLDIR}/share
+
+BOARDDB_SRCDIR=	${SHARE_SRCDIR}/installboot
+BOARDDB_DSTDIR=	${HOST_SHAREDIR}/installboot
+
+BOARDDBS=	evbarm
+
+.for _d in ${BOARDDBS}
+install: .PHONY install.${_d}.boards.plist
+install.${_d}.boards.plist: .PHONY ${BOARDDB_DSTDIR}/${_d}/boards.plist
+${BOARDDB_DSTDIR}/${_d}/boards.plist: ${BOARDDB_SRCDIR}/${_d}/boards.plist
+	${_MKTARGET_INSTALL}
+	${HOST_INSTALL_DIR} ${HOST_SHAREDIR}
+	${HOST_INSTALL_DIR} ${BOARDDB_DSTDIR}
+	${HOST_INSTALL_DIR} ${BOARDDB_DSTDIR}/${_d}
+	${HOST_INSTALL_FILE} -m ${NONBINMODE} ${.ALLSRC} ${.TARGET}
+.endfor
+
 .include "${.CURDIR}/../Makefile.nbincludes"
 .include "${.CURDIR}/../Makefile.host"
 

Index: src/usr.sbin/installboot/Makefile
diff -u src/usr.sbin/installboot/Makefile:1.51 src/usr.sbin/installboot/Makefile:1.52
--- src/usr.sbin/installboot/Makefile:1.51	Wed Jan 11 12:19:44 2017
+++ src/usr.sbin/installboot/Makefile	Tue May  7 05:02:42 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.51 2017/01/11 12:19:44 joerg Exp $
+#	$NetBSD: Makefile,v 1.52 2019/05/07 05:02:42 thorpej Exp $
 #
 
 .include <bsd.own.mk>
@@ -11,9 +11,17 @@ ARCH_XLAT= amd64-i386.c news68k-news.c n
 ARCH_XLAT+= sun2-sun68k.c sun3-sun68k.c
 
 .if !defined(SMALLPROG) && !defined(ARCH_FILES)
-ARCH_FILES=  alpha.c amiga.c emips.c ews4800mips.c hp300.c hppa.c i386.c
-ARCH_FILES+= landisk.c macppc.c news.c next68k.c pmax.c
-ARCH_FILES+= sparc.c sparc64.c sun68k.c vax.c x68k.c
+ARCH_FILES=  alpha.c amiga.c
+ARCH_FILES+= emips.c evbarm.c ews4800mips.c
+ARCH_FILES+= hp300.c hppa.c
+ARCH_FILES+= i386.c
+ARCH_FILES+= landisk.c
+ARCH_FILES+= macppc.c
+ARCH_FILES+= news.c next68k.c
+ARCH_FILES+= pmax.c
+ARCH_FILES+= sparc.c sparc64.c sun68k.c
+ARCH_FILES+= vax.c
+ARCH_FILES+= x68k.c
 .else
 ARCH_FILES?= ${ARCH_XLAT:M${MACHINE}-*:S/${MACHINE}-//}
 .if empty(ARCH_FILES)
@@ -23,8 +31,30 @@ ARCH_FILES= ${MACHINE}.c
 
 SRCS+=${ARCH_FILES}
 
+.if !empty(ARCH_FILES:C/(evbarm)/evboard/:Mevboard.c)
+SRCS+=evboards.c
+.endif
+
+.if !empty(ARCH_FILES:C/(evbarm)/fdt/:Mfdt.c)
+FDTDIR=		${.CURDIR}/../../sys/external/bsd/libfdt/dist
+.PATH:		${FDTDIR}
+CPPFLAGS+=	-DSUPPORT_FDT -I${FDTDIR}
+SRCS+=fdt.c fdt_ro.c fdt_strerror.c
+# XXX libfdt has some sign-comparison issues
+COPTS.fdt.c+=		-Wno-error=sign-compare
+COPTS.fdt_ro.c+=	-Wno-error=sign-compare
+COPTS.fdt_strerror.c+=	-Wno-error=sign-compare
+.endif
+
+
+.if !defined(HOSTPROGNAME)
+.if !empty(ARCH_FILES:C/(evbarm)/ofw/:Mofw.c)
+CPPFLAGS+=	-DSUPPORT_OPENFIRMWARE
+.endif
+.endif
+
 .if empty(ARCH_FILES:C/(macppc|news|sparc|sun68k|x68k)/stg2/:Mstg2.c)
-CPPFLAGS	+= -DNO_STAGE2
+CPPFLAGS+=	-DNO_STAGE2
 .else
 SRCS+= bbinfo.c
 
@@ -47,6 +77,11 @@ CPPFLAGS+=	-I${.CURDIR} -I.
 COPTS.${f}.c+=  -Wno-pointer-sign
 .endfor
 
+.if !empty(SRCS:Mevboards.c)
+LDADD+=	-lprop
+DPADD+=	${LIBPROP}
+.endif
+
 LDADD+= -lutil
 DPADD+= ${LIBUTIL}
 .endif

Index: src/usr.sbin/installboot/installboot.8
diff -u src/usr.sbin/installboot/installboot.8:1.95 src/usr.sbin/installboot/installboot.8:1.96
--- src/usr.sbin/installboot/installboot.8:1.95	Tue Aug 15 21:21:18 2017
+++ src/usr.sbin/installboot/installboot.8	Tue May  7 05:02:42 2019
@@ -1,6 +1,6 @@
-.\"	$NetBSD: installboot.8,v 1.95 2017/08/15 21:21:18 wiz Exp $
+.\"	$NetBSD: installboot.8,v 1.96 2019/05/07 05:02:42 thorpej Exp $
 .\"
-.\" Copyright (c) 2002-2017 The NetBSD Foundation, Inc.
+.\" Copyright (c) 2002-2019 The NetBSD Foundation, Inc.
 .\" All rights reserved.
 .\"
 .\" This code is derived from software contributed to The NetBSD Foundation
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd March 14, 2017
+.Dd May 5, 2019
 .Dt INSTALLBOOT 8
 .Os
 .Sh NAME
@@ -132,6 +132,28 @@ other platforms:
 .Sy next68k .
 .El
 .Pp
+Some platforms, typically embedded system platforms, are umbrella platforms
+that support many different individual board types, each with their own
+boot loader binary and installation procedure requirements.
+On these platforms, it may be necessary to provide specific board type
+information to
+.Nm .
+Information about known boards and their requirements is loaded from a
+database at run-time.
+Sometimes these platforms also require the use of 3rd-party boot loader
+software, such as
+.Sy U-boot .
+To support these platforms,
+.Nm
+scans known locations for these 3rd-party boot loader packages for
+database overlays that contain additional board-specific boot loader
+installation information in a file called
+.Sq installboot.plist .
+.Pp
+The following platforms have this requirement and utilize this database
+overlay feature:
+.Sy evbarm .
+.Pp
 The options and arguments recognized by
 .Nm
 are as follows:
@@ -202,6 +224,7 @@ The following machines are currently sup
 .Sy alpha ,
 .Sy amd64 ,
 .Sy amiga ,
+.Sy evbarm ,
 .Sy ews4800mips ,
 .Sy hp300 ,
 .Sy hppa ,
@@ -250,6 +273,15 @@ to the end of
 .Ar filesystem ,
 which must be a regular file in this case.
 .
+.It Sy board=<board name>
+.Sy [ evbarm ]
+Specify the board type used to determine the correct boot loader image
+and installation procedure.
+If omitted,
+.Nm
+will attempt to guess the board type based on system information if run
+natively.
+.
 .It Sy bootconf
 .Sy [ amd64 ,
 .Sy i386 ]
@@ -267,6 +299,18 @@ Modify the default boot command line.
 Set the console device, <console name> must be one of:
 pc, com0, com1, com2, com3, com0kbd, com1kbd, com2kbd, com3kbd or auto.
 .
+.It Sy dtb=<path to dtb file>
+.Sy [ evbarm ]
+Attempt to determine the board type from information in the device tree
+blob file at <path to dtb file>.
+If both
+.Sy board
+and
+.Sy dtb
+optios are specified,
+.Sy board
+takes precendence.
+.
 .It Sy ioaddr=<ioaddr>
 .Sy [ amd64 ,
 .Sy i386 ]
@@ -285,6 +329,16 @@ would swap the lowercase letters
 and
 .Sq z .
 .
+.It Sy media=<media type>
+.Sy [ evbarm ]
+Some boards require a different boot loader binary and/or installation
+procedure depending on what type of media will be used to boot the system.
+For such boards, this option is required, and omitting it will display a
+usage message that lists the valid media types for the board.
+For boards that do not require special media handling, this option is
+not allowed.
+Common values: sdmmc, emmc, usb.
+.
 .It Sy modules
 .Sy [ amd64 ,
 .Sy i386 ]
@@ -418,6 +472,21 @@ uses the following environment variables
 .
 .Bl -tag -width "MACHINE"
 .
+.It Ev INSTALLBOOT_UBOOT_PATHS
+A colon-separated list of search paths to scan for
+.Sy U-boot
+packages with
+.Nm installboot
+installation overlays.
+If multiple overlays are found, overlays from paths closer to the front
+of the list take precensence.
+If not specified, the default path is
+.Pa /usr/pkg/share/u-boot .
+This environment variable is only used on platforms that support
+using
+.Sy U-boot :
+.Sy evbarm .
+.
 .It Ev MACHINE
 Default value for
 .Ar machine ,
@@ -525,6 +594,30 @@ is not found.
 .
 .El
 .
+.Ss Nx Ns /evbarm files
+The
+.Nx Ns /evbarm
+platform covers a wide variety of board types, many of which use
+.Sy U-boot .
+Running
+.Nm
+with no options will display a list of known boards.
+Using the verbose option will also display information about which
+.Sy U-boot
+package needs to be installed to support that board, and if the required
+.Sy U-boot
+package is installed, the path at which it is located.
+.Bl -tag -width /usr/pkg/share/u-boot
+.It Pa /usr/pkg/share/u-boot
+The default location scanned for
+.Sy U-boot
+packages with installation overlays.
+.It Pa /usr/share/installboot/evbarm/boards.plist
+Base board database, used to provide information about which
+.Sy U-boot
+package is required for a given board.
+.El
+.
 .Ss Nx Ns /evbmips files
 .
 The
@@ -649,6 +742,27 @@ Modify the command line to change the de
 "netbsd -S":
 .Dl Ic installboot -m amiga -o command="netbsd -S" /dev/rsd0a /usr/mdec/bootxx_ffs
 .
+.Ss Nx Ns /evbarm
+Install the
+.Sy U-boot
+boot loader for a Pinebook into an image that will be written to
+an SDMMC card:
+.Dl Ic installboot -m evbarm -o board=pine64,pinebook arm64.img
+.Pp
+Install / update the
+.Sy U-boot
+boot loader for the current running system on the eMMC device
+.Sq ld0
+and display verbose information about the procedure:
+.Dl Ic installboot -v /dev/rld0c
+.Pp
+Install a specific
+.Sy U-boot
+package for a BeagleBone Black into an image that will be written
+to an SDMMC card:
+.Dl Ic installboot -m evbarm -o board=ti,am335x-bone-black armv7.img \
+	/path/to/experimental/u-boot/package
+.
 .Ss Nx Ns /ews4800mips
 Install the System V Boot File System primary bootstrap on to disk
 .Sq sd0 ,

Index: src/usr.sbin/installboot/installboot.c
diff -u src/usr.sbin/installboot/installboot.c:1.39 src/usr.sbin/installboot/installboot.c:1.40
--- src/usr.sbin/installboot/installboot.c:1.39	Sat Jul 25 10:37:22 2015
+++ src/usr.sbin/installboot/installboot.c	Tue May  7 05:02:42 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: installboot.c,v 1.39 2015/07/25 10:37:22 mlelstv Exp $	*/
+/*	$NetBSD: installboot.c,v 1.40 2019/05/07 05:02:42 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
 
 #include <sys/cdefs.h>
 #if !defined(__lint)
-__RCSID("$NetBSD: installboot.c,v 1.39 2015/07/25 10:37:22 mlelstv Exp $");
+__RCSID("$NetBSD: installboot.c,v 1.40 2019/05/07 05:02:42 thorpej Exp $");
 #endif	/* !__lint */
 
 #include <sys/param.h>
@@ -56,6 +56,7 @@ __RCSID("$NetBSD: installboot.c,v 1.39 2
 #endif
 
 #include "installboot.h"
+#include "evboards.h"
 
 static	void	getmachine(ib_params *, const char *, const char *);
 static	void	getfstype(ib_params *, const char *, const char *);
@@ -92,6 +93,9 @@ const struct option {
 	{ "timeout",	IB_TIMEOUT,	OPT_INT,	OFFSET(timeout) },
 	{ "modules",	IB_MODULES,	OPT_BOOL,	0 },
 	{ "bootconf",	IB_BOOTCONF,	OPT_BOOL,	0 },
+	{ "board",	IB_BOARD,	OPT_STRING,	OFFSET(board) },
+	{ "dtb",	IB_DTB,		OPT_STRING,	OFFSET(dtb) },
+	{ "media",	IB_MEDIA,	OPT_WORD,	OFFSET(media) },
 	{ .name = NULL },
 };
 #undef OFFSET
@@ -280,16 +284,32 @@ main(int argc, char *argv[])
 		}
 	}
 
+	assert(params->machine != NULL);
+
 	if (argc >= 2) {
 		if ((params->s1fd = open(argv[1], O_RDONLY, 0600)) == -1)
 			err(1, "Opening primary bootstrap `%s'", argv[1]);
 		if (fstat(params->s1fd, &params->s1stat) == -1)
 			err(1, "Examining primary bootstrap `%s'", argv[1]);
-		if (!S_ISREG(params->s1stat.st_mode))
-			errx(1, "`%s' must be a regular file", argv[1]);
+		if (!S_ISREG(params->s1stat.st_mode)) {
+			/*
+			 * If the platform uses u-boot, then the stage1
+			 * spec might be the directory where the u-boot
+			 * binaries for the system are located.
+			 */
+			if (params->machine->mach_flags & MF_UBOOT) {
+				if (!S_ISDIR(params->s1stat.st_mode)) {
+					errx(1, "`%s' must be a regular file "
+					     "or a directory", argv[1]);
+				}
+				(void) close(params->s1fd);
+				params->s1fd = -1;
+			} else {
+				errx(1, "`%s' must be a regular file", argv[1]);
+			}
+		}
 		params->stage1 = argv[1];
 	}
-	assert(params->machine != NULL);
 
 	if (params->flags & IB_VERBOSE) {
 		printf("File system:         %s\n", params->filesystem);
@@ -299,9 +319,11 @@ main(int argc, char *argv[])
 			    params->fstype->name, params->fstype->blocksize,
 			    params->fstype->needswap);
 		if (!(params->flags & IB_EDIT))
-			printf("Primary bootstrap:   %s\n",
+			printf("Primary bootstrap:   %s%s\n",
 			    (params->flags & IB_CLEAR) ? "(to be cleared)"
-			    : params->stage1 ? params->stage1 : "(none)" );
+			    : params->stage1 ? params->stage1 : "(none)",
+			    S_ISDIR(params->s1stat.st_mode) ? " (directory)"
+			    				    : "");
 		if (params->stage2 != NULL)
 			printf("Secondary bootstrap: %s\n", params->stage2);
 	}
@@ -313,9 +335,18 @@ main(int argc, char *argv[])
 		op = "Clear";
 		rv = params->machine->clearboot(params);
 	} else {
-		if (argc < 2)
-			errx(EXIT_FAILURE, "Please specify the primary "
-			    "bootstrap file");
+		if (argc < 2) {
+			/*
+			 * If the platform uses u-boot, then the stage1 spec is
+			 * optional iff they specified a board (because we can
+			 * infer a default location for u-boot binaries if the
+			 * board type is given).
+			 */
+			if (!(params->machine->mach_flags & MF_UBOOT)) {
+				errx(EXIT_FAILURE,
+				   "Please specify the primary bootstrap file");
+			}
+		}
 		op = "Set";
 		rv = params->machine->setboot(params);
 	}
@@ -332,7 +363,7 @@ main(int argc, char *argv[])
 	}
 	if (close(params->fsfd) == -1)
 		err(1, "Closing file system `%s'", params->filesystem);
-	if (argc == 2)
+	if (params->s1fd != -1)
 		if (close(params->s1fd) == -1)
 			err(1, "Closing primary bootstrap `%s'",
 			    params->stage1);
@@ -585,5 +616,8 @@ usage(void)
 	machine_usage();
 	fstype_usage();
 	options_usage();
+	if (installboot_params.machine != NULL &&
+	    installboot_params.machine->usage != NULL)
+		installboot_params.machine->usage(&installboot_params);
 	exit(1);
 }
Index: src/usr.sbin/installboot/installboot.h
diff -u src/usr.sbin/installboot/installboot.h:1.39 src/usr.sbin/installboot/installboot.h:1.40
--- src/usr.sbin/installboot/installboot.h:1.39	Mon Feb 24 07:23:44 2014
+++ src/usr.sbin/installboot/installboot.h	Tue May  7 05:02:42 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: installboot.h,v 1.39 2014/02/24 07:23:44 skrll Exp $	*/
+/*	$NetBSD: installboot.h,v 1.40 2019/05/07 05:02:42 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -67,8 +67,19 @@ typedef enum {
 	IB_CONSADDR = 	1<<20,		/* i386 console io address */
 	IB_MODULES =	1<<21,		/* i386: load modules */
 	IB_BOOTCONF = 	1<<22,		/* i386: read boot.conf */
+
+	IB_BOARD =	1<<23,		/* evb*: board specification */
+	IB_DTB=		1<<24,		/* evb*: device tree blob */
+
+	/* IB_MEDIA is required for some evb*, but not all. */
+	IB_MEDIA =	1<<25,		/* evb*: boot media type */
 } ib_flags;
 
+typedef enum {
+
+	MF_UBOOT =	1<<0,		/* platform (maybe) uses u-boot */
+} m_flags;
+
 typedef struct {
 	ib_flags	 flags;		/* flags (see above) */
 	struct ib_mach	*machine;	/* machine details (see below) */
@@ -91,6 +102,12 @@ typedef struct {
 	const char	*password;	/* boot password */
 	int		 timeout;	/* interactive boot timeout */
 	const char	*keymap;	/* keyboard translations */
+	const char	*board;		/* board specification */
+	const char	*dtb;		/* dtb specification */
+	const char	*media;		/* boot media type */
+
+		/* temporary working data */
+	void		*mach_data;	/* platform-specific data */
 } ib_params;
 
 typedef struct {
@@ -103,7 +120,9 @@ struct ib_mach {
 	int		(*setboot)	(ib_params *);
 	int		(*clearboot)	(ib_params *);
 	int		(*editboot)	(ib_params *);
+	void		(*usage)	(ib_params *);
 	ib_flags	valid_flags;
+	m_flags		mach_flags;
 };
 
 struct ib_fs {
@@ -165,6 +184,7 @@ int		ext2fs_findstage2(ib_params *, uint
 extern struct ib_mach ib_mach_alpha;
 extern struct ib_mach ib_mach_amd64;
 extern struct ib_mach ib_mach_amiga;
+extern struct ib_mach ib_mach_evbarm;
 extern struct ib_mach ib_mach_ews4800mips;
 extern struct ib_mach ib_mach_hp300;
 extern struct ib_mach ib_mach_hppa;
Index: src/usr.sbin/installboot/machines.c
diff -u src/usr.sbin/installboot/machines.c:1.39 src/usr.sbin/installboot/machines.c:1.40
--- src/usr.sbin/installboot/machines.c:1.39	Mon Feb 24 07:23:44 2014
+++ src/usr.sbin/installboot/machines.c	Tue May  7 05:02:42 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: machines.c,v 1.39 2014/02/24 07:23:44 skrll Exp $	*/
+/*	$NetBSD: machines.c,v 1.40 2019/05/07 05:02:42 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2002-2005 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
 
 #include <sys/cdefs.h>
 #if !defined(__lint)
-__RCSID("$NetBSD: machines.c,v 1.39 2014/02/24 07:23:44 skrll Exp $");
+__RCSID("$NetBSD: machines.c,v 1.40 2019/05/07 05:02:42 thorpej Exp $");
 #endif	/* !__lint */
 
 #include <sys/types.h>
@@ -51,6 +51,7 @@ struct ib_mach
     ib_mach_amd64,
     ib_mach_amiga,
     ib_mach_emips,
+    ib_mach_evbarm,
     ib_mach_ews4800mips,
     ib_mach_hp300,
     ib_mach_hppa,
@@ -73,6 +74,7 @@ struct ib_mach * const machines[] = {
     &ib_mach_amd64,
     &ib_mach_amiga,
     &ib_mach_emips,
+    &ib_mach_evbarm,
     &ib_mach_ews4800mips,
     &ib_mach_hp300,
     &ib_mach_hppa,

Added files:

Index: src/share/installboot/Makefile
diff -u /dev/null src/share/installboot/Makefile:1.1
--- /dev/null	Tue May  7 05:02:42 2019
+++ src/share/installboot/Makefile	Tue May  7 05:02:42 2019
@@ -0,0 +1,9 @@
+#	$NetBSD: Makefile,v 1.1 2019/05/07 05:02:42 thorpej Exp $
+
+.include <bsd.own.mk>
+
+.if ${MKSHARE} != "no"
+SUBDIR=	evbarm
+.endif
+
+.include <bsd.subdir.mk>

Index: src/share/installboot/evbarm/Makefile
diff -u /dev/null src/share/installboot/evbarm/Makefile:1.1
--- /dev/null	Tue May  7 05:02:42 2019
+++ src/share/installboot/evbarm/Makefile	Tue May  7 05:02:42 2019
@@ -0,0 +1,12 @@
+#	$NetBSD: Makefile,v 1.1 2019/05/07 05:02:42 thorpej Exp $
+
+NOOBJ=		# defined
+
+.include <bsd.own.mk>
+
+.if ${MKSHARE} != "no"
+FILES=		boards.plist
+FILESDIR=	/usr/share/installboot/evbarm
+.endif
+
+.include <bsd.prog.mk>
Index: src/share/installboot/evbarm/boards.plist
diff -u /dev/null src/share/installboot/evbarm/boards.plist:1.1
--- /dev/null	Tue May  7 05:02:42 2019
+++ src/share/installboot/evbarm/boards.plist	Tue May  7 05:02:42 2019
@@ -0,0 +1,337 @@
+<!-- $NetBSD: boards.plist,v 1.1 2019/05/07 05:02:42 thorpej Exp $ -->
+<!--
+  Copyright (c) 2019 The NetBSD Foundation, Inc.
+  All rights reserved.
+ 
+  This code is derived from software contributed to The NetBSD Foundation
+  by Jason R. Thorpe.
+ 
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 
+  THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+-->
+<plist>
+<dict>
+	<!--
+	  -- amlogic boards
+	  -->
+	<key>hardkernel,odroid-c2</key>
+	<dict>
+		<key>description</key>
+		<string>Hardkernel ODROID-C2</string>
+		<key>u-boot-pkg</key>
+		<string>odroid-c2</string>
+	</dict>
+	<key>libretech,cc</key>
+	<dict>
+		<key>description</key>
+		<string>Libre Computer Board AML-S905X-CC</string>
+		<key>u-boot-pkg</key>
+		<string>libretech-cc</string>
+	</dict>
+
+	<!--
+	  -- exynos boards
+	  -->
+	<key>hardkernel,odroid-xu3</key>
+	<dict>
+		<key>description</key>
+		<string>Hardkernel Odroid XU3</string>
+		<key>u-boot-pkg</key>
+		<string>odroid-xu3</string>
+	</dict>
+
+	<!--
+	  -- rockchip boards
+	  -->
+	<key>pine64,rockpro64</key>
+	<dict>
+		<key>description</key>
+		<string>Pine64 RockPro64</string>
+		<key>u-boot-pkg</key>
+		<string>rockpro64</string>
+	</dict>
+
+	<!--
+	 -- mediatek boards
+	 -->
+	<key>bananapi,bpi-r2</key>
+	<dict>
+		<key>description</key>
+		<string>Bananapi BPI-R2</string>
+		<key>u-boot-pkg</key>
+		<string>bananapi-r2</string>
+	</dict>
+
+	<!--
+	  -- nvidia boards
+	  -->
+	<key>nvidia,jetson-tk1</key>
+	<dict>
+		<key>description</key>
+		<string>NVIDIA Tegra124 Jetson TK1</string>
+		<key>u-boot-pkg</key>
+		<string>jetson-tk1</string>
+	</dict>
+	<key>nvidia,p2371-2180</key>
+	<dict>
+		<key>description</key>
+		<string>NVIDIA Jetson TX1 Developer Kit</string>
+		<key>u-boot-pkg</key>
+		<string>jetson-tx1</string>
+	</dict>
+	<key>nvidia,p2771-0000</key>
+	<dict>
+		<key>description</key>
+		<string>NVIDIA Tegra186 P2771-0000 Development Board</string>
+		<key>u-boot-pkg</key>
+		<string>jetson-tx2</string>
+	</dict>
+
+	<!--
+	  -- omap boards
+	  -->
+	<key>ti,omap3-beagle</key>
+	<dict>
+		<key>description</key>
+		<string>TI OMAP3 BeagleBoard</string>
+		<key>u-boot-pkg</key>
+		<string>beagleboard</string>
+	</dict>
+	<key>ti,am335x-bone</key>
+	<dict>
+		<key>description</key>
+		<string>TI AM335x BeagleBone</string>
+		<key>u-boot-pkg</key>
+		<string>beaglebonewhite</string>
+	</dict>
+	<key>ti,am335x-bone-black</key>
+	<dict>
+		<key>description</key>
+		<string>TI AM335x BeagleBone Black</string>
+		<key>u-boot-pkg</key>
+		<string>beagleboneblack</string>
+	</dict>
+
+	<!--
+	  -- sunxi boards
+	  -->
+	<!-- Banana Pi-branded board "compatible" strings are a mess.
+	     We will just keep them all together here.  -->
+	<key>lemaker,bananapi</key>
+	<dict>
+		<key>description</key>
+		<string>LeMaker Banana Pi</string>
+		<key>u-boot-pkg</key>
+		<string>bananapi</string>
+	</dict>
+	<key>sinovoip,bpi-m3</key>
+	<dict>
+		<key>description</key>
+		<string>Banana Pi BPI-M3</string>
+		<key>u-boot-pkg</key>
+		<string>bananapi-m3</string>
+	</dict>
+
+	<key>cubietech,cubieboard2</key>
+	<dict>
+		<key>description</key>
+		<string>Cubietech Cubieboard2</string>
+		<key>u-boot-pkg</key>
+		<string>cubieboard2</string>
+	</dict>
+	<key>cubietech,a80-cubieboard4</key>
+	<dict>
+		<key>description</key>
+		<string>Cubietech Cubieboard4</string>
+		<key>u-boot-pkg</key>
+		<string>cubieboard4</string>
+	</dict>
+	<key>cubietech,cubietruck</key>
+	<dict>
+		<key>description</key>
+		<string>Cubietech Cubietruck</string>
+		<key>u-boot-pkg</key>
+		<string>cubietruck</string>
+	</dict>
+	<key>cubietech,cubietruck-plus</key>
+	<dict>
+		<key>description</key>
+		<string>Cubietech Cubietruck Plus</string>
+		<key>u-boot-pkg</key>
+		<string>cubietruck_plus</string>
+	</dict>
+
+	<key>friendlyarm,nanopi-m1</key>
+	<dict>
+		<key>description</key>
+		<string>FriendlyArm NanoPi M1</string>
+		<key>u-boot-pkg</key>
+		<string>nanopi-m1</string>
+	</dict>
+	<key>friendlyarm,nanopi-neo</key>
+	<dict>
+		<key>description</key>
+		<string>FriendlyARM NanoPi NEO</string>
+		<key>u-boot-pkg</key>
+		<string>nanopi-neo</string>
+	</dict>
+	<key>friendlyarm,nanopi-neo-plus2</key>
+	<dict>
+		<key>description</key>
+		<string>FriendlyARM NanoPi NEO Plus2</string>
+		<key>u-boot-pkg</key>
+		<string>nanopi-neo-plus2</string>
+	</dict>
+	<key>friendlyarm,nanopi-neo2</key>
+	<dict>
+		<key>description</key>
+		<string>FriendlyARM NanoPi NEO 2</string>
+		<key>u-boot-pkg</key>
+		<string>nanopi-neo2</string>
+	</dict>
+
+	<key>merrii,a31-hummingbird</key>
+	<dict>
+		<key>description</key>
+		<string>Merrii A31 Hummingbird</string>
+		<key>u-boot-pkg</key>
+		<string>hummingbird-a31</string>
+	</dict>
+
+	<key>nextthing,chip</key>
+	<dict>
+		<key>description</key>
+		<string>NextThing C.H.I.P.</string>
+		<key>u-boot-pkg</key>
+		<string>chip</string>
+	</dict>
+	<key>nextthing,pocketchip</key>
+	<dict>
+		<key>description</key>
+		<string>NextThing PocketC.H.I.P.</string>
+		<key>u-boot-pkg</key>
+		<string>pocketchip</string>
+	</dict>
+	<key>nextthing,chip-pro</key>
+	<dict>
+		<key>description</key>
+		<string>NextThing C.H.I.P. Pro</string>
+		<key>u-boot-pkg</key>
+		<string>chip-pro</string>
+	</dict>
+
+	<key>olimex,a10-olinuxino-lime</key>
+	<dict>
+		<key>description</key>
+		<string>Olimex A10-OLinuXino-LIME</string>
+		<key>u-boot-pkg</key>
+		<string>a10-olinuxino-lime</string>
+	</dict>
+
+	<key>pine64,pine64-plus</key>
+	<dict>
+		<key>description</key>
+		<string>Pine64+</string>
+		<key>u-boot-pkg</key>
+		<string>pine64-plus</string>
+	</dict>
+	<key>pine64,pine64</key>
+	<dict>
+		<key>description</key>
+		<string>Pine64</string>
+		<key>u-boot-pkg</key>
+		<string>pine64</string>
+	</dict>
+	<key>pine64,pinebook</key>
+	<dict>
+		<key>description</key>
+		<string>Pinebook</string>
+		<key>u-boot-pkg</key>
+		<string>pinebook</string>
+	</dict>
+	<key>pine64,sopine-baseboard</key>
+	<dict>
+		<key>description</key>
+		<string>SoPine with baseboard</string>
+		<key>u-boot-pkg</key>
+		<string>sopine-baseboard</string>
+	</dict>
+	<key>pine64,pine64-lts</key>
+	<dict>
+		<key>description</key>
+		<string>Pine64 LTS</string>
+		<!-- Same u-boot as sopine-baseboard. -->
+		<key>u-boot-pkg</key>
+		<string>sopine-baseboard</string>
+	</dict>
+	<key>pine64,pine-h64</key>
+	<dict>
+		<key>description</key>
+		<string>Pine H64</string>
+		<key>u-boot-pkg</key>
+		<string>pine-h64</string>
+	</dict>
+
+	<key>terasic,de0-atlas</key>
+	<dict>
+		<key>description</key>
+		<string>Terasic DE-0(Atlas)</string>
+		<key>u-boot-pkg</key>
+		<string>de0-nanosoc</string>
+	</dict>
+
+	<key>xunlong,orangepi-2</key>
+	<dict>
+		<key>description</key>
+		<string>Xunlong Orange Pi 2</string>
+		<key>u-boot-pkg</key>
+		<string>orangepi-2</string>
+	</dict>
+	<key>xunlong,orangepi-one</key>
+	<dict>
+		<key>description</key>
+		<string>Xunlong Orange Pi One</string>
+		<key>u-boot-pkg</key>
+		<string>orangepi-one</string>
+	</dict>
+	<key>xunlong,orangepi-plus2e</key>
+	<dict>
+		<key>description</key>
+		<string>Xunlong Orange Pi Plus 2E</string>
+		<key>u-boot-pkg</key>
+		<string>orangepi-plus2e</string>
+	</dict>
+	<key>xunlong,orangepi-zero</key>
+	<dict>
+		<key>description</key>
+		<string>Xunlong Orange Pi Zero</string>
+		<key>u-boot-pkg</key>
+		<string>orangepi-zero</string>
+	</dict>
+	<key>xunlong,orangepi-zero-plus</key>
+	<dict>
+		<key>description</key>
+		<string>Xunlong Orange Pi Zero Plus</string>
+		<key>u-boot-pkg</key>
+		<string>orangepi-zero-plus</string>
+	</dict>
+</dict>
+</plist>

Index: src/usr.sbin/installboot/evboards.c
diff -u /dev/null src/usr.sbin/installboot/evboards.c:1.1
--- /dev/null	Tue May  7 05:02:42 2019
+++ src/usr.sbin/installboot/evboards.c	Tue May  7 05:02:42 2019
@@ -0,0 +1,1655 @@
+/*	$NetBSD: evboards.c,v 1.1 2019/05/07 05:02:42 thorpej Exp $	*/
+
+/*-
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: evboards.c,v 1.1 2019/05/07 05:02:42 thorpej Exp $");
+#endif  /* !__lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef SUPPORT_FDT
+#include "libfdt.h"
+#endif
+
+#if !HAVE_NBTOOL_CONFIG_H
+#include <sys/utsname.h>
+
+#ifdef SUPPORT_OPENFIRMWARE
+#include <sys/ioctl.h>
+#include <dev/ofw/openfirmio.h>
+#endif
+
+#endif /* ! HAVE_NBTOOL_CONFIG_H */
+
+#include "installboot.h"
+#include "evboards.h"
+
+/*
+ * The board database is implemented as a property list.  The base
+ * system provides a set of known boards, keyed by their "compatible"
+ * device tree property.
+ *
+ * The database provided by the base system is meant to help guide
+ * the user as to which u-boot package needs to be installed on the
+ * system in order to write the boot loader to the boot media.  The
+ * base board plist is specific to the $MACHINE (e.g. "evbarm"), and
+ * is installed along with the build tools, e.g.:
+ *
+ * (native location)
+ *	/usr/sbin/installboot
+ *	/usr/share/installboot/evbarm/boards.plist
+ *	/usr/share/installboot/evbmips/boards.plist
+ *
+ * (example cross host tool location)
+ *	/usr/local/xnbsd/bin/nbinstallboot
+ *	/usr/local/xnbsd/share/installboot/evbarm/boards.plist
+ *	/usr/local/xnbsd/share/installboot/evbmips/boards.plist
+ *
+ * The schema of the base board plist is as follows:
+ *
+ * <plist>
+ * <dict>
+ *	<!--
+ *	  -- Key: string matching a "compatible" DT property.
+ *	  -- Value: dictionary representing a board object.
+ *	  -- (required)
+ *	  -->
+ *	<key>example,example-board</key>
+ *	<dict>
+ *		<!--
+ *		  -- Key: "description".
+ *		  -- Value: string containing the board description.
+ *		  -- (required)
+ *		  -->
+ *		<key>description</key>
+ *		<string>Example Co. Example Board</string>
+ *
+ *		<!--
+ *		  -- Key: "u-boot-pkg".
+ *		  -- Value: string representing the board-specific
+ *		  --        portion of the u-boot package name.
+ *		  --        In this example, the package's full name
+ *		  --        is "u-boot-exampleboard".  This is used
+ *		  --        to recommend to the user which u-boot
+ *		  --        package to install.  If not present, then
+ *		  --        no package recommendation will be made.
+ *		  -- (optional)
+ *		  -->
+ *		<key>u-boot-pkg</key>
+ *		<string>exampleboard</string>
+ *	</dict>
+ * </dict>
+ * </plist>
+ *
+ * Individual u-boot packages install their own overlay property list
+ * files that installboot(8) then scans for.  These overlay files are
+ * named "installboot.plist", and are installed alongside the u-boot
+ * binaries by the individual u-boot packages, for example:
+ *
+ *	/usr/pkg/share/u-boot/exampleboard/installboot.plist
+ *	/usr/pkg/share/u-boot/exampleboard/u-boot-with-spl.bin
+ *
+ * installboot(8) scans a set of directories looking for "installboot.plist"
+ * overlay files one directory deep.  For example:
+ *
+ *	/usr/pkg/share/u-boot/
+ *				exampleboard/installboot.plist
+ *				superarmdeluxe/installboot.plist
+ *				dummy/
+ *
+ * In this example, "/usr/pkg/share/u-boot" is scanned, it would identify
+ * "exampleboard" and "superarmdeluxe" as directories containing overlays
+ * and load them.
+ *
+ * The default path scanned for u-boot packages is:
+ *
+ *	/usr/pkg/share/u-boot
+ *
+ * This can be overridden with the INSTALLBOOT_UBOOT_PATHS environment
+ * variable, which contains a colon-sparated list of directories, e.g.:
+ *
+ *	/usr/pkg/share/u-boot:/home/jmcneill/hackityhack/u-boot
+ *
+ * The scan only consults the top-level children of the specified directory.
+ *
+ * Each overlay includes complete board objects that entirely replace
+ * the system-provided board objects in memory.  Some of the keys in
+ * overlay board objects are computed at run-time and should not appear
+ * in the plists loaded from the file system.
+ *
+ * The schema of the overlay board plists are as follows:
+ *
+ * <plist>
+ * <dict>
+ *	<!--
+ *	  -- Key: string matching a "compatible" DT property.
+ *	  -- Value: dictionary representing a board object.
+ *	  -- (required)
+ *	  -->
+ *	<key>example,example-board</key>
+ *	<dict>
+ *		<!--
+ *		  -- Key: "description".
+ *		  -- Value: string containing the board description.
+ *		  -- (required)
+ *		  -->
+ *		<key>description</key>
+ *		<string>Example Co. Example Board</string>
+ *
+ *		<!--
+ *		  -- Key: "u-boot-install".
+ *		  --      (and variants; see discussion below)
+ *		  --      "u-boot-install-emmc", etc.).
+ *		  -- Value: Array of u-boot installation step objects,
+ *		  --        as described below.
+ *		  -- (required)
+ *		  --
+ *		  -- At least one of these objects is required.  If the
+ *		  -- board uses a single set of steps for all boot media
+ *		  -- types, then it should provide just "u-boot-install".
+ *		  -- Otherwise, it whould provide one or more objects
+ *		  -- with names reflecting the media type, e.g.:
+ *		  --
+ *		  --	"u-boot-install-sdmmc"	(for SD cards)
+ *		  --	"u-boot-install-emmc"	(for eMMC modules)
+ *		  --	"u-boot-install-usb"	(for USB block storage)
+ *		  --
+ *		  -- These installation steps will be selectable using
+ *		  -- the "media=..." option to installboot(8).
+ *		  -->
+ *		<key>u-boot-install</key>
+ *		<array>
+ *			<!-- see installation object discussion below. -->
+ *		</array>
+ *
+ *		<!--
+ *		  -- Key: "runtime-u-boot-path"
+ *		  -- Value: A string representing the path to the u-boot
+ *		  --        binary files needed to install the boot loader.
+ *		  --        This value is computed at run-time and is the
+ *		  --        same directory in which the instalboot.plist
+ *		  --        file for that u-boot package is located.
+ *		  --        This key/value pair should never be included
+ *		  --        in an installboot.plist file, and including it
+ *		  --	    will cause the overlay to be rejected.
+ *		  -- (computed at run-time)
+ *		  -->
+ *		<key>runtime-u-boot-path</key>
+ *		<string>/usr/pkg/share/u-boot/exampleboard</string>
+ *	</dict>
+ * </dict>
+ * </plist>
+ *
+ * The installation objects provide a description of the steps needed
+ * to install u-boot on the boot media.  Each installation object it
+ * itself an array of step object.
+ *
+ * A basic installation object has a single step that instructs
+ * installboot(8) to write a file to a specific offset onto the
+ * boot media.
+ *
+ *	<key>u-boot-install</key>
+ *	<!-- installation object -->
+ *	<array>
+ *		<!-- step object -->
+ *		<dict>
+ *			<!--
+ *			  -- Key: "file-name".
+ *			  -- Value: a string naming the file to be
+ *			  --        written to the media.
+ *			  -- (required)
+ *			  -->
+ *			<key>file-name</key>
+ *			<string>u-boot-with-spl.bin</string>
+ *
+ *			<!--
+ *			  -- Key: "image-offset".
+ *			  -- Value: an integer specifying the offset
+ *			  --        into the output image or device
+ *			  --        where to write the file.  Defaults
+ *			  --        to 0 if not specified.
+ *			  -- (optional)
+ *			  -->
+ *			<key>image-offset</key>
+ *			<integer>8192</integer>
+ *		</dict>
+ *	</array>
+ *
+ * Some installations require multiple steps with special handling.
+ *
+ *	<key>u-boot-install</key>
+ *	<array>
+ *		<--
+ *		 -- Step 1: Write the initial portion of the boot
+ *		 -- loader onto the media.  The loader has a "hole"
+ *		 -- to leave room for the MBR partition table.  Take
+ *		 -- care not to scribble over the table.
+ *		 -->
+ *		<dict>
+ *			<key>file-name</key>
+ *			<string>u-boot-img.bin</string>
+ *
+ *			<!--
+ *			  -- Key: "file-size".
+ *			  -- Value: an integer specifying the amount of
+ *			  --        data from the file to be written to the
+ *			  --        output.  Defaults to "to end of file" if
+ *			  --        not specified.
+ *			  -- (optional)
+ *			  -->
+ *			<!-- Stop short of the MBR partition table. -->
+ *			<key>file-size</key>
+ *			<integer>442</integer>
+ *
+ *			<!--
+ *			  -- Key: "preserve".
+ *			  -- Value: a boolean indicating that any partial
+ *			  --        output block should preserve any pre-
+ *			  --        existing contents of that block for
+ *			  --        the portion of the of the block not
+ *			  --        overwritten by the input file.
+ *			  --        (read-modify-write)
+ *			  -- (optional)
+ *			  -->
+ *			<!-- Preserve the MBR partition table. -->
+ *			<key>preserve</key>
+ *			<true/>
+ *		</dict>
+ *		<--
+ *		 -- Step 2: Write the rest of the loader after the
+ *		 -- MBR partition table.
+ *		 -->
+ *		<dict>
+ *			<key>file-name</key>
+ *			<string>u-boot-img.bin</string>
+ *
+ *			<!--
+ *			  -- Key: "file-offset".
+ *			  -- Value: an integer specifying the offset into
+ *			  --        the input file from where to start
+ *			  --        copying to the output.
+ *			  -- (optional)
+ *			  -->
+ *			<key>file-offset</key>
+ *			<integer>512</integer>
+ *
+ *			<!-- ...just after the MBR partition talble. -->
+ *			<key>image-offset</key>
+ *			<integer>512</integer>
+ *		</dict>
+ *	</array>
+ */
+
+/*
+ * make_path --
+ *	Build a path into the given buffer with the specified
+ *	format.  Returns NULL if the path won't fit.
+ */
+static const char *
+make_path(char *buf, size_t bufsize, const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+
+	va_start(ap, fmt);
+	ret = vsnprintf(buf, bufsize, fmt, ap);
+	va_end(ap);
+
+	if (ret < 0 || (size_t)ret >= bufsize)
+		return NULL;
+
+	return buf;
+}
+
+#ifndef EVBOARDS_PLIST_BASE
+#define	EVBOARDS_PLIST_BASE	"/usr"
+#endif
+
+static const char evb_db_base_location[] =
+    EVBOARDS_PLIST_BASE "/share/installboot";
+
+#ifndef DEFAULT_UBOOT_PKG_PATH
+#define	DEFAULT_UBOOT_PKG_PATH	"/usr/pkg/share/u-boot"
+#endif
+
+#ifndef UBOOT_PATHS_ENV_VAR
+#define	UBOOT_PATHS_ENV_VAR	"INSTALLBOOT_UBOOT_PATHS"
+#endif
+
+static const char evb_uboot_pkg_path[] = DEFAULT_UBOOT_PKG_PATH;
+
+/*
+ * evb_db_base_path --
+ *	Returns the path to the base board db file.
+ */
+static const char *
+evb_db_base_path(ib_params *params, char *buf, size_t bufsize)
+{
+
+	return make_path(buf, bufsize, "%s/%s/boards.plist",
+	    evb_db_base_location, params->machine->name);
+}
+
+/*
+ * evb_uboot_pkg_paths --
+ *	Returns an array of u-boot package paths to scan for
+ *	installboot.plist files.
+ *
+ *	Number of array elements, not including the NULL terminator,
+ *	is returned in *countp.
+ *
+ *	The working buffer is returned in *bufp so that the caller
+ *	can free it.
+ */
+static char **
+evb_uboot_pkg_paths(ib_params *params, int *countp, void **bufp)
+{
+	char **ret_array = NULL;
+	char *buf = NULL;
+	const char *pathspec;
+	int i, count;
+	char *cp, *startcp;;
+
+	pathspec = getenv(UBOOT_PATHS_ENV_VAR);
+	if (pathspec == NULL)
+		pathspec = evb_uboot_pkg_path;
+
+	if (strlen(pathspec) == 0)
+		goto out;
+
+	/* Count the path elements. */
+	for (cp = __UNCONST(pathspec), count = 0;;) {
+		count++;
+		cp = strchr(cp, ':');
+		if (cp == NULL)
+			break;
+		cp++;
+	}
+
+	buf = malloc((sizeof(char *) * (count + 1)) +
+		     strlen(pathspec) + 1);
+	if (buf == NULL)
+		goto out;
+
+	/*
+	 * Because we want to follow the usual "paths are listed in priority
+	 * order" semantics, we reverse the order of the paths when we put
+	 * them into the array we feed to fts.  This is because we always
+	 * overwrite existing entries as we find them, thus the last board
+	 * object found one a given key is the one that will be used.
+	 */
+
+	ret_array = (char **)buf;
+	startcp = buf + (sizeof(char *) * (count + 1));
+	/* this is a safe strcpy(); don't replace it. */
+	strcpy(startcp, pathspec);
+
+	cp = strrchr(startcp, ':');
+	if (cp == NULL)
+		cp = startcp;
+
+	for (i = 0;;) {
+		if (*cp == ':') {
+			ret_array[i++] = cp+1;
+			*cp-- = '\0';
+		} else
+			ret_array[i++] = cp;
+		if (cp == startcp)
+			break;
+		cp = strrchr(cp, ':');
+		if (cp == NULL)
+			cp = startcp;
+	}
+	assert(i == count);
+	ret_array[i] = NULL;
+
+ out:
+	if (ret_array == NULL) {
+		if (buf != NULL)
+			free(buf);
+	} else {
+		if (countp != NULL)
+			*countp = count;
+		if (bufp != NULL)
+			*bufp = buf;
+	}
+	return ret_array;
+}
+
+static const char step_file_name_key[] = "file-name";
+static const char step_file_offset_key[] = "file-offset";
+static const char step_file_size_key[] = "file-size";
+static const char step_image_offset_key[] = "image-offset";
+static const char step_preserve_key[] = "preserve";
+
+static bool
+validate_ubstep_object(evb_ubstep obj)
+{
+	/*
+	 * evb_ubstep is a dictionary with the following keys:
+	 *
+	 *	"file-name"	(string) (required)
+	 *	"file-offset"	(number) (optional)
+	 *	"file-size"	(number) (optional)
+	 *	"image-offset"	(number) (optional)
+	 *	"preserve"	(bool)	 (optional)
+	 */
+	if (prop_object_type(obj) != PROP_TYPE_DICTIONARY)
+		return false;
+
+	prop_object_t v;
+
+	v = prop_dictionary_get(obj, step_file_name_key);
+	if (v == NULL ||
+	    prop_object_type(v) != PROP_TYPE_STRING)
+	    	return false;
+
+	v = prop_dictionary_get(obj, step_file_offset_key);
+	if (v != NULL &&
+	    prop_object_type(v) != PROP_TYPE_NUMBER)
+	    	return false;
+
+	v = prop_dictionary_get(obj, step_file_size_key);
+	if (v != NULL &&
+	    prop_object_type(v) != PROP_TYPE_NUMBER)
+	    	return false;
+
+	v = prop_dictionary_get(obj, step_image_offset_key);
+	if (v != NULL &&
+	    prop_object_type(v) != PROP_TYPE_NUMBER)
+	    	return false;
+
+	v = prop_dictionary_get(obj, step_preserve_key);
+	if (v != NULL &&
+	    prop_object_type(v) != PROP_TYPE_BOOL)
+	    	return false;
+
+	return true;
+}
+
+static bool
+validate_ubinstall_object(evb_ubinstall obj)
+{
+	/*
+	 * evb_ubinstall is an array with one or more evb_ubstep
+	 * objects.
+	 *
+	 * (evb_ubsteps is just a convenience type for iterating
+	 * over the steps.)
+	 */
+	if (prop_object_type(obj) != PROP_TYPE_ARRAY)
+		return false;
+	if (prop_array_count(obj) < 1)
+		return false;
+
+	prop_object_t v;
+	prop_object_iterator_t iter = prop_array_iterator(obj);
+
+	while ((v = prop_object_iterator_next(iter)) != NULL) {
+		if (!validate_ubstep_object(v))
+			break;
+	}
+
+	prop_object_iterator_release(iter);
+	return v == NULL;
+}
+
+static const char board_description_key[] = "description";
+static const char board_u_boot_pkg_key[] = "u-boot-pkg";
+static const char board_u_boot_path_key[] = "runtime-u-boot-path";
+static const char board_u_boot_install_key[] = "u-boot-install";
+
+static bool
+validate_board_object(evb_board obj, bool is_overlay)
+{
+	/*
+	 * evb_board is a dictionary with the following keys:
+	 *
+	 *	"description"		(string) (required)
+	 *	"u-boot-pkg"		(string) (optional, base only)
+	 *	"runtime-u-boot-path"	(string) (required, overlay only)
+	 *
+	 * With special consideration for these keys:
+	 *
+	 * Either this key and no other "u-boot-install*" keys:
+	 *	"u-boot-install"	(string) (required, overlay only)
+	 *
+	 * Or one or more keys of the following pattern:
+	 *	"u-boot-install-*"	(string) (required, overlay only)
+	 */
+	bool has_default_install = false;
+	bool has_media_install = false;
+
+	if (prop_object_type(obj) != PROP_TYPE_DICTIONARY)
+		return false;
+
+	prop_object_t v;
+
+	v = prop_dictionary_get(obj, board_description_key);
+	if (v == NULL ||
+	    prop_object_type(v) != PROP_TYPE_STRING)
+	    	return false;
+
+	v = prop_dictionary_get(obj, board_u_boot_pkg_key);
+	if (v != NULL &&
+	    (is_overlay || prop_object_type(v) != PROP_TYPE_STRING))
+	    	return false;
+
+	/*
+	 * "runtime-u-boot-path" is added to an overlay after we've
+	 * validated the board object, so simply make sure it's not
+	 * present.
+	 */
+	v = prop_dictionary_get(obj, board_u_boot_path_key);
+	if (v != NULL)
+		return false;
+
+	prop_object_iterator_t iter = prop_dictionary_iterator(obj);
+	prop_dictionary_keysym_t key;
+	while ((key = prop_object_iterator_next(iter)) != NULL) {
+		const char *cp = prop_dictionary_keysym_cstring_nocopy(key);
+		if (strcmp(cp, board_u_boot_install_key) == 0) {
+			has_default_install = true;
+		} else if (strncmp(cp, board_u_boot_install_key,
+				   sizeof(board_u_boot_install_key) - 1) == 0 &&
+			   cp[sizeof(board_u_boot_install_key) - 1] == '-') {
+			has_media_install = true;
+		} else {
+			continue;
+		}
+		v = prop_dictionary_get_keysym(obj, key);
+		assert(v != NULL);
+		if (!is_overlay || !validate_ubinstall_object(v))
+			break;
+	}
+	prop_object_iterator_release(iter);
+	if (key != NULL)
+		return false;
+
+	/*
+	 * Overlays must have only a default install key OR one or more
+	 * media install keys.
+	 */
+	if (is_overlay)
+		return has_default_install ^ has_media_install;
+
+	/*
+	 * Base board objects must have neither.
+	 */
+	return (has_default_install | has_media_install) == false;
+}
+
+/*
+ * evb_db_load_overlay --
+ *	Load boards from an overlay file into the db.
+ */
+static void
+evb_db_load_overlay(ib_params *params, const char *path,
+    const char *runtime_uboot_path)
+{
+	prop_dictionary_t overlay;
+	struct stat sb;
+
+	if (params->flags & IB_VERBOSE)
+		printf("Loading '%s'.\n", path);
+
+	if (stat(path, &sb) < 0) {
+		warn("'%s'", path);
+		return;
+	} else {
+		overlay = prop_dictionary_internalize_from_file(path);
+		if (overlay == NULL) {
+			warnx("unable to parse overlay '%s'", path);
+			return;
+		}
+	}
+
+	/*
+	 * Validate all of the board objects and add them to the board
+	 * db, replacing any existing entries as we go.
+	 */
+	prop_object_iterator_t iter = prop_dictionary_iterator(overlay);
+	prop_dictionary_keysym_t key;
+	prop_dictionary_t board;
+	while ((key = prop_object_iterator_next(iter)) != NULL) {
+		board = prop_dictionary_get_keysym(overlay, key);
+		assert(board != NULL);
+		if (!validate_board_object(board, true)) {
+			warnx("invalid board object in '%s': '%s'", path,
+			    prop_dictionary_keysym_cstring_nocopy(key));
+			continue;
+		}
+
+		/* Add "runtime-u-boot-path". */
+		prop_string_t string =
+		    prop_string_create_cstring(runtime_uboot_path);
+		assert(string != NULL);
+		prop_dictionary_set(board, board_u_boot_path_key, string);
+		prop_object_release(string);
+
+		/* Insert into board db. */
+		prop_dictionary_set_keysym(params->mach_data, key, board);
+	}
+	prop_object_iterator_release(iter);
+	prop_object_release(overlay);
+}
+
+/*
+ * evb_db_load_overlays --
+ *	Load the overlays from the search path.
+ */
+static void
+evb_db_load_overlays(ib_params *params)
+{
+	char overlay_pathbuf[PATH_MAX+1];
+	const char *overlay_path;
+	char **paths;
+	void *pathsbuf = NULL;
+	FTS *fts;
+	FTSENT *chp, *p;
+	struct stat sb;
+
+	paths = evb_uboot_pkg_paths(params, NULL, &pathsbuf);
+	if (paths == NULL) {
+		warnx("No u-boot search path?");
+		return;
+	}
+
+	fts = fts_open(paths, FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR, NULL);
+	if (fts == NULL ||
+	    (chp = fts_children(fts, 0)) == NULL) {
+		warn("Unable to search u-boot path");
+		if (fts != NULL)
+			fts_close(fts);
+		return;
+	}
+
+	chp = fts_children(fts, 0);
+
+	while ((p = fts_read(fts)) != NULL) {
+		if (p->fts_info != FTS_D)
+			continue;
+		overlay_path = make_path(overlay_pathbuf,
+		    sizeof(overlay_pathbuf), "%s/installboot.plist",
+		    p->fts_path);
+		if (overlay_path == NULL)
+			continue;
+		if (stat(overlay_path, &sb) < 0)
+			continue;
+		evb_db_load_overlay(params, overlay_path, p->fts_path);
+	}
+
+	fts_close(fts);
+
+	/*
+	 * If the user specifed a stage1 loader, then consult it last
+	 * for a possible u-boot package location.
+	 */
+	if (params->stage1 != NULL) {
+		overlay_path = make_path(overlay_pathbuf,
+		    sizeof(overlay_pathbuf), "%s/installboot.plist",
+		    params->stage1);
+		if (overlay_path != NULL) {
+			if (stat(overlay_path, &sb) == 0) {
+				evb_db_load_overlay(params, overlay_path,
+				    params->stage1);
+			}
+		}
+	}
+}
+
+/*
+ * evb_db_load_base --
+ *	Load the base board db.
+ */
+static bool
+evb_db_load_base(ib_params *params)
+{
+	char buf[PATH_MAX+1];
+	const char *path;
+	prop_dictionary_t board_db;
+	struct stat sb;
+
+	path = evb_db_base_path(params, buf, sizeof(buf));
+	if (path == NULL)
+		return false;
+
+	if (params->flags & IB_VERBOSE)
+		printf("Loading '%s'.\n", path);
+
+	if (stat(path, &sb) < 0) {
+		if (errno != ENOENT) {
+			warn("'%s'", path);
+			return false;
+		}
+		board_db = prop_dictionary_create();
+		assert(board_db != NULL);
+	} else {
+		board_db = prop_dictionary_internalize_from_file(path);
+		if (board_db == NULL) {
+			warnx("unable to parse board db '%s'", path);
+			return false;
+		}
+	}
+
+	if (prop_dictionary_count(board_db) == 0) {
+		/*
+		 * Oh well, maybe we'll load some overlays.
+		 */
+		goto done;
+	}
+
+	/*
+	 * Validate all of the board objects and remove any bad ones.
+	 */
+	prop_array_t all_board_keys = prop_dictionary_all_keys(board_db);
+	prop_object_iterator_t iter = prop_array_iterator(all_board_keys);
+	prop_dictionary_keysym_t key;
+	prop_dictionary_t board;
+	while ((key = prop_object_iterator_next(iter)) != NULL) {
+		board = prop_dictionary_get_keysym(board_db, key);
+		assert(board != NULL);
+		if (!validate_board_object(board, false)) {
+			warnx("invalid board object in '%s': '%s'", path,
+			    prop_dictionary_keysym_cstring_nocopy(key));
+			prop_dictionary_remove_keysym(board_db, key);
+		}
+	}
+	prop_object_iterator_release(iter);
+	prop_object_release(all_board_keys);
+
+ done:
+	params->mach_data = board_db;
+	return true;
+}
+
+/*
+ * evb_db_load --
+ *	Load the board database.
+ */
+bool
+evb_db_load(ib_params *params)
+{
+	if (!evb_db_load_base(params))
+		return false;
+	evb_db_load_overlays(params);
+
+	return true;
+}
+
+#if !HAVE_NBTOOL_CONFIG_H
+/*
+ * Native board name guessing methods.
+ */
+
+#ifdef SUPPORT_OPENFIRMWARE
+static int
+ofw_fd(void)
+{
+	static const char openfirm_path[] = "/dev/openfirm";
+
+	return open(openfirm_path, O_RDONLY);
+}
+
+static int
+OF_finddevice(const char *name)
+{
+	struct ofiocdesc ofio = {
+		.of_name = __UNCONST(name),
+		.of_namelen = strlen(name),
+	};
+	int fd = ofw_fd();
+
+	if (fd == -1)
+		return -1;
+
+	if (ioctl(fd, OFIOCFINDDEVICE, &ofio) < 0) {
+		if (errno != ENOENT)
+			warn("OFIOCFINDDEVICE('%s')", name);
+		ofio.of_nodeid = -1;
+	}
+	(void) close(fd);
+
+	return ofio.of_nodeid;
+}
+
+static int
+OF_getprop(int phandle, const char *prop, void *buf, size_t buflen)
+{
+	struct ofiocdesc ofio = {
+		.of_nodeid = phandle,
+		.of_name = __UNCONST(prop),
+		.of_namelen = strlen(prop),
+		.of_buf = buf,
+		.of_buflen = buflen,
+	};
+	int fd = ofw_fd();
+
+	if (fd == -1)
+		return -1;
+
+	int save_errno = 0;
+
+	if (ioctl(fd, OFIOCGET, &ofio) < 0) {
+		save_errno = errno;
+		if (errno != ENOMEM && errno != ENOENT) {
+			save_errno = errno;
+			warn("OFIOCGET('%s')", prop);
+		}
+		ofio.of_buflen = -1;
+	}
+	(void) close(fd);
+	errno = save_errno;
+
+	return ofio.of_buflen;
+}
+
+static void *
+ofw_getprop(int phandle, const char *prop, int *lenp)
+{
+	size_t buflen = 32;
+	void *buf = NULL;
+	int len;
+
+	for (;;) {
+		void *newbuf = realloc(buf, buflen);
+		if (newbuf == NULL) {
+			free(buf);
+			return NULL;
+		}
+		buf = newbuf;
+		switch (len = OF_getprop(phandle, prop, buf, buflen)) {
+		case -1:
+			if (errno != ENOMEM) {
+				free(buf);
+				return NULL;
+			}
+			buflen *= 2;
+			break;
+
+		default:
+			if (lenp)
+				*lenp = len;
+			return buf;
+		}
+	}
+}
+
+static evb_board
+evb_db_get_board_from_ofw(ib_params *params, const char **board_namep)
+{
+	int phandle;
+	int compatible_len = 0;
+	char *compatible_buf;
+	const char *sp, *nsp;
+	evb_board board;
+
+	phandle = OF_finddevice("/");
+	if (phandle == -1) {
+		/* No OpenFirmware available. */
+		return NULL;
+	}
+
+	compatible_buf = ofw_getprop(phandle, "compatible", &compatible_len);
+
+	/*
+	 * We just leak compatible_buf on success.  Not a big deal since
+	 * we are not a long-running process.
+	 */
+
+	sp = compatible_buf;
+	while (compatible_len &&
+	       (nsp = memchr(sp, 0, compatible_len)) != NULL) {
+		if (params->flags & IB_VERBOSE)
+			printf("Checking OFW compatible string '%s'.\n", sp);
+		board = prop_dictionary_get(params->mach_data, sp);
+		if (board != NULL) {
+			if (board_namep)
+				*board_namep = sp;
+			return board;
+		}
+		nsp++;	/* skip over NUL */
+		compatible_len -= (nsp - sp);
+		sp = nsp;
+	}
+
+	free(compatible_buf);
+	return NULL;
+}
+#endif /* SUPPORT_OPENFIRMWARE */
+
+#endif /* ! HAVE_NBTOOL_CONFIG_H */
+
+/*
+ * Host-tool and native board name guessing methods.
+ */
+
+#ifdef SUPPORT_FDT
+static void *
+load_dtb(ib_params *params)
+{
+	struct stat sb;
+	void *buf;
+	int fd;
+
+	if (stat(params->dtb, &sb) < 0) {
+		warn("%s", params->dtb);
+		return NULL;
+	}
+
+	buf = malloc((size_t)sb.st_size);
+	assert(buf != NULL);
+
+	if ((fd = open(params->dtb, O_RDONLY)) < 0) {
+		warn("%s", params->dtb);
+		free(buf);
+		return NULL;
+	}
+
+	if (read(fd, buf, (size_t)sb.st_size) != (ssize_t)sb.st_size) {
+		warn("read '%s'", params->dtb);
+		free(buf);
+		buf = NULL;
+	}
+	(void) close(fd);
+
+	return buf;
+}
+
+static evb_board
+evb_db_get_board_from_dtb(ib_params *params, const char **board_namep)
+{
+	evb_board board = NULL;
+	void *fdt = NULL;
+	int error;
+
+	fdt = load_dtb(params);
+	if (fdt == NULL)
+		return NULL;
+
+	error = fdt_check_header(fdt);
+	if (error) {
+		warnx("%s: %s", params->dtb, fdt_strerror(error));
+		goto bad;
+	}
+
+	const int system_root = fdt_path_offset(fdt, "/");
+	if (system_root < 0) {
+		warnx("%s: unable to find node '/'", params->dtb);
+		goto bad;
+	}
+
+	const int system_ncompat = fdt_stringlist_count(fdt, system_root,
+	    "compatible");
+	if (system_ncompat <= 0) {
+		warnx("%s: no 'compatible' property on node '/'", params->dtb);
+		goto bad;
+	}
+
+	const char *compatible;
+	int si;
+	for (si = 0; si < system_ncompat; si++) {
+		compatible = fdt_stringlist_get(fdt, system_root,
+		    "compatible", si, NULL);
+		if (compatible == NULL)
+			continue;
+		if (params->flags & IB_VERBOSE)
+			printf("Checking FDT compatible string '%s'.\n",
+			    compatible);
+		board = prop_dictionary_get(params->mach_data, compatible);
+		if (board != NULL) {
+			/*
+			 * We just leak compatible on success.  Not a big
+			 * deal since we are not a long-running process.
+			 */
+			if (board_namep) {
+				*board_namep = strdup(compatible);
+				assert(*board_namep != NULL);
+			}
+			free(fdt);
+			return board;
+		}
+	}
+
+ bad:
+	if (fdt != NULL)
+		free(fdt);
+	return NULL;
+}
+#endif /* SUPPORT_FDT */
+
+/*
+ * evb_db_get_board --
+ *	Return the specified board object from the database.
+ */
+evb_board
+evb_db_get_board(ib_params *params)
+{
+	const char *board_name = NULL;
+	evb_board board = NULL;
+
+#if !HAVE_NBTOOL_CONFIG_H
+	/*
+	 * If we're not a host tool, determine if we're running "natively".
+	 */
+	bool is_native = false;
+	struct utsname utsname;
+
+	if (uname(&utsname) < 0) {
+		warn("uname");
+	} else if (strcmp(utsname.machine, params->machine->name) == 0) {
+		is_native = true;
+	}
+#endif /* ! HAVE_NBTOOL_CONFIG_H */
+
+	/*
+	 * Logic for determing board type that can be shared by host-tool
+	 * and native builds goes here.
+	 */
+
+	/*
+	 * Command-line argument trumps all.
+	 */
+	if (params->flags & IB_BOARD) {
+		board_name = params->board;
+	}
+
+#ifdef SUPPORT_FDT
+	if (board_name == NULL && (params->flags & IB_DTB)) {
+		board = evb_db_get_board_from_dtb(params, &board_name);
+		if ((params->flags & IB_VERBOSE) && board != NULL)
+			printf("Found board '%s' from DTB data.\n", board_name);
+#if !HAVE_NBTOOL_CONFIG_H
+		/*
+		 * If the user specified a DTB, then regardless of the
+		 * outcome, this is like specifying the board directly,
+		 * so native checks should be skipped.
+		 */
+		is_native = false;
+#endif /* ! HAVE_NBTOOL_CONFIG_H */
+	}
+#endif /* SUPPORT_FDT */
+
+#if !HAVE_NBTOOL_CONFIG_H
+	/*
+	 * Non-host-tool logic for determining the board type goes here.
+	 */
+
+#ifdef SUPPORT_OPENFIRMWARE
+	if (board_name == NULL && is_native) {
+		board = evb_db_get_board_from_ofw(params, &board_name);
+		if ((params->flags & IB_VERBOSE) && board != NULL)
+			printf("Found board '%s' from OFW data.\n", board_name);
+	}
+#endif /* SUPPORT_OPENFIRMWARE */
+
+	/* Ensure is_native is consumed. */
+	if (is_native == false)
+		is_native = false;
+
+#endif /* ! HAVE_NBTOOL_CONFIG_H */
+
+	/*
+	 * If all else fails, we can always rely on the user, right?
+	 */
+	if (board_name == NULL) {
+		if (!(params->flags & IB_BOARD)) {
+			warnx("Must specify board=...");
+			return NULL;
+		}
+		board_name = params->board;
+	}
+
+	assert(board_name != NULL);
+
+	if (board == NULL)
+		board = prop_dictionary_get(params->mach_data, board_name);
+	if (board == NULL)
+		warnx("Unknown board '%s'", board_name);
+
+	/* Ensure params->board is always valid. */
+	params->board = board_name;
+
+	if (params->flags & IB_VERBOSE) {
+		printf("Board: %s\n", evb_board_get_description(params, board));
+	}
+
+	return board;
+}
+
+/*
+ * evb_db_list_boards --
+ *	Print the list of known boards to the specified output stream.
+ */
+void
+evb_db_list_boards(ib_params *params, FILE *out)
+{
+	prop_object_iterator_t iter;
+	prop_dictionary_keysym_t key;
+	evb_board board;
+	const char *uboot_pkg;
+	const char *uboot_path;
+
+	/*
+	 * By default, we only list boards that we have a u-boot
+	 * package installed for, or if we know which package you
+	 * need to install.  You get the full monty in verbose mode.
+	 */
+
+	iter = prop_dictionary_iterator(params->mach_data);
+	while ((key = prop_object_iterator_next(iter)) != NULL) {
+		board = prop_dictionary_get_keysym(params->mach_data, key);
+		assert(board != NULL);
+		uboot_pkg = evb_board_get_uboot_pkg(params, board);
+		uboot_path = evb_board_get_uboot_path(params, board);
+
+		if (uboot_pkg == NULL && uboot_path == NULL &&
+		    !(params->flags & IB_VERBOSE))
+			continue;
+
+		fprintf(out, "%-30s %s\n",
+		    prop_dictionary_keysym_cstring_nocopy(key),
+		    evb_board_get_description(params, board));
+
+		if ((params->flags & IB_VERBOSE) && uboot_path) {
+			fprintf(out, "\t(u-boot package found at %s)\n",
+			    uboot_path);
+		} else if ((params->flags & IB_VERBOSE) && uboot_pkg) {
+			fprintf(out,
+			    "\t(install the sysutils/u-boot-%s package)\n",
+			    uboot_pkg);
+		}
+	}
+	prop_object_iterator_release(iter);
+}
+
+/*
+ * evb_board_get_description --
+ *	Return the description for the specified board.
+ */
+const char *
+evb_board_get_description(ib_params *params, evb_board board)
+{
+	prop_string_t string;
+
+	string = prop_dictionary_get(board, board_description_key);
+	return prop_string_cstring_nocopy(string);
+}
+
+/*
+ * evb_board_get_uboot_pkg --
+ *	Return the u-boot package name for the specified board.
+ */
+const char *
+evb_board_get_uboot_pkg(ib_params *params, evb_board board)
+{
+	prop_string_t string;
+
+	string = prop_dictionary_get(board, board_u_boot_pkg_key);
+	if (string == NULL)
+		return NULL;
+	return prop_string_cstring_nocopy(string);
+}
+
+/*
+ * evb_board_get_uboot_path --
+ *	Return the u-boot installed package path for the specified board.
+ */
+const char *
+evb_board_get_uboot_path(ib_params *params, evb_board board)
+{
+	prop_string_t string;
+
+	string = prop_dictionary_get(board, board_u_boot_path_key);
+	if (string == NULL)
+		return NULL;
+	return prop_string_cstring_nocopy(string);
+}
+
+/*
+ * evb_board_get_uboot_install --
+ *	Return the u-boot install object for the specified board,
+ *	corresponding to the media specified by the user.
+ */
+evb_ubinstall
+evb_board_get_uboot_install(ib_params *params, evb_board board)
+{
+	evb_ubinstall install;
+
+	install = prop_dictionary_get(board, board_u_boot_install_key);
+
+	if (!(params->flags & IB_MEDIA)) {
+		if (install == NULL) {
+			warnx("Must specify media=... for board '%s'",
+			    params->board);
+			goto list_media;
+		}
+		return install;
+	}
+
+	/* media=... was specified by the user. */
+
+	if (install) {
+		warnx("media=... is not a valid option for board '%s'",
+		    params->board);
+		return NULL;
+	}
+
+	char install_key[128];
+	int n = snprintf(install_key, sizeof(install_key), "%s-%s",
+	    board_u_boot_install_key, params->media);
+	if (n < 0 || (size_t)n >= sizeof(install_key))
+		goto invalid_media;;
+	install = prop_dictionary_get(board, install_key);
+	if (install != NULL)
+		return install;
+ invalid_media:
+	warnx("invalid media specification: '%s'", params->media);
+ list_media:
+	fprintf(stderr, "Valid media types:");
+	prop_array_t array = evb_board_copy_uboot_media(params, board);
+	assert(array != NULL);
+	prop_object_iterator_t iter = prop_array_iterator(array);
+	prop_string_t string;
+	while ((string = prop_object_iterator_next(iter)) != NULL)
+		fprintf(stderr, " %s", prop_string_cstring_nocopy(string));
+	fprintf(stderr, "\n");
+	prop_object_iterator_release(iter);
+	prop_object_release(array);
+
+	return NULL;
+}
+
+/*
+ * evb_board_copy_uboot_media --
+ *	Return the valid media types for the given board as an array
+ *	of strings.
+ *
+ *	Follows the create rule; caller is responsible for releasing
+ *	the array.
+ */
+prop_array_t
+evb_board_copy_uboot_media(ib_params *params, evb_board board)
+{
+	prop_array_t array = prop_array_create();
+	prop_object_iterator_t iter = prop_dictionary_iterator(board);
+	prop_string_t string;
+	prop_dictionary_keysym_t key;
+	const char *cp;
+
+	assert(array != NULL);
+	assert(iter != NULL);
+
+	while ((key = prop_object_iterator_next(iter)) != NULL) {
+		cp = prop_dictionary_keysym_cstring_nocopy(key);
+		if (strcmp(cp, board_u_boot_install_key) == 0 ||
+		    strncmp(cp, board_u_boot_install_key,
+			    sizeof(board_u_boot_install_key) - 1) != 0)
+			continue;
+		string = prop_string_create_cstring(strrchr(cp, '-')+1);
+		assert(string != NULL);
+		prop_array_add(array, string);
+		prop_object_release(string);
+	}
+	prop_object_iterator_release(iter);
+	return array;
+}
+
+/*
+ * evb_ubinstall_get_steps --
+ *	Get the install steps for a given install object.
+ */
+evb_ubsteps
+evb_ubinstall_get_steps(ib_params *params, evb_ubinstall install)
+{
+	return prop_array_iterator(install);
+}
+
+/*
+ * evb_ubsteps_next_step --
+ *	Return the next step in the install object.
+ *
+ *	N.B. The iterator is released upon termination.
+ */
+evb_ubstep
+evb_ubsteps_next_step(ib_params *params, evb_ubsteps steps)
+{
+	prop_dictionary_t step = prop_object_iterator_next(steps);
+
+	/* If we are out of steps, release the iterator. */
+	if (step == NULL)
+		prop_object_iterator_release(steps);
+	
+	return step;
+}
+
+/*
+ * evb_ubstep_get_file_name --
+ *	Returns the input file name for the step.
+ */
+const char *
+evb_ubstep_get_file_name(ib_params *params, evb_ubstep step)
+{
+	prop_string_t string = prop_dictionary_get(step, step_file_name_key);
+	return prop_string_cstring_nocopy(string);
+}
+
+/*
+ * evb_ubstep_get_file_offset --
+ *	Returns the input file offset for the step.
+ */
+uint64_t
+evb_ubstep_get_file_offset(ib_params *params, evb_ubstep step)
+{
+	prop_number_t number = prop_dictionary_get(step, step_file_offset_key);
+	if (number != NULL)
+		return prop_number_unsigned_integer_value(number);
+	return 0;
+}
+
+/*
+ * evb_ubstep_get_file_size --
+ *	Returns the size of the input file to copy for this step, or
+ *	zero if the remainder of the file should be copied.
+ */
+uint64_t
+evb_ubstep_get_file_size(ib_params *params, evb_ubstep step)
+{
+	prop_number_t number = prop_dictionary_get(step, step_file_size_key);
+	if (number != NULL)
+		return prop_number_unsigned_integer_value(number);
+	return 0;
+}
+
+/*
+ * evb_ubstep_get_image_offset --
+ *	Returns the offset into the destination image / device to
+ *	copy the input file.
+ */
+uint64_t
+evb_ubstep_get_image_offset(ib_params *params, evb_ubstep step)
+{
+	prop_number_t number = prop_dictionary_get(step, step_image_offset_key);
+	if (number != NULL)
+		return prop_number_unsigned_integer_value(number);
+	return 0;
+}
+
+/*
+ * evb_ubstep_preserves_partial_block --
+ *	Returns true if the step preserves a partial block.
+ */
+bool
+evb_ubstep_preserves_partial_block(ib_params *params, evb_ubstep step)
+{
+	prop_bool_t val = prop_dictionary_get(step, step_preserve_key);
+	if (val != NULL)
+		return prop_bool_true(val);
+	return false;
+}
+
+/*
+ * evb_uboot_file_path --
+ *	Build a file path from the u-boot base path in the board object
+ *	and the file name in the step object.
+ */
+static const char *
+evb_uboot_file_path(ib_params *params, evb_board board, evb_ubstep step,
+    char *buf, size_t bufsize)
+{
+	const char *base_path = evb_board_get_uboot_path(params, board);
+	const char *file_name = evb_ubstep_get_file_name(params, step);
+
+	if (base_path == NULL || file_name == NULL)
+		return NULL;
+
+	return make_path(buf, bufsize, "%s/%s", base_path, file_name);
+}
+
+/*
+ * evb_uboot_do_step --
+ *	Given a evb_ubstep, do the deed.
+ */
+static int
+evb_uboot_do_step(ib_params *params, const char *uboot_file, evb_ubstep step)
+{
+	struct stat sb;
+	int ifd = -1;
+	char *blockbuf;
+	size_t thisblock;
+	off_t curoffset;
+	off_t remaining;
+	bool rv = false;
+
+	uint64_t file_size = evb_ubstep_get_file_size(params, step);
+	uint64_t file_offset = evb_ubstep_get_file_offset(params, step);
+	uint64_t image_offset = evb_ubstep_get_image_offset(params, step);
+
+	blockbuf = malloc(params->sectorsize);
+	if (blockbuf == NULL)
+		goto out;
+
+	ifd = open(uboot_file, O_RDONLY);
+	if (ifd < 0) {
+		warn("open '%s'", uboot_file);
+		goto out;
+	}
+	if (fstat(ifd, &sb) < 0) {
+		warn("fstat '%s'", uboot_file);
+		goto out;
+	}
+
+	if (file_size)
+		remaining = (off_t)file_size;
+	else
+		remaining = sb.st_size - (off_t)file_offset;
+
+	if (params->flags & IB_VERBOSE) {
+		if (file_offset) {
+			printf("Writing '%s' -- %lld @ %" PRIu64 " ==> %" PRIu64 "\n",
+			    evb_ubstep_get_file_name(params, step),
+			    (long long)remaining, file_offset, image_offset);
+		} else {
+			printf("Writing '%s' -- %lld ==> %" PRIu64 "\n",
+			    evb_ubstep_get_file_name(params, step),
+			    (long long)remaining, image_offset);
+		}
+	}
+
+	if (lseek(ifd, (off_t)file_offset, SEEK_SET) < 0) {
+		warn("lseek '%s' @ %" PRIu64, uboot_file,
+		    file_offset);
+		goto out;
+	}
+
+	for (curoffset = (off_t)image_offset; remaining > 0;
+	     remaining -= thisblock, curoffset += params->sectorsize) {
+		thisblock = params->sectorsize;
+		if ((off_t)thisblock > remaining)
+			thisblock = (size_t)remaining;
+		if ((thisblock % params->sectorsize) != 0) {
+			memset(blockbuf, 0, params->sectorsize);
+			if (evb_ubstep_preserves_partial_block(params, step)) {
+				if (params->flags & IB_VERBOSE) {
+					printf("(Reading '%s' -- %u @ %lld)\n",
+					    params->filesystem,
+					    params->sectorsize,
+					    (long long)curoffset);
+				}
+				if (pread(params->fsfd, blockbuf,
+					  params->sectorsize, curoffset) < 0) {
+					warn("pread '%s'", params->filesystem);
+					goto out;
+				}
+			}
+		}
+		if (read(ifd, blockbuf, thisblock) != (ssize_t)thisblock) {
+			warn("read '%s'", uboot_file);
+			goto out;
+		}
+		if (!(params->flags & IB_NOWRITE) &&
+		    pwrite(params->fsfd, blockbuf, params->sectorsize,
+			   curoffset) != (ssize_t)params->sectorsize) {
+			warn("pwrite '%s'", params->filesystem);
+			goto out;
+		}
+	}
+
+	/* Success! */
+	rv = true;
+
+ out:
+	if (ifd != -1 && close(ifd) == -1)
+		warn("close '%s'", uboot_file);
+	if (blockbuf)
+		free(blockbuf);
+	return rv;
+}
+
+int
+evb_uboot_setboot(ib_params *params, evb_board board)
+{
+	char uboot_filebuf[PATH_MAX+1];
+	const char *uboot_file;
+	struct stat sb;
+	off_t max_offset = 0;
+
+	/*
+	 * If we don't have a u-boot path for this board, it means
+	 * that a u-boot package wasn't found.  Prompt the user to
+	 * install it.
+	 */
+	if (evb_board_get_uboot_path(params, board) == NULL) {
+		warnx("No u-boot package found for board '%s'",
+		    params->board);
+		uboot_file = evb_board_get_uboot_pkg(params, board);
+		if (uboot_file != NULL)
+			warnx("Please install the sysutils/u-boot-%s package.",
+			    uboot_file);
+		return 0;
+	}
+
+	evb_ubinstall install = evb_board_get_uboot_install(params, board);
+	evb_ubsteps steps;
+	evb_ubstep step;
+
+	if (install == NULL)
+		return 0;
+
+	/*
+	 * First, make sure the files are all there.  While we're
+	 * at it, calculate the largest byte offset that we will
+	 * be writing.
+	 */
+	steps = evb_ubinstall_get_steps(params, install);
+	while ((step = evb_ubsteps_next_step(params, steps)) != NULL) {
+		uint64_t file_offset = evb_ubstep_get_file_offset(params, step);
+		uint64_t file_size = evb_ubstep_get_file_size(params, step);
+		uint64_t image_offset =
+		    evb_ubstep_get_image_offset(params, step);
+		uboot_file = evb_uboot_file_path(params, board, step,
+		    uboot_filebuf, sizeof(uboot_filebuf));
+		if (uboot_file == NULL)
+			return 0;
+		if (stat(uboot_file, &sb) < 0) {
+			warn("%s", uboot_file);
+			return 0;
+		}
+		if (!S_ISREG(sb.st_mode)) {
+			warnx("%s: %s", uboot_file, strerror(EFTYPE));
+			return 0;
+		}
+		off_t this_max;
+		if (file_size)
+			this_max = file_size;
+		else
+			this_max = sb.st_size - file_offset;
+		this_max += image_offset;
+		if (max_offset < this_max)
+			max_offset = this_max;
+	}
+
+	/*
+	 * Ok, we've verified that all of the files are there, and now
+	 * max_offset points to the first byte that's available for a
+	 * partition containing a file system.
+	 */
+
+	off_t rounded_max_offset = (off_t)(max_offset / params->sectorsize) *
+	    params->sectorsize;
+	if (rounded_max_offset != max_offset)
+		rounded_max_offset += params->sectorsize;
+
+	if (params->flags & IB_VERBOSE) {
+		printf("Max u-boot offset (rounded): %lld (%lld)\n",
+		    (long long)max_offset, (long long)rounded_max_offset);
+		printf("First free block available for file systems: "
+		    "%lld (0x%llx)\n",
+		    (long long)rounded_max_offset / params->sectorsize,
+		    (long long)rounded_max_offset / params->sectorsize);
+	}
+
+	/* XXX Check MBR table for overlapping partitions. */
+
+	/*
+	 * Now write each binary component to the appropriate location
+	 * on disk.
+	 */
+	steps = evb_ubinstall_get_steps(params, install);
+	while ((step = evb_ubsteps_next_step(params, steps)) != NULL) {
+		uboot_file = evb_uboot_file_path(params, board, step,
+		    uboot_filebuf, sizeof(uboot_filebuf));
+		if (uboot_file == NULL)
+			return 0;
+		if (!evb_uboot_do_step(params, uboot_file, step))
+			return 0;
+	}
+
+	return 1;
+}
Index: src/usr.sbin/installboot/evboards.h
diff -u /dev/null src/usr.sbin/installboot/evboards.h:1.1
--- /dev/null	Tue May  7 05:02:42 2019
+++ src/usr.sbin/installboot/evboards.h	Tue May  7 05:02:42 2019
@@ -0,0 +1,65 @@
+/*	$NetBSD: evboards.h,v 1.1 2019/05/07 05:02:42 thorpej Exp $	*/
+
+/*-
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef installboot_evboards_h_included
+#define	installboot_evboards_h_included
+
+#include <stdio.h>
+#include <prop/proplib.h>
+
+typedef prop_dictionary_t      evb_board;
+typedef prop_array_t           evb_ubinstall;
+typedef prop_object_iterator_t evb_ubsteps;
+typedef prop_dictionary_t      evb_ubstep;
+
+bool		evb_db_load(ib_params *);
+evb_board	evb_db_get_board(ib_params *);
+void		evb_db_list_boards(ib_params *, FILE *);
+
+const char *	evb_board_get_description(ib_params *, evb_board);
+const char *	evb_board_get_uboot_pkg(ib_params *, evb_board);
+const char *	evb_board_get_uboot_path(ib_params *, evb_board);
+evb_ubinstall	evb_board_get_uboot_install(ib_params *, evb_board);
+prop_array_t	evb_board_copy_uboot_media(ib_params *, evb_board);
+
+evb_ubsteps	evb_ubinstall_get_steps(ib_params *, evb_ubinstall);
+
+evb_ubstep	evb_ubsteps_next_step(ib_params *, evb_ubsteps);
+
+const char *	evb_ubstep_get_file_name(ib_params *, evb_ubstep);
+uint64_t	evb_ubstep_get_file_offset(ib_params *, evb_ubstep);
+uint64_t	evb_ubstep_get_file_size(ib_params *, evb_ubstep);
+uint64_t	evb_ubstep_get_image_offset(ib_params *, evb_ubstep);
+bool		evb_ubstep_preserves_partial_block(ib_params *, evb_ubstep);
+
+int		evb_uboot_setboot(ib_params *, evb_board);
+
+#endif /* installboot_evboards_h_included */

Index: src/usr.sbin/installboot/arch/evbarm.c
diff -u /dev/null src/usr.sbin/installboot/arch/evbarm.c:1.1
--- /dev/null	Tue May  7 05:02:42 2019
+++ src/usr.sbin/installboot/arch/evbarm.c	Tue May  7 05:02:42 2019
@@ -0,0 +1,119 @@
+/*	$NetBSD: evbarm.c,v 1.1 2019/05/07 05:02:42 thorpej Exp $	*/
+
+/*-
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(__lint)
+__RCSID("$NetBSD: evbarm.c,v 1.1 2019/05/07 05:02:42 thorpej Exp $");
+#endif  /* !__lint */
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#include "installboot.h"
+#include "evboards.h"
+
+static int	evbarm_setboot(ib_params *);
+static int	evbarm_clearboot(ib_params *);
+static int	evbarm_editboot(ib_params *);
+static void	evbarm_usage(ib_params *);
+
+struct ib_mach ib_mach_evbarm = {
+	.name		=	"evbarm",
+	.setboot	=	evbarm_setboot,
+	.clearboot	=	evbarm_clearboot,
+	.editboot	=	evbarm_editboot,
+	.usage		=	evbarm_usage,
+	.valid_flags	=	IB_BOARD | IB_DTB | IB_MEDIA,
+	.mach_flags	=	MF_UBOOT,
+};
+
+static int
+evbarm_setboot(ib_params *params)
+{
+	evb_board board;
+	int rv = 0;
+
+	if (!evb_db_load(params)) {
+		warnx("Unable to load board db.");
+		return 0;
+	}
+
+	board = evb_db_get_board(params);
+	if (board == NULL)
+		goto out;
+
+	rv = evb_uboot_setboot(params, board);
+
+ out:
+	if (params->mach_data) {
+		prop_object_release(params->mach_data);
+		params->mach_data = NULL;
+	}
+	return rv;
+}
+
+static int
+evbarm_clearboot(ib_params *params)
+{
+
+	return no_clearboot(params);
+}
+
+static int
+evbarm_editboot(ib_params *params)
+{
+
+	return no_editboot(params);
+}
+
+static void
+evbarm_usage(ib_params *params)
+{
+
+	if (!evb_db_load(params)) {
+		warnx("Unable to load board db.");
+		return;
+	}
+
+	fprintf(stderr, "Known boards (for -o board=...) are:\n");
+	evb_db_list_boards(params, stderr);
+
+	if (params->mach_data) {
+		prop_object_release(params->mach_data);
+		params->mach_data = NULL;
+	}
+}

Reply via email to