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, ¶ms->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; + } +}