diff --git a/tools/nbsd_ports b/tools/nbsd_ports index e4830d47f..9c6e5f9f7 100644 --- a/tools/nbsd_ports +++ b/tools/nbsd_ports @@ -33,6 +33,7 @@ usr.bin/seq src/usr.bin/seq usr.bin/man src/usr.bin/man usr.bin/apropos src/usr.bin/apropos usr.bin/mdocml src/external/bsd/mdocml +usr.sbin/installboot src/usr.sbin/installboot usr.sbin/pwd_mkdb src/usr.sbin/pwd_mkdb usr.sbin/user src/usr.sbin/user usr.sbin/vipw src/usr.sbin/vipw diff --git a/usr.sbin/installboot/Makefile b/usr.sbin/installboot/Makefile new file mode 100644 index 000000000..b631a32e8 --- /dev/null +++ b/usr.sbin/installboot/Makefile @@ -0,0 +1,54 @@ +# $NetBSD: Makefile,v 1.46 2011/08/14 17:50:16 christos Exp $ +# + +.include + +PROG= installboot +MAN= installboot.8 +SRCS= installboot.c sum.c machines.c fstypes.c + + +ARCH_XLAT= amd64-i386.c news68k-news.c newsmips-news.c +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 hp700.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 +.else +ARCH_FILES?= ${ARCH_XLAT:M${MACHINE}-*:S/${MACHINE}-//} +.if empty(ARCH_FILES) +ARCH_FILES= ${MACHINE}.c +.endif +.endif + +SRCS+=${ARCH_FILES} + +.if empty(ARCH_FILES:C/(macppc|news|sparc|sun68k|x68k)/stg2/:Mstg2.c) +CPPFLAGS += -DNO_STAGE2 +.else +SRCS+= bbinfo.c + +# fstypes are only needed for 'stage2' and then only from bbinfo. +SRCS+= ffs.c +.if SMALLPROG +CPPFLAGS+= -DNO_FFS_SWAP +.else +SRCS+= ffs_bswap.c +.endif +#SRCS+= ext2fs.c ext2fs_bswap.c +.endif + +UFSSRC= ${NETBSDSRCDIR}/sys/ufs +CPPFLAGS+= -I${.CURDIR} -I. +.PATH: ${.CURDIR}/arch ${UFSSRC}/ffs ${UFSSRC}/ext2fs + +.if !defined(HOSTPROGNAME) +.if defined(HAVE_GCC) || defined(HAVE_PCC) +.for f in i386 macppc +COPTS.${f}.c+= -Wno-pointer-sign +.endfor +.endif +.endif + +.include diff --git a/usr.sbin/installboot/arch/alpha.c b/usr.sbin/installboot/arch/alpha.c new file mode 100644 index 000000000..e2de898d4 --- /dev/null +++ b/usr.sbin/installboot/arch/alpha.c @@ -0,0 +1,451 @@ +/* $NetBSD: alpha.c,v 1.21 2011/08/14 17:50:17 christos Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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. + */ + +/* + * Copyright (c) 1999 Ross Harvey. All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ross Harvey + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * Copyright (c) 1999 Christopher G. Demetriou. All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christopher G. Demetriou + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 +#if !defined(__lint) +__RCSID("$NetBSD: alpha.c,v 1.21 2011/08/14 17:50:17 christos Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +#define SUN_DKMAGIC 55998 /* XXX: from */ + +static void resum(ib_params *, struct alpha_boot_block * const bb, + uint16_t *bb16); +static void sun_bootstrap(ib_params *, struct alpha_boot_block * const); +static void check_sparc(const struct alpha_boot_block * const, + const char *); + +static int alpha_clearboot(ib_params *); +static int alpha_setboot(ib_params *); + +struct ib_mach ib_mach_alpha = + { "alpha", alpha_setboot, alpha_clearboot, no_editboot, + IB_STAGE1START | IB_ALPHASUM | IB_APPEND | IB_SUNSUM }; + +static int +alpha_clearboot(ib_params *params) +{ + struct alpha_boot_block bb; + uint64_t cksum; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(sizeof(struct alpha_boot_block) == ALPHA_BOOT_BLOCK_BLOCKSIZE); + + if (params->flags & (IB_STAGE1START | IB_APPEND)) { + warnx("Can't use `-b bno' or `-o append' with `-c'"); + return (0); + } + + rv = pread(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + return (0); + } else if (rv != sizeof(bb)) { + warnx("Reading `%s': short read", params->filesystem); + return (0); + } + ALPHA_BOOT_BLOCK_CKSUM(&bb, &cksum); + if (cksum != bb.bb_cksum) { // XXX check bb_cksum endian? + warnx( + "Old boot block checksum invalid (was %#llx, calculated %#llx)", + (unsigned long long)le64toh(bb.bb_cksum), + (unsigned long long)le64toh(cksum)); + warnx("Boot block invalid"); + return (0); + } + + if (params->flags & IB_VERBOSE) { + printf("Old bootstrap start sector: %llu\n", + (unsigned long long)le64toh(bb.bb_secstart)); + printf("Old bootstrap size: %llu\n", + (unsigned long long)le64toh(bb.bb_secsize)); + printf("Old bootstrap checksum: %#llx\n", + (unsigned long long)le64toh(bb.bb_cksum)); + } + + bb.bb_secstart = bb.bb_secsize = bb.bb_flags = 0; + + ALPHA_BOOT_BLOCK_CKSUM(&bb, &bb.bb_cksum); + if (params->flags & IB_SUNSUM) + sun_bootstrap(params, &bb); + + printf("New bootstrap start sector: %llu\n", + (unsigned long long)le64toh(bb.bb_secstart)); + printf("New bootstrap size: %llu\n", + (unsigned long long)le64toh(bb.bb_secsize)); + printf("New bootstrap checksum: %#llx\n", + (unsigned long long)le64toh(bb.bb_cksum)); + + if (params->flags & IB_VERBOSE) + printf("%slearing boot block\n", + (params->flags & IB_NOWRITE) ? "Not c" : "C"); + if (params->flags & IB_NOWRITE) + return (1); + + rv = pwrite(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + return (0); + } else if (rv != sizeof(bb)) { + warnx("Writing `%s': short write", params->filesystem); + return (0); + } + + return (1); +} + +static int +alpha_setboot(ib_params *params) +{ + struct alpha_boot_block bb; + uint64_t startblock; + int retval; + char *bootstrapbuf; + size_t bootstrapsize; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + assert(sizeof(struct alpha_boot_block) == ALPHA_BOOT_BLOCK_BLOCKSIZE); + + retval = 0; + bootstrapbuf = NULL; + + /* + * Allocate a buffer, with space to round up the input file + * to the next block size boundary, and with space for the boot + * block. + */ + bootstrapsize = roundup(params->s1stat.st_size, + ALPHA_BOOT_BLOCK_BLOCKSIZE); + + bootstrapbuf = malloc(bootstrapsize); + if (bootstrapbuf == NULL) { + warn("Allocating %lu bytes", (unsigned long) bootstrapsize); + goto done; + } + memset(bootstrapbuf, 0, bootstrapsize); + + /* read the file into the buffer */ + rv = pread(params->s1fd, bootstrapbuf, params->s1stat.st_size, 0); + if (rv == -1) { + warn("Reading `%s'", params->stage1); + goto done; + } else if (rv != params->s1stat.st_size) { + warnx("Reading `%s': short read", params->stage1); + goto done; + } + + rv = pread(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + goto done; + } else if (rv != sizeof(bb)) { + warnx("Reading `%s': short read", params->filesystem); + goto done; + } + + if (params->flags & IB_SUNSUM) + check_sparc(&bb, "Initial"); + + /* fill in the updated bootstrap fields */ + if (params->flags & IB_APPEND) { + struct stat filesyssb; + + if (fstat(params->fsfd, &filesyssb) == -1) { + warn("Examining `%s'", params->filesystem); + goto done; + } + if (!S_ISREG(filesyssb.st_mode)) { + warnx( + "`%s' must be a regular file to append a bootstrap", + params->filesystem); + goto done; + } + startblock = howmany(filesyssb.st_size, + ALPHA_BOOT_BLOCK_BLOCKSIZE); + } else if (params->flags & IB_STAGE1START) { + startblock = params->s1start; + } else { + startblock = ALPHA_BOOT_BLOCK_OFFSET / + ALPHA_BOOT_BLOCK_BLOCKSIZE + 1; + } + + bb.bb_secsize = + htole64(howmany(params->s1stat.st_size, + ALPHA_BOOT_BLOCK_BLOCKSIZE)); + bb.bb_secstart = htole64(startblock); + bb.bb_flags = 0; + + ALPHA_BOOT_BLOCK_CKSUM(&bb, &bb.bb_cksum); + if (params->flags & IB_SUNSUM) + sun_bootstrap(params, &bb); + + if (params->flags & IB_VERBOSE) { + printf("Bootstrap start sector: %llu\n", + (unsigned long long)startblock); + printf("Bootstrap sector count: %llu\n", + (unsigned long long)le64toh(bb.bb_secsize)); + printf("New boot block checksum: %#llx\n", + (unsigned long long)le64toh(bb.bb_cksum)); + printf("%sriting bootstrap\n", + (params->flags & IB_NOWRITE) ? "Not w" : "W"); + } + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize, + startblock * ALPHA_BOOT_BLOCK_BLOCKSIZE); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if ((size_t)rv != bootstrapsize) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } + + if (params->flags & IB_VERBOSE) + printf("Writing boot block\n"); + rv = pwrite(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if (rv != sizeof(bb)) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } else { + retval = 1; + } + + done: + if (bootstrapbuf) + free(bootstrapbuf); + return (retval); +} + + +/* + * The Sun and alpha checksums overlay, and the Sun magic number also + * overlays the alpha checksum. If you think you are smart: stop here + * and do exercise one: figure out how to salt unimportant uint16_t + * words in mid-sector so that the alpha and sparc checksums match, + * and so the Sun magic number is embedded in the alpha checksum. + * + * The last uint64_t in the sector is the alpha arithmetic checksum. + * The last uint16_t in the sector is the sun xor checksum. + * The penultimate uint16_t in the sector is the sun magic number. + * + * A: 511 510 509 508 507 506 505 504 + * S: 510 511 508 509 506 507 504 505 + * 63 : : : 32:31 : : : 0 + * | : : : \:| : : : | + * 7654321076543210765432107654321076543210765432107654321076543210 + * |-- sparc --||-- sparc --| + * |-- checksum --||-- magic --| + * |----------------------- alpha checksum -----------------------| + * 1011111011011010 + * b e d a + */ + +static void +resum(ib_params *params, struct alpha_boot_block * const bb, uint16_t *bb16) +{ + static uint64_t lastsum; + + if (bb16 != NULL) + memcpy(bb, bb16, sizeof(*bb)); + ALPHA_BOOT_BLOCK_CKSUM(bb, &bb->bb_cksum); + if (bb16 != NULL) + memcpy(bb16, bb, sizeof(*bb)); + if ((params->flags & IB_VERBOSE) && lastsum != bb->bb_cksum) + printf("alpha checksum now %016llx\n", + (unsigned long long)le64toh(bb->bb_cksum)); + lastsum = bb->bb_cksum; +} + +static void +sun_bootstrap(ib_params *params, struct alpha_boot_block * const bb) +{ +# define BB_ADJUST_OFFSET 64 + static char our_int16s[] = "\2\3\6\7\12"; + uint16_t i, j, chkdelta, sunsum, bb16[256]; + + /* + * Theory: the alpha checksum is adjusted so bits 47:32 add up + * to the Sun magic number. Then, another adjustment is computed + * so bits 63:48 add up to the Sun checksum, and applied in pieces + * so it changes the alpha checksum but not the Sun value. + * + * Note: using memcpy(3) instead of a union as a strict c89/c9x + * conformance experiment and to avoid a public interface delta. + */ + assert(sizeof(bb16) == sizeof(*bb)); + memcpy(bb16, bb, sizeof(bb16)); + for (i = 0; our_int16s[i]; ++i) { + j = BB_ADJUST_OFFSET + our_int16s[i]; + if (bb16[j]) { + warnx("Non-zero bits %04x in bytes %d..%d", + bb16[j], j * 2, j * 2 + 1); + bb16[j] = 0; + resum(params, bb, bb16); + } + } + /* + * Make alpha checksum <47:32> come out to the sun magic. + */ + bb16[BB_ADJUST_OFFSET + 2] = htobe16(SUN_DKMAGIC) - bb16[254]; + resum(params, bb, bb16); + sunsum = compute_sunsum(bb16); /* might be the final value */ + if (params->flags & IB_VERBOSE) + printf("target sun checksum is %04x\n", sunsum); + /* + * Arrange to have alpha 63:48 add up to the sparc checksum. + */ + chkdelta = sunsum - bb16[255]; + bb16[BB_ADJUST_OFFSET + 3] = chkdelta >> 1; + bb16[BB_ADJUST_OFFSET + 7] = chkdelta >> 1; + /* + * By placing half the correction in two different uint64_t words at + * positions 63:48, the sparc sum will not change but the alpha sum + * will have the full correction, but only if the target adjustment + * was even. If it was odd, reverse propagate the carry one place. + */ + if (chkdelta & 1) { + if (params->flags & IB_VERBOSE) + printf("target adjustment %04x was odd, correcting\n", + chkdelta); + assert(bb16[BB_ADJUST_OFFSET + 6] == 0); + assert(bb16[BB_ADJUST_OFFSET + 012] == 0); + bb16[BB_ADJUST_OFFSET + 6] += 0x8000; + bb16[BB_ADJUST_OFFSET + 012] += 0x8000; + } + resum(params, bb, bb16); + if (params->flags & IB_VERBOSE) + printf("final harmonized checksum: %016llx\n", + (unsigned long long)le64toh(bb->bb_cksum)); + check_sparc(bb, "Final"); +} + +static void +check_sparc(const struct alpha_boot_block * const bb, const char *when) +{ + uint16_t bb16[256]; +#define wmsg "%s sparc %s 0x%04x invalid, expected 0x%04x" + + memcpy(bb16, bb, sizeof(bb16)); + if (compute_sunsum(bb16) != bb16[255]) + warnx(wmsg, when, "checksum", bb16[255], compute_sunsum(bb16)); + if (bb16[254] != htobe16(SUN_DKMAGIC)) + warnx(wmsg, when, "magic number", bb16[254], + htobe16(SUN_DKMAGIC)); +} diff --git a/usr.sbin/installboot/arch/amiga.c b/usr.sbin/installboot/arch/amiga.c new file mode 100644 index 000000000..e6650b95f --- /dev/null +++ b/usr.sbin/installboot/arch/amiga.c @@ -0,0 +1,173 @@ +/* $NetBSD: amiga.c,v 1.7 2010/01/14 16:27:49 tsutsui Exp $ */ + +/*- + * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Michael Hitch. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: amiga.c,v 1.7 2010/01/14 16:27:49 tsutsui Exp $"); +#endif /* !__lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +/* XXX Must be kept in sync with bbstart.s! */ +#define CMDLN_LOC 0x10 +#define CMDLN_LEN 0x20 + +#define CHKSUMOFFS 1 + +u_int32_t chksum(u_int32_t *, int); + +static int amiga_setboot(ib_params *); + +struct ib_mach ib_mach_amiga = + { "amiga", amiga_setboot, no_clearboot, no_editboot, + IB_STAGE1START | IB_STAGE2START | IB_COMMAND }; + +static int +amiga_setboot(ib_params *params) +{ + int retval; + ssize_t rv; + char *dline; + int sumlen; + u_int32_t sum2, sum16; + + struct stat bootstrapsb; + + u_int32_t block[128*16]; + + retval = 0; + if (fstat(params->s1fd, &bootstrapsb) == -1) { + warn("Examining `%s'", params->stage1); + goto done; + } + if (!S_ISREG(bootstrapsb.st_mode)) { + warnx("`%s' must be a regular file", params->stage1); + goto done; + } + + rv = pread(params->s1fd, &block, sizeof(block), 0); + if (rv == -1) { + warn("Reading `%s'", params->stage1); + goto done; + } else if (rv != sizeof(block)) { + warnx("Reading `%s': short read", params->stage1); + goto done; + } + + /* XXX the choices should not be hardcoded */ + + sum2 = chksum(block, 1024/4); + sum16 = chksum(block, 8192/4); + + if (sum16 == 0xffffffff) { + sumlen = 8192/4; + } else if (sum2 == 0xffffffff) { + sumlen = 1024/4; + } else { + errx(1, "%s: wrong checksum", params->stage1); + /* NOTREACHED */ + } + + if (sum2 == sum16) { + warnx("eek - both sums are the same"); + } + + if (params->flags & IB_COMMAND) { + dline = (char *)&(block[CMDLN_LOC/4]); + /* XXX keep the default default line in sync with bbstart.s */ + if (strcmp(dline, "netbsd -ASn2") != 0) { + errx(1, "Old bootblock version? Can't change command line."); + } + (void)strncpy(dline, params->command, CMDLN_LEN-1); + + block[1] = 0; + block[1] = 0xffffffff - chksum(block, sumlen); + } + + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + if (params->flags & IB_VERBOSE) + printf("Writing boot block\n"); + rv = pwrite(params->fsfd, &block, sizeof(block), 0); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if (rv != sizeof(block)) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } else { + retval = 1; + } + + done: + return (retval); +} + +u_int32_t +chksum(block, size) + u_int32_t *block; + int size; +{ + u_int32_t sum, lastsum; + int i; + + sum = 0; + + for (i=0; i +#if !defined(__lint) +__RCSID("$NetBSD: emips.c,v 1.1 2011/01/26 01:18:55 pooka Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "installboot.h" + +static int emips_clearboot(ib_params *); +static int emips_setboot(ib_params *); + +struct ib_mach ib_mach_emips = + { "emips", emips_setboot, emips_clearboot, no_editboot, + IB_STAGE1START | IB_APPEND | IB_SUNSUM }; + + +static int +emips_clearboot(ib_params *params) +{ + /* Nothing to do */ + return (1); +} + +static int +emips_setboot(ib_params *params) +{ + /* Nothing to do */ + return (1); +} diff --git a/usr.sbin/installboot/arch/ews4800mips.c b/usr.sbin/installboot/arch/ews4800mips.c new file mode 100644 index 000000000..3a8e5d08a --- /dev/null +++ b/usr.sbin/installboot/arch/ews4800mips.c @@ -0,0 +1,62 @@ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(__lint) +__RCSID("$NetBSD: ews4800mips.c,v 1.2 2006/02/18 10:08:07 dsl Exp $"); +#endif /* !__lint */ + +#include +#include +#include +#include +#include "installboot.h" + +static int ews4800mips_setboot(ib_params *); + +struct ib_mach ib_mach_ews4800mips = + { "ews4800mips", ews4800mips_setboot, no_clearboot, no_editboot, 0}; + +struct bbinfo_params ews4800mips_bbparams = { + EWS4800MIPS_BBINFO_MAGIC, + EWS4800MIPS_BOOT_BLOCK_OFFSET, + EWS4800MIPS_BOOT_BLOCK_BLOCKSIZE, + EWS4800MIPS_BOOT_BLOCK_MAX_SIZE, + 0, + BBINFO_BIG_ENDIAN, +}; + +static int +ews4800mips_setboot(ib_params *params) +{ + u_int8_t buf[EWS4800MIPS_BOOT_BLOCK_MAX_SIZE]; + int rv; + + rv = pread(params->s1fd, buf, sizeof buf, 0); + if (rv == -1) { + warn("Reading `%s'", params->stage1); + return 0; + } else if (rv != sizeof buf) { + warnx("Reading `%s' : short read", params->stage1); + return 0; + } + + if (params->flags & IB_NOWRITE) + return 1; + + if (params->flags & IB_VERBOSE) + printf("Writing boot block\n"); + + rv = pwrite(params->fsfd, buf, sizeof buf, 0); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + return 0; + } else if (rv != sizeof buf) { + warnx("Writing `%s': short write", params->filesystem); + return 0; + } + + return 1; +} diff --git a/usr.sbin/installboot/arch/hp300.c b/usr.sbin/installboot/arch/hp300.c new file mode 100644 index 000000000..57410fc46 --- /dev/null +++ b/usr.sbin/installboot/arch/hp300.c @@ -0,0 +1,214 @@ +/* $NetBSD: hp300.c,v 1.13 2011/02/10 23:25:11 tsutsui Exp $ */ + +/*- + * Copyright (c) 2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by David Laight. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: hp300.c,v 1.13 2011/02/10 23:25:11 tsutsui Exp $"); +#endif /* !__lint */ + +/* We need the target disklabel.h, not the hosts one..... */ +#ifdef HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#include +#else +#include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +static int hp300_setboot(ib_params *); + +struct ib_mach ib_mach_hp300 = + { "hp300", hp300_setboot, no_clearboot, no_editboot, IB_APPEND }; + +static int +hp300_setboot(ib_params *params) +{ + int retval; + uint8_t *bootstrap; + ssize_t rv; + struct partition *boot; + struct hp300_lifdir *lifdir; + int offset; + int i; + unsigned int secsize = HP300_SECTSIZE; + uint64_t boot_size, boot_offset; + struct disklabel *label; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + + retval = 0; + bootstrap = MAP_FAILED; + + label = malloc(params->sectorsize); + if (label == NULL) { + warn("Failed to allocate memory for disklabel"); + goto done; + } + + if (params->flags & IB_APPEND) { + if (!S_ISREG(params->fsstat.st_mode)) { + warnx( + "`%s' must be a regular file to append a bootstrap", + params->filesystem); + goto done; + } + boot_offset = roundup(params->fsstat.st_size, HP300_SECTSIZE); + } else { + /* + * The bootstrap can be well over 8k, and must go into a BOOT + * partition. Read NetBSD label to locate BOOT partition. + */ + if (pread(params->fsfd, label, params->sectorsize, + LABELSECTOR * params->sectorsize) + != (ssize_t)params->sectorsize) { + warn("reading disklabel"); + goto done; + } + /* And a quick validation - must be a big-endian label */ + secsize = be32toh(label->d_secsize); + if (label->d_magic != htobe32(DISKMAGIC) || + label->d_magic2 != htobe32(DISKMAGIC) || + secsize == 0 || secsize & (secsize - 1) || + be16toh(label->d_npartitions) > MAXMAXPARTITIONS) { + warnx("Invalid disklabel in %s", params->filesystem); + goto done; + } + + i = be16toh(label->d_npartitions); + for (boot = label->d_partitions; ; boot++) { + if (--i < 0) { + warnx("No BOOT partition"); + goto done; + } + if (boot->p_fstype == FS_BOOT) + break; + } + boot_size = be32toh(boot->p_size) * (uint64_t)secsize; + boot_offset = be32toh(boot->p_offset) * (uint64_t)secsize; + + /* + * We put the entire LIF file into the BOOT partition even when + * it doesn't start at the beginning of the disk. + * + * Maybe we ought to be able to take a binary file and add + * it to the LIF filesystem. + */ + if (boot_size < (uint64_t)params->s1stat.st_size) { + warn("BOOT partition too small (%llu < %llu)", + (unsigned long long)boot_size, + (unsigned long long)params->s1stat.st_size); + goto done; + } + } + + bootstrap = mmap(NULL, params->s1stat.st_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE, params->s1fd, 0); + if (bootstrap == MAP_FAILED) { + warn("mmaping `%s'", params->stage1); + goto done; + } + + /* Relocate files, sanity check LIF directory on the way */ + lifdir = (void *)(bootstrap + HP300_SECTSIZE * 2); + for (i = 0; i < 8; lifdir++, i++) { + int32_t addr = be32toh(lifdir->dir_addr); + int32_t limit = (params->s1stat.st_size - 1) / HP300_SECTSIZE + 1; + int32_t end = addr + be32toh(lifdir->dir_length); + if (end > limit) { + warnx("LIF entry %d larger (%d %d) than LIF file", + i, end, limit); + goto done; + } + if (addr != 0 && boot_offset != 0) + lifdir->dir_addr = htobe32(addr + boot_offset + / HP300_SECTSIZE); + } + + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + /* Write LIF volume header and directory to sectors 0 and 1 */ + rv = pwrite(params->fsfd, bootstrap, 1024, 0); + if (rv != 1024) { + if (rv == -1) + warn("Writing `%s'", params->filesystem); + else + warnx("Writing `%s': short write", params->filesystem); + goto done; + } + + /* Write files to BOOT partition */ + offset = boot_offset <= HP300_SECTSIZE * 16 ? HP300_SECTSIZE * 16 : 0; + i = roundup(params->s1stat.st_size, secsize) - offset; + rv = pwrite(params->fsfd, bootstrap + offset, i, boot_offset + offset); + if (rv != i) { + if (rv == -1) + warn("Writing boot filesystem of `%s'", + params->filesystem); + else + warnx("Writing boot filesystem of `%s': short write", + params->filesystem); + goto done; + } + + retval = 1; + + done: + if (label != NULL) + free(label); + if (bootstrap != MAP_FAILED) + munmap(bootstrap, params->s1stat.st_size); + return retval; +} diff --git a/usr.sbin/installboot/arch/hp700.c b/usr.sbin/installboot/arch/hp700.c new file mode 100644 index 000000000..c6d84805b --- /dev/null +++ b/usr.sbin/installboot/arch/hp700.c @@ -0,0 +1,220 @@ +/* $NetBSD: hp700.c,v 1.4 2008/04/28 20:24:16 martin Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: hp700.c,v 1.4 2008/04/28 20:24:16 martin Exp $"); +#endif /* !__lint */ + +/* We need the target disklabel.h, not the hosts one..... */ +#ifdef HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#include +#else +#include +#endif +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +#define HP700_LABELOFFSET 512 +#define HP700_LABELSIZE 404 /* reserve 16 partitions */ +#define HP700_BOOT_BLOCK_SIZE 8192 + +static int hp700_clearboot(ib_params *); +static int hp700_setboot(ib_params *); + +struct ib_mach ib_mach_hp700 = + { "hp700", hp700_setboot, hp700_clearboot, no_editboot, 0}; + +static int +hp700_clearboot(ib_params *params) +{ + char bb[HP700_BOOT_BLOCK_SIZE]; + int retval, eol; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + + retval = 0; + + /* read disklabel on the target disk */ + rv = pread(params->fsfd, bb, sizeof bb, 0); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + goto done; + } else if (rv != sizeof bb) { + warnx("Reading `%s': short read", params->filesystem); + goto done; + } + + /* clear header */ + memset(bb, 0, HP700_LABELOFFSET); + eol = HP700_LABELOFFSET + HP700_LABELSIZE; + memset(&bb[eol], 0, sizeof bb - eol); + + if (params->flags & IB_VERBOSE) { + printf("%slearing bootstrap\n", + (params->flags & IB_NOWRITE) ? "Not c" : "C"); + } + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + rv = pwrite(params->fsfd, bb, sizeof bb, 0); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if (rv != HP700_BOOT_BLOCK_SIZE) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } else + retval = 1; + + done: + return (retval); +} + +static int +hp700_setboot(ib_params *params) +{ + struct stat bootstrapsb; + char bb[HP700_BOOT_BLOCK_SIZE]; + struct { + char l_off[HP700_LABELOFFSET]; + struct disklabel l; + char l_pad[HP700_BOOT_BLOCK_SIZE + - HP700_LABELOFFSET - sizeof(struct disklabel)]; + } label; + unsigned int secsize, npart; + int retval; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + + retval = 0; + + /* read disklabel on the target disk */ + rv = pread(params->fsfd, &label, HP700_BOOT_BLOCK_SIZE, 0); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + goto done; + } else if (rv != HP700_BOOT_BLOCK_SIZE) { + warnx("Reading `%s': short read", params->filesystem); + goto done; + } + + if (fstat(params->s1fd, &bootstrapsb) == -1) { + warn("Examining `%s'", params->stage1); + goto done; + } + if (!S_ISREG(bootstrapsb.st_mode)) { + warnx("`%s' must be a regular file", params->stage1); + goto done; + } + + /* check if valid disklabel exists */ + secsize = be32toh(label.l.d_secsize); + npart = be16toh(label.l.d_npartitions); + if (label.l.d_magic != htobe32(DISKMAGIC) || + label.l.d_magic2 != htobe32(DISKMAGIC) || + secsize == 0 || secsize & (secsize - 1) || + npart > MAXMAXPARTITIONS) { + warnx("No disklabel in `%s'", params->filesystem); + + /* then check if boot partition exists */ + } else if (npart < 1 || label.l.d_partitions[0].p_size == 0) { + warnx("Partition `a' doesn't exist in %s", params->filesystem); + + /* check if the boot partition is below 2GB */ + } else if (be32toh(label.l.d_partitions[0].p_offset) + + be32toh(label.l.d_partitions[0].p_size) > + ((unsigned)2*1024*1024*1024) / secsize) { + warnx("WARNING: Partition `a' of `%s' exceeds 2GB boundary.", + params->filesystem); + warnx("WARNING: It won't boot since hp700 PDC can handle only 2GB."); + } + + /* read boot loader */ + memset(&bb, 0, sizeof bb); + rv = read(params->s1fd, &bb, sizeof bb); + if (rv == -1) { + warn("Reading `%s'", params->stage1); + goto done; + } + /* then, overwrite disklabel */ + memcpy(&bb[HP700_LABELOFFSET], &label.l, HP700_LABELSIZE); + + if (params->flags & IB_VERBOSE) { + printf("Bootstrap start sector: %#x\n", 0); + printf("Bootstrap byte count: %#zx\n", rv); + printf("%sriting bootstrap\n", + (params->flags & IB_NOWRITE) ? "Not w" : "W"); + } + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + /* write boot loader and disklabel into the target disk */ + rv = pwrite(params->fsfd, &bb, HP700_BOOT_BLOCK_SIZE, 0); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if (rv != HP700_BOOT_BLOCK_SIZE) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } else + retval = 1; + + done: + return (retval); +} diff --git a/usr.sbin/installboot/arch/i386.c b/usr.sbin/installboot/arch/i386.c new file mode 100644 index 000000000..64a6b0dd1 --- /dev/null +++ b/usr.sbin/installboot/arch/i386.c @@ -0,0 +1,552 @@ +/* $NetBSD: i386.c,v 1.37 2011/08/14 17:50:17 christos Exp $ */ + +/*- + * Copyright (c) 2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by David Laight. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: i386.c,v 1.37 2011/08/14 17:50:17 christos Exp $"); +#endif /* !__lint */ + +#include +#ifndef HAVE_NBTOOL_CONFIG_H +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +static const struct console_name { + const char *name; /* Name of console selection */ + const int dev; /* value matching CONSDEV_* from sys/arch/i386/stand/lib/libi386.h */ +} consoles[] = { + { "pc", 0 /* CONSDEV_PC */ }, + { "com0", 1 /* CONSDEV_COM0 */ }, + { "com1", 2 /* CONSDEV_COM1 */ }, + { "com2", 3 /* CONSDEV_COM2 */ }, + { "com3", 4 /* CONSDEV_COM3 */ }, + { "com0kbd", 5 /* CONSDEV_COM0KBD */ }, + { "com1kbd", 6 /* CONSDEV_COM1KBD */ }, + { "com2kbd", 7 /* CONSDEV_COM2KBD */ }, + { "com3kbd", 8 /* CONSDEV_COM3KBD */ }, + { "auto", -1 /* CONSDEV_AUTO */ }, +}; + +static int i386_setboot(ib_params *); +static int i386_editboot(ib_params *); + +struct ib_mach ib_mach_i386 = + { "i386", i386_setboot, no_clearboot, i386_editboot, + IB_RESETVIDEO | IB_CONSOLE | IB_CONSPEED | IB_CONSADDR | + IB_KEYMAP | IB_PASSWORD | IB_TIMEOUT | + IB_MODULES | IB_BOOTCONF }; + +struct ib_mach ib_mach_amd64 = + { "amd64", i386_setboot, no_clearboot, i386_editboot, + IB_RESETVIDEO | IB_CONSOLE | IB_CONSPEED | IB_CONSADDR | + IB_KEYMAP | IB_PASSWORD | IB_TIMEOUT | + IB_MODULES | IB_BOOTCONF }; + +/* + * Attempting to write the 'labelsector' (or a sector near it - within 8k?) + * using the non-raw disk device fails silently. This can be detected (today) + * by doing a fsync() and a read back. + * This is very likely to affect installboot, indeed the code may need to + * be written into the 'labelsector' itself - especially on non-512 byte media. + * We do all writes with a read verify. + * If EROFS is returned we also try to enable writes to the label sector. + * (Maybe these functions should be in the generic part of installboot.) + */ +static int +pwrite_validate(int fd, const void *buf, size_t n_bytes, off_t offset) +{ + void *r_buf; + ssize_t rv; + + r_buf = malloc(n_bytes); + if (r_buf == NULL) + return -1; + rv = pwrite(fd, buf, n_bytes, offset); + if (rv == -1) { + free(r_buf); + return -1; + } + fsync(fd); + if (pread(fd, r_buf, rv, offset) == rv && memcmp(r_buf, buf, rv) == 0) { + free(r_buf); + return rv; + } + free(r_buf); + errno = EROFS; + return -1; +} + +static int +write_boot_area(ib_params *params, uint8_t *buf, size_t len) +{ + int rv, i; + + /* + * Writing the 'label' sector (likely to be bytes 512-1023) could + * fail, so we try to avoid writing that area. + * Unfortunately, if we are accessing the raw disk, and the sector + * size is larger than 512 bytes that is also doomed. + * See how we get on.... + * + * NB: Even if the physical sector size is not 512, the space for + * the label is 512 bytes from the start of the disk. + * So all the '512' constants in these functions are correct. + */ + + /* Write out first 512 bytes - the pbr code */ + rv = pwrite_validate(params->fsfd, buf, 512, 0); + if (rv == 512) { + /* That worked, do the rest */ + if (len == 512) + return 1; + len -= 512 * 2; + rv = pwrite_validate(params->fsfd, buf + 512 * 2, len, 512 * 2); + if (rv != (ssize_t)len) + goto bad_write; + return 1; + } + if (rv != -1 || (errno != EINVAL && errno != EROFS)) + goto bad_write; + + if (errno == EINVAL) { + /* Assume the failure was due to to the sector size > 512 */ + rv = pwrite_validate(params->fsfd, buf, len, 0); + if (rv == (ssize_t)len) + return 1; + if (rv != -1 || (errno != EROFS)) + goto bad_write; + } + +#ifdef DIOCWLABEL + /* Pesky label is protected, try to unprotect it */ + i = 1; + rv = ioctl(params->fsfd, DIOCWLABEL, &i); + if (rv != 0) { + warn("Cannot enable writes to the label sector"); + return 0; + } + /* Try again with label write-enabled */ + rv = pwrite_validate(params->fsfd, buf, len, 0); + + /* Reset write-protext */ + i = 0; + ioctl(params->fsfd, DIOCWLABEL, &i); + if (rv == (ssize_t)len) + return 1; +#endif + + bad_write: + if (rv == -1) + warn("Writing `%s'", params->filesystem); + else + warnx("Writing `%s': short write, %u bytes", + params->filesystem, rv); + return 0; +} + +static void +show_i386_boot_params(struct x86_boot_params *bpp) +{ + size_t i; + + printf("Boot options: "); + printf("timeout %d, ", le32toh(bpp->bp_timeout)); + printf("flags %x, ", le32toh(bpp->bp_flags)); + printf("speed %d, ", le32toh(bpp->bp_conspeed)); + printf("ioaddr %x, ", le32toh(bpp->bp_consaddr)); + for (i = 0; i < __arraycount(consoles); i++) { + if (consoles[i].dev == (int)le32toh(bpp->bp_consdev)) + break; + } + if (i == __arraycount(consoles)) + printf("console %d\n", le32toh(bpp->bp_consdev)); + else + printf("console %s\n", consoles[i].name); + if (bpp->bp_keymap[0]) + printf(" keymap %s\n", bpp->bp_keymap); +} + +static int +is_zero(const uint8_t *p, unsigned int len) +{ + return len == 0 || (p[0] == 0 && memcmp(p, p + 1, len - 1) == 0); +} + +static int +update_i386_boot_params(ib_params *params, struct x86_boot_params *bpp) +{ + struct x86_boot_params bp; + uint32_t bplen; + size_t i; + + bplen = le32toh(bpp->bp_length); + if (bplen > sizeof bp) + /* Ignore pad space in bootxx */ + bplen = sizeof bp; + + /* Take (and update) local copy so we handle size mismatches */ + memset(&bp, 0, sizeof bp); + memcpy(&bp, bpp, bplen); + + if (params->flags & IB_TIMEOUT) + bp.bp_timeout = htole32(params->timeout); + if (params->flags & IB_RESETVIDEO) + bp.bp_flags ^= htole32(X86_BP_FLAGS_RESET_VIDEO); + if (params->flags & IB_CONSPEED) + bp.bp_conspeed = htole32(params->conspeed); + if (params->flags & IB_CONSADDR) + bp.bp_consaddr = htole32(params->consaddr); + if (params->flags & IB_CONSOLE) { + for (i = 0; i < __arraycount(consoles); i++) + if (strcmp(consoles[i].name, params->console) == 0) + break; + + if (i == __arraycount(consoles)) { + warnx("invalid console name, valid names are:"); + (void)fprintf(stderr, "\t%s", consoles[0].name); + for (i = 1; consoles[i].name != NULL; i++) + (void)fprintf(stderr, ", %s", consoles[i].name); + (void)fprintf(stderr, "\n"); + return 1; + } + bp.bp_consdev = htole32(consoles[i].dev); + } + if (params->flags & IB_PASSWORD) { + if (params->password[0]) { + MD5_CTX md5ctx; + MD5Init(&md5ctx); + MD5Update(&md5ctx, params->password, + strlen(params->password)); + MD5Final(bp.bp_password, &md5ctx); + bp.bp_flags |= htole32(X86_BP_FLAGS_PASSWORD); + } else { + memset(&bp.bp_password, 0, sizeof bp.bp_password); + bp.bp_flags &= ~htole32(X86_BP_FLAGS_PASSWORD); + } + } + if (params->flags & IB_KEYMAP) + strlcpy(bp.bp_keymap, params->keymap, sizeof bp.bp_keymap); + if (params->flags & IB_MODULES) + bp.bp_flags ^= htole32(X86_BP_FLAGS_NOMODULES); + if (params->flags & IB_BOOTCONF) + bp.bp_flags ^= htole32(X86_BP_FLAGS_NOBOOTCONF); + + if (params->flags & (IB_NOWRITE | IB_VERBOSE)) + show_i386_boot_params(&bp); + + /* Check we aren't trying to set anything we can't save */ + if (!is_zero((char *)&bp + bplen, sizeof bp - bplen)) { + warnx("Patch area in stage1 bootstrap is too small"); + return 1; + } + memcpy(bpp, &bp, bplen); + return 0; +} + +static int +i386_setboot(ib_params *params) +{ + unsigned int u; + ssize_t rv; + uint32_t *magic, expected_magic; + union { + struct mbr_sector mbr; + uint8_t b[8192]; + } disk_buf, bootstrap; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + + /* + * There is only 8k of space in a FFSv1 partition (and ustarfs) + * so ensure we don't splat over anything important. + */ + if (params->s1stat.st_size > (off_t)(sizeof bootstrap)) { + warnx("stage1 bootstrap `%s' (%u bytes) is larger than 8192 bytes", + params->stage1, (unsigned int)params->s1stat.st_size); + return 0; + } + if (params->s1stat.st_size < 3 * 512 && params->s1stat.st_size != 512) { + warnx("stage1 bootstrap `%s' (%u bytes) is too small", + params->stage1, (unsigned int)params->s1stat.st_size); + return 0; + } + + /* Read in the existing disk header and boot code */ + rv = pread(params->fsfd, &disk_buf, sizeof (disk_buf), 0); + if (rv != sizeof(disk_buf)) { + if (rv == -1) + warn("Reading `%s'", params->filesystem); + else + warnx("Reading `%s': short read, %ld bytes" + " (should be %ld)", params->filesystem, (long)rv, + (long)sizeof(disk_buf)); + return 0; + } + + if (disk_buf.mbr.mbr_magic != le16toh(MBR_MAGIC)) { + if (params->flags & IB_VERBOSE) { + printf( + "Ignoring PBR with invalid magic in sector 0 of `%s'\n", + params->filesystem); + } + memset(&disk_buf, 0, 512); + } + + /* Read the new bootstrap code. */ + rv = pread(params->s1fd, &bootstrap, params->s1stat.st_size, 0); + if (rv != params->s1stat.st_size) { + if (rv == -1) + warn("Reading `%s'", params->stage1); + else + warnx("Reading `%s': short read, %ld bytes" + " (should be %ld)", params->stage1, (long)rv, + (long)params->s1stat.st_size); + return 0; + } + + /* + * The bootstrap code is either 512 bytes for booting FAT16, or best + * part of 8k (with bytes 512-1023 all zeros). + */ + if (params->s1stat.st_size == 512) { + /* Magic number is at end of pbr code */ + magic = (void *)(bootstrap.b + 512 - 16 + 4); + expected_magic = htole32(X86_BOOT_MAGIC_FAT); + } else { + /* Magic number is at start of sector following label */ + magic = (void *)(bootstrap.b + 512 * 2 + 4); + expected_magic = htole32(X86_BOOT_MAGIC_1); + /* + * For a variety of reasons we restrict our 'normal' partition + * boot code to a size which enable it to be used as mbr code. + * IMHO this is bugus (dsl). + */ + if (!is_zero(bootstrap.b + 512-2-64, 64)) { + warnx("Data in mbr partition table of new bootstrap"); + return 0; + } + if (!is_zero(bootstrap.b + 512, 512)) { + warnx("Data in label part of new bootstrap"); + return 0; + } + /* Copy mbr table and label from existing disk buffer */ + memcpy(bootstrap.b + 512-2-64, disk_buf.b + 512-2-64, 64); + memcpy(bootstrap.b + 512, disk_buf.b + 512, 512); + } + + /* Validate the 'magic number' that marks the parameter block */ + if (*magic != expected_magic) { + warnx("Invalid magic in stage1 bootstrap %x != %x", + *magic, expected_magic); + return 0; + } + + /* + * If the partition has a FAT (or NTFS) filesystem, then we must + * preserve the BIOS Parameter Block (BPB). + * It is also very likely that there isn't 8k of space available + * for (say) bootxx_msdos, and that blindly installing it will trash + * the FAT filesystem. + * To avoid this we check the number of 'reserved' sectors to ensure + * there there is enough space. + * Unfortunately newfs(8) doesn't (yet) splat the BPB (which is + * effectively the FAT superblock) when a filesystem is initailised + * so this code tends to complain rather too often, + * Specifying 'installboot -f' will delete the old BPB info. + */ + if (!(params->flags & IB_FORCE)) { + #define USE_F ", use -f (may invalidate filesystem)" + /* + * For FAT compatibility, the pbr code starts 'jmp xx; nop' + * followed by the BIOS Parameter Block (BPB). + * The 2nd byte (jump offset) is the size of the nop + BPB. + */ + if (bootstrap.b[0] != 0xeb || bootstrap.b[2] != 0x90) { + warnx("No BPB in new bootstrap %02x:%02x:%02x" USE_F, + bootstrap.b[0], bootstrap.b[1], bootstrap.b[2]); + return 0; + } + + /* Find size of old BPB, and copy into new bootcode */ + if (!is_zero(disk_buf.b + 3 + 8, disk_buf.b[1] - 1 - 8)) { + struct mbr_bpbFAT16 *bpb = (void *)(disk_buf.b + 3 + 8); + /* Check enough space before the FAT for the bootcode */ + u = le16toh(bpb->bpbBytesPerSec) + * le16toh(bpb->bpbResSectors); + if (u != 0 && u < params->s1stat.st_size) { + warnx("Insufficient reserved space before FAT " + "(%u bytes available)" USE_F, u); + return 0; + } + /* Check we have enough space for the old bpb */ + if (disk_buf.b[1] > bootstrap.b[1]) { + /* old BPB is larger, allow if extra zeros */ + if (!is_zero(disk_buf.b + 2 + bootstrap.b[1], + disk_buf.b[1] - bootstrap.b[1])) { + warnx("Old BPB too big" USE_F); + return 0; + } + u = bootstrap.b[1]; + } else { + /* Old BPB is shorter, leave zero filled */ + u = disk_buf.b[1]; + } + memcpy(bootstrap.b + 2, disk_buf.b + 2, u); + } + #undef USE_F + } + + /* + * Fill in any user-specified options into the + * struct x86_boot_params + * that follows the magic number. + * See sys/arch/i386/stand/bootxx/bootxx.S for more information. + */ + if (update_i386_boot_params(params, (void *)(magic + 1))) + return 0; + + if (params->flags & IB_NOWRITE) { + return 1; + } + + /* Copy new bootstrap data into disk buffer, ignoring label area */ + memcpy(&disk_buf, &bootstrap, 512); + if (params->s1stat.st_size > 512 * 2) { + memcpy(disk_buf.b + 2 * 512, bootstrap.b + 2 * 512, + params->s1stat.st_size - 2 * 512); + /* Zero pad to 512 byte sector boundary */ + memset(disk_buf.b + params->s1stat.st_size, 0, + (8192 - params->s1stat.st_size) & 511); + } + + return write_boot_area(params, disk_buf.b, sizeof disk_buf.b); +} + +static int +i386_editboot(ib_params *params) +{ + int retval; + uint8_t buf[512]; + ssize_t rv; + uint32_t magic; + uint32_t offset; + struct x86_boot_params *bpp; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + + retval = 0; + + /* + * Read in the existing bootstrap. + * Look in any of the first 4 sectors. + */ + + bpp = NULL; + for (offset = 0; offset < 4 * 512; offset += 512) { + rv = pread(params->fsfd, &buf, sizeof buf, offset); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + goto done; + } else if (rv != sizeof buf) { + warnx("Reading `%s': short read", params->filesystem); + goto done; + } + + /* Magic number is 4 bytes in (to allow for a jmps) */ + /* Also allow any of the magic numbers. */ + magic = le32toh(*(uint32_t *)(buf + 4)) | 0xf; + if (magic != (X86_BOOT_MAGIC_1 | 0xf)) + continue; + + /* The parameters are just after the magic number */ + bpp = (void *)(buf + 8); + break; + } + if (bpp == NULL) { + warnx("Invalid magic in existing bootstrap"); + goto done; + } + + /* + * Fill in any user-specified options into the + * struct x86_boot_params + * that's 8 bytes in from the start of the third sector. + * See sys/arch/i386/stand/bootxx/bootxx.S for more information. + */ + if (update_i386_boot_params(params, bpp)) + goto done; + + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + /* + * Write boot code back + */ + rv = pwrite(params->fsfd, buf, sizeof buf, offset); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if (rv != sizeof buf) { + warnx("Writing `%s': short write, %zd bytes (should be %zu)", + params->filesystem, rv, sizeof(buf)); + goto done; + } + + retval = 1; + + done: + return retval; +} diff --git a/usr.sbin/installboot/arch/landisk.c b/usr.sbin/installboot/arch/landisk.c new file mode 100644 index 000000000..a5d4ef2e6 --- /dev/null +++ b/usr.sbin/installboot/arch/landisk.c @@ -0,0 +1,250 @@ +/* $NetBSD: landisk.c,v 1.5 2009/05/07 07:03:39 lukem Exp $ */ + +/*- + * Copyright (c) 2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by David Laight. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: landisk.c,v 1.5 2009/05/07 07:03:39 lukem Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +static int landisk_setboot(ib_params *); + +struct ib_mach ib_mach_landisk = + { "landisk", landisk_setboot, no_clearboot, no_editboot, + IB_TIMEOUT }; + +static int +landisk_setboot(ib_params *params) +{ + struct mbr_sector mbr; + struct landisk_boot_params bp, *bpp; + uint8_t *bootstrapbuf; + ssize_t rv; + uint32_t magic; + size_t bootstrapsize; + int retval, i; + uint32_t bplen; + int bpbsize; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + + retval = 0; + bootstrapbuf = NULL; + + /* + * There is only 8k of space in a FFSv1 partition (and ustarfs) + * so ensure we don't splat over anything important. + */ + if (params->s1stat.st_size > 8192) { + warnx("stage1 bootstrap `%s' is larger than 8192 bytes", + params->stage1); + goto done; + } + + /* + * Read in the existing MBR. + */ + rv = pread(params->fsfd, &mbr, sizeof(mbr), MBR_BBSECTOR); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + goto done; + } else if (rv != sizeof(mbr)) { + warnx("Reading `%s': short read", params->filesystem); + goto done; + } + if (mbr.mbr_magic != le16toh(MBR_MAGIC)) { + if (params->flags & IB_VERBOSE) { + printf( + "Ignoring MBR with invalid magic in sector 0 of `%s'\n", + params->filesystem); + } + memset(&mbr, 0, sizeof(mbr)); + } + + /* + * Allocate a buffer, with space to round up the input file + * to the next block size boundary, and with space for the boot + * block. + */ + bootstrapsize = roundup(params->s1stat.st_size, 512); + + bootstrapbuf = malloc(bootstrapsize); + if (bootstrapbuf == NULL) { + warn("Allocating %zu bytes", bootstrapsize); + goto done; + } + memset(bootstrapbuf, 0, bootstrapsize); + + /* + * Read the file into the buffer. + */ + rv = pread(params->s1fd, bootstrapbuf, params->s1stat.st_size, 0); + if (rv == -1) { + warn("Reading `%s'", params->stage1); + goto done; + } else if (rv != params->s1stat.st_size) { + warnx("Reading `%s': short read", params->stage1); + goto done; + } + + magic = *(uint32_t *)(bootstrapbuf + 512 * 2 + 4); + if (magic != htole32(LANDISK_BOOT_MAGIC_1)) { + warnx("Invalid magic in stage1 boostrap %x != %x", + magic, htole32(LANDISK_BOOT_MAGIC_1)); + goto done; + } + + /* + * Determine size of BIOS Parameter Block (BPB) to copy from + * original MBR to the temporary buffer by examining the first + * few instruction in the new bootblock. Supported values: + * 2b a0 11 jmp ENDOF(mbr_bpbFAT32)+1, nop + * (anything else) ; don't preserve + */ + bpbsize = 0; +#if 0 + if (bootstrapbuf[1] == 0xa0 && bootstrapbuf[2] == 0x11 && + (bootstrapbuf[0] == 0x2b /*|| bootstrapbuf[0] == 0x1d*/)) { + bpbsize = bootstrapbuf[0] + 2 - MBR_BPB_OFFSET; + } +#endif + + /* + * Ensure bootxx hasn't got any code or data (i.e, non-zero bytes) in + * the partition table. + */ + for (i = 0; i < (int)sizeof(mbr.mbr_parts); i++) { + if (*(uint8_t *)(bootstrapbuf + MBR_PART_OFFSET + i) != 0) { + warnx( + "Partition table has non-zero byte at offset %d in `%s'", + MBR_PART_OFFSET + i, params->stage1); + goto done; + } + } + +#if 0 + /* + * Copy the BPB and the partition table from the original MBR to the + * temporary buffer so that they're written back to the fs. + */ + if (bpbsize != 0) { + if (params->flags & IB_VERBOSE) + printf("Preserving %d (%#x) bytes of the BPB\n", + bpbsize, bpbsize); + (void)memcpy(bootstrapbuf + MBR_BPB_OFFSET, &mbr.mbr_bpb, + bpbsize); + } +#endif + memcpy(bootstrapbuf + MBR_PART_OFFSET, &mbr.mbr_parts, + sizeof(mbr.mbr_parts)); + + /* + * Fill in any user-specified options into the + * struct landisk_boot_params + * that's 8 bytes in from the start of the third sector. + * See sys/arch/landisk/stand/bootxx/bootxx.S for more information. + */ + bpp = (void *)(bootstrapbuf + 512 * 2 + 8); + bplen = le32toh(bpp->bp_length); + if (bplen > sizeof bp) + /* Ignore pad space in bootxx */ + bplen = sizeof bp; + /* Take (and update) local copy so we handle size mismatches */ + memset(&bp, 0, sizeof bp); + memcpy(&bp, bpp, bplen); + if (params->flags & IB_TIMEOUT) + bp.bp_timeout = htole32(params->timeout); + /* Check we aren't trying to set anything we can't save */ + if (bplen < sizeof bp && memcmp((char *)&bp + bplen, + (char *)&bp + bplen + 1, + sizeof bp - bplen - 1) != 0) { + warnx("Patch area in stage1 bootstrap is too small"); + goto done; + } + memcpy(bpp, &bp, bplen); + + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + /* + * Write MBR code to sector zero. + */ + rv = pwrite(params->fsfd, bootstrapbuf, 512, 0); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if (rv != 512) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } + + /* + * Skip disklabel in sector 1 and write bootxx to sectors 2..N. + */ + rv = pwrite(params->fsfd, bootstrapbuf + 512 * 2, + bootstrapsize - 512 * 2, 512 * 2); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if ((size_t)rv != bootstrapsize - 512 * 2) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } + + retval = 1; + + done: + if (bootstrapbuf) + free(bootstrapbuf); + return retval; +} diff --git a/usr.sbin/installboot/arch/macppc.c b/usr.sbin/installboot/arch/macppc.c new file mode 100644 index 000000000..1f4e88beb --- /dev/null +++ b/usr.sbin/installboot/arch/macppc.c @@ -0,0 +1,186 @@ +/* $NetBSD: macppc.c,v 1.11 2008/05/24 19:15:21 tsutsui Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: macppc.c,v 1.11 2008/05/24 19:15:21 tsutsui Exp $"); +#endif /* !__lint */ + +#include +#ifndef HAVE_NBTOOL_CONFIG_H +#include +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include "installboot.h" + +static struct bbinfo_params bbparams = { + MACPPC_BBINFO_MAGIC, + MACPPC_BOOT_BLOCK_OFFSET, + MACPPC_BOOT_BLOCK_BLOCKSIZE, + MACPPC_BOOT_BLOCK_MAX_SIZE, + 0, + BBINFO_BIG_ENDIAN, +}; + +static int writeapplepartmap(ib_params *, struct bbinfo_params *, uint8_t *); + +static int macppc_clearboot(ib_params *); +static int macppc_setboot(ib_params *); + +struct ib_mach ib_mach_macppc = + { "macppc", macppc_setboot, macppc_clearboot, no_editboot, + IB_STAGE2START }; + +static int +macppc_clearboot(ib_params *params) +{ + + assert(params != NULL); + + /* XXX: maybe clear the apple partition map too? */ + return (shared_bbinfo_clearboot(params, &bbparams, NULL)); +} + +static int +macppc_setboot(ib_params *params) +{ + + assert(params != NULL); + + return (shared_bbinfo_setboot(params, &bbparams, writeapplepartmap)); +} + + +static int +writeapplepartmap(ib_params *params, struct bbinfo_params *bb_params, + uint8_t *bb) +{ + struct apple_drvr_map dm; + struct apple_part_map_entry pme; + int rv; + + assert (params != NULL); + assert (bb_params != NULL); + assert (bb != NULL); + + if (params->flags & IB_NOWRITE) + return (1); + + /* block 0: driver map */ + if (pread(params->fsfd, &dm, MACPPC_BOOT_BLOCK_BLOCKSIZE, 0) != + MACPPC_BOOT_BLOCK_BLOCKSIZE) { + warn("Can't read sector 0 of `%s'", params->filesystem); + return (0); + } + dm.sbSig = htobe16(APPLE_DRVR_MAP_MAGIC); + dm.sbBlockSize = htobe16(512); + dm.sbBlkCount = htobe32(0); + + rv = pwrite(params->fsfd, &dm, MACPPC_BOOT_BLOCK_BLOCKSIZE, 0); +#ifdef DIOCWLABEL + if (rv == -1 && errno == EROFS) { + /* + * block 0 is LABELSECTOR which might be protected by + * bounds_check_with_label(9). + */ + int enable; + + enable = 1; + rv = ioctl(params->fsfd, DIOCWLABEL, &enable); + if (rv != 0) { + warn("Cannot enable writes to the label sector"); + return 0; + } + + rv = pwrite(params->fsfd, &dm, MACPPC_BOOT_BLOCK_BLOCKSIZE, 0); + + /* Reset write-protect. */ + enable = 0; + (void)ioctl(params->fsfd, DIOCWLABEL, &enable); + } +#endif + if (rv != MACPPC_BOOT_BLOCK_BLOCKSIZE) { + warn("Can't write sector 0 of `%s'", params->filesystem); + return (0); + } + + /* block 1: Apple Partition Map */ + memset(&pme, 0, sizeof(pme)); + pme.pmSig = htobe16(APPLE_PART_MAP_ENTRY_MAGIC); + pme.pmMapBlkCnt = htobe32(2); + pme.pmPyPartStart = htobe32(1); + pme.pmPartBlkCnt = htobe32(2); + pme.pmDataCnt = htobe32(2); + strlcpy(pme.pmPartName, "Apple", sizeof(pme.pmPartName)); + strlcpy(pme.pmPartType, "Apple_partition_map", sizeof(pme.pmPartType)); + pme.pmPartStatus = htobe32(0x37); + if (pwrite(params->fsfd, &pme, MACPPC_BOOT_BLOCK_BLOCKSIZE, + 1 * MACPPC_BOOT_BLOCK_BLOCKSIZE) != MACPPC_BOOT_BLOCK_BLOCKSIZE) { + warn("Can't write Apple Partition Map into sector 1 of `%s'", + params->filesystem); + return (0); + } + + /* block 2: NetBSD partition */ + memset(&pme, 0, sizeof(pme)); + pme.pmSig = htobe16(APPLE_PART_MAP_ENTRY_MAGIC); + pme.pmMapBlkCnt = htobe32(2); + pme.pmPyPartStart = htobe32(4); + pme.pmPartBlkCnt = htobe32(0x7fffffff); + pme.pmDataCnt = htobe32(0x7fffffff); + strlcpy(pme.pmPartName, "NetBSD", sizeof(pme.pmPartName)); + strlcpy(pme.pmPartType, "NetBSD/macppc", sizeof(pme.pmPartType)); + pme.pmPartStatus = htobe32(0x3b); + pme.pmBootSize = htobe32(roundup(params->s1stat.st_size, 512)); + pme.pmBootLoad = htobe32(0x4000); + pme.pmBootEntry = htobe32(0x4000); + strlcpy(pme.pmProcessor, "PowerPC", sizeof(pme.pmProcessor)); + if (pwrite(params->fsfd, &pme, MACPPC_BOOT_BLOCK_BLOCKSIZE, + 2 * MACPPC_BOOT_BLOCK_BLOCKSIZE) != MACPPC_BOOT_BLOCK_BLOCKSIZE) { + warn("Can't write Apple Partition Map into sector 2 of `%s'", + params->filesystem); + return (0); + } + + return (1); +} diff --git a/usr.sbin/installboot/arch/news.c b/usr.sbin/installboot/arch/news.c new file mode 100644 index 000000000..27acd8b5d --- /dev/null +++ b/usr.sbin/installboot/arch/news.c @@ -0,0 +1,166 @@ +/* $NetBSD: news.c,v 1.7 2008/04/28 20:24:16 martin Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn and Izumi Tsutsui. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: news.c,v 1.7 2008/04/28 20:24:16 martin Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +static int news_copydisklabel(ib_params *, struct bbinfo_params *, uint8_t *); + +static int news68k_clearboot(ib_params *); +static int news68k_setboot(ib_params *); +static int newsmips_clearboot(ib_params *); +static int newsmips_setboot(ib_params *); + +struct ib_mach ib_mach_news68k = + { "news68k", news68k_setboot, news68k_clearboot, no_editboot, + IB_STAGE2START }; + +struct ib_mach ib_mach_newsmips = + { "newsmips", newsmips_setboot, newsmips_clearboot, no_editboot, + IB_STAGE2START }; + +/* + * news68k specific support + */ + +static struct bbinfo_params news68k_bbparams = { + NEWS68K_BBINFO_MAGIC, + NEWS_BOOT_BLOCK_OFFSET, /* write all 8K (including disklabel) */ + NEWS_BOOT_BLOCK_BLOCKSIZE, + NEWS_BOOT_BLOCK_MAX_SIZE, + 0, + BBINFO_BIG_ENDIAN, +}; + +static int +news68k_clearboot(ib_params *params) +{ + + assert(params != NULL); + + return (shared_bbinfo_clearboot(params, &news68k_bbparams, + news_copydisklabel)); +} + +static int +news68k_setboot(ib_params *params) +{ + + assert(params != NULL); + + return (shared_bbinfo_setboot(params, &news68k_bbparams, + news_copydisklabel)); +} + + +/* + * newsmips specific support + */ + +static struct bbinfo_params newsmips_bbparams = { + NEWSMIPS_BBINFO_MAGIC, + NEWS_BOOT_BLOCK_OFFSET, /* write all 8K (including disklabel) */ + NEWS_BOOT_BLOCK_BLOCKSIZE, + NEWS_BOOT_BLOCK_MAX_SIZE, + 0, + BBINFO_BIG_ENDIAN, +}; + +static int +newsmips_clearboot(ib_params *params) +{ + + assert(params != NULL); + + return (shared_bbinfo_clearboot(params, &newsmips_bbparams, + news_copydisklabel)); +} + +static int +newsmips_setboot(ib_params *params) +{ + + assert(params != NULL); + + return (shared_bbinfo_setboot(params, &newsmips_bbparams, + news_copydisklabel)); +} + + +/* + * news_copydisklabel -- + * copy disklabel from existing location on disk into bootstrap, + * as the primary bootstrap contains the disklabel. + */ +static int +news_copydisklabel(ib_params *params, struct bbinfo_params *bbparams, + uint8_t *bb) +{ + uint8_t boot00[NEWS_BOOT_BLOCK_BLOCKSIZE]; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(bbparams != NULL); + assert(bb != NULL); + + /* Read label sector to copy disklabel from */ + memset(boot00, 0, sizeof(boot00)); + rv = pread(params->fsfd, boot00, sizeof(boot00), 0); + if (rv == -1) { + warn("Reading label sector from `%s'", params->filesystem); + return (0); + } + /* Copy disklabel */ + memcpy(bb + NEWS_BOOT_BLOCK_LABELOFFSET, + boot00 + NEWS_BOOT_BLOCK_LABELOFFSET, + sizeof(boot00) - NEWS_BOOT_BLOCK_LABELOFFSET); + + return (1); +} diff --git a/usr.sbin/installboot/arch/next68k.c b/usr.sbin/installboot/arch/next68k.c new file mode 100644 index 000000000..438dd1366 --- /dev/null +++ b/usr.sbin/installboot/arch/next68k.c @@ -0,0 +1,267 @@ +/* $NetBSD: next68k.c,v 1.7 2010/01/07 13:26:00 tsutsui Exp $ */ + +/*- + * Copyright (c) 2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by David Laight and Christian Limpach. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: next68k.c,v 1.7 2010/01/07 13:26:00 tsutsui Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +static uint16_t nextstep_checksum(const void *, const void *); +static int next68k_setboot(ib_params *); + +struct ib_mach ib_mach_next68k = + { "next68k", next68k_setboot, no_clearboot, no_editboot, 0}; + +static uint16_t +nextstep_checksum(const void *vbuf, const void *vlimit) +{ + const uint16_t *buf = vbuf; + const uint16_t *limit = vlimit; + u_int sum = 0; + + while (buf < limit) { + sum += be16toh(*buf++); + } + sum += (sum >> 16); + return (sum & 0xffff); +} + +static int +next68k_setboot(ib_params *params) +{ + int retval, labelupdated; + uint8_t *bootbuf; + size_t bootsize; + ssize_t rv; + uint32_t cd_secsize; + int sec_netonb_mult; + struct next68k_disklabel *next68klabel; + uint16_t *checksum; + uint32_t fp, b0, b1; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + + retval = 0; + labelupdated = 0; + bootbuf = NULL; + + next68klabel = malloc(NEXT68K_LABEL_SIZE); + if (next68klabel == NULL) { + warn("Allocating %lu bytes", (unsigned long)NEXT68K_LABEL_SIZE); + goto done; + } + + /* + * Read in the next68k disklabel + */ + rv = pread(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE, + NEXT68K_LABEL_SECTOR * params->sectorsize + NEXT68K_LABEL_OFFSET); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + goto done; + } + if (rv != NEXT68K_LABEL_SIZE) { + warnx("Reading `%s': short read", params->filesystem); + goto done; + } + if (be32toh(next68klabel->cd_version) == NEXT68K_LABEL_CD_V3) { + checksum = &next68klabel->NEXT68K_LABEL_cd_v3_checksum; + } else { + checksum = &next68klabel->cd_checksum; + } + if (nextstep_checksum (next68klabel, checksum) != + be16toh(*checksum)) { + warn("Disklabel checksum invalid on `%s'", + params->filesystem); + goto done; + } + + cd_secsize = be32toh(next68klabel->cd_secsize); + sec_netonb_mult = (cd_secsize / params->sectorsize); + + /* + * Allocate a buffer, with space to round up the input file + * to the next block size boundary, and with space for the boot + * block. + */ + bootsize = roundup(params->s1stat.st_size, cd_secsize); + + bootbuf = malloc(bootsize); + if (bootbuf == NULL) { + warn("Allocating %zu bytes", bootsize); + goto done; + } + memset(bootbuf, 0, bootsize); + + /* + * Read the file into the buffer. + */ + rv = pread(params->s1fd, bootbuf, params->s1stat.st_size, 0); + if (rv == -1) { + warn("Reading `%s'", params->stage1); + goto done; + } else if (rv != params->s1stat.st_size) { + warnx("Reading `%s': short read", params->stage1); + goto done; + } + + if (bootsize > be16toh(next68klabel->cd_front) * cd_secsize - + NEXT68K_LABEL_SIZE) { + warnx("Boot program is larger than front porch space"); + goto done; + } + + fp = be16toh(next68klabel->cd_front); + b0 = be32toh(next68klabel->cd_boot_blkno[0]); + b1 = be32toh(next68klabel->cd_boot_blkno[1]); + + if (b0 > fp) + b0 = fp; + if (b1 > fp) + b1 = fp; + if (((bootsize / cd_secsize) > b1 - b0) || + ((bootsize / cd_secsize) > fp - b1)) { + if (2 * bootsize > (fp * cd_secsize - NEXT68K_LABEL_SIZE)) + /* can only fit one copy */ + b0 = b1 = NEXT68K_LABEL_SIZE / cd_secsize; + else { + if (2 * bootsize > (fp * cd_secsize - + NEXT68K_LABEL_DEFAULTBOOT0_1 * + params->sectorsize)) + /* can fit two copies starting after label */ + b0 = NEXT68K_LABEL_SIZE / cd_secsize; + else + /* can fit two copies starting at default 1 */ + b0 = NEXT68K_LABEL_DEFAULTBOOT0_1 / + sec_netonb_mult; + /* try to fit 2nd copy at default 2 */ + b1 = NEXT68K_LABEL_DEFAULTBOOT0_2 / sec_netonb_mult; + if (fp < b1) + b1 = fp; + if (bootsize / cd_secsize > (fp - b1)) + /* fit 2nd copy before front porch */ + b1 = fp - bootsize / cd_secsize; + } + } + if (next68klabel->cd_boot_blkno[0] != (int32_t)htobe32(b0)) { + next68klabel->cd_boot_blkno[0] = htobe32(b0); + labelupdated = 1; + } + if (next68klabel->cd_boot_blkno[1] != (int32_t)htobe32(b1)) { + next68klabel->cd_boot_blkno[1] = htobe32(b1); + labelupdated = 1; + } + if (params->flags & IB_VERBOSE) + printf("Boot programm locations%s: %d %d\n", + labelupdated ? " updated" : "", b0 * sec_netonb_mult, + b1 * sec_netonb_mult); + + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + /* + * Write the updated next68k disklabel + */ + if (labelupdated) { + if (params->flags & IB_VERBOSE) + printf ("Writing updated label\n"); + *checksum = htobe16(nextstep_checksum (next68klabel, + checksum)); + rv = pwrite(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE, + NEXT68K_LABEL_SECTOR * params->sectorsize + + NEXT68K_LABEL_OFFSET); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } + if (rv != NEXT68K_LABEL_SIZE) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } + } + + b0 *= sec_netonb_mult; + b1 *= sec_netonb_mult; + + /* + * Write boot program to locations b0 and b1 (if different). + */ + for (;;) { + if (params->flags & IB_VERBOSE) + printf ("Writing boot program at %d\n", b0); + rv = pwrite(params->fsfd, bootbuf, bootsize, + b0 * params->sectorsize); + if (rv == -1) { + warn("Writing `%s' at %d", params->filesystem, b0); + goto done; + } + if ((size_t)rv != bootsize) { + warnx("Writing `%s' at %d: short write", + params->filesystem, b0); + goto done; + } + if (b0 == b1) + break; + b0 = b1; + } + + retval = 1; + + done: + if (bootbuf) + free(bootbuf); + if (next68klabel) + free(next68klabel); + return retval; +} diff --git a/usr.sbin/installboot/arch/pmax.c b/usr.sbin/installboot/arch/pmax.c new file mode 100644 index 000000000..bdbdde71c --- /dev/null +++ b/usr.sbin/installboot/arch/pmax.c @@ -0,0 +1,369 @@ +/* $NetBSD: pmax.c,v 1.14 2009/04/05 11:55:39 lukem Exp $ */ + +/*- + * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Simon Burge. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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. + */ + +/* + * Copyright (c) 1999 Ross Harvey. All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ross Harvey + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * Copyright (c) 1999 Christopher G. Demetriou. All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christopher G. Demetriou + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 +#if !defined(__lint) +__RCSID("$NetBSD: pmax.c,v 1.14 2009/04/05 11:55:39 lukem Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "installboot.h" + +static int load_bootstrap(ib_params *, char **, + uint32_t *, uint32_t *, size_t *); + +static int pmax_clearboot(ib_params *); +static int pmax_setboot(ib_params *); + +struct ib_mach ib_mach_pmax = + { "pmax", pmax_setboot, pmax_clearboot, no_editboot, + IB_STAGE1START | IB_APPEND | IB_SUNSUM }; + + +static int +pmax_clearboot(ib_params *params) +{ + struct pmax_boot_block bb; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE); + + rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + return (0); + } else if (rv != sizeof(bb)) { + warnx("Reading `%s': short read", params->filesystem); + return (0); + } + + if (le32toh(bb.magic) != PMAX_BOOT_MAGIC) { + warnx( + "Old boot block magic number invalid; boot block invalid"); + return (0); + } + + bb.map[0].num_blocks = bb.map[0].start_block = bb.mode = 0; + bb.magic = htole32(PMAX_BOOT_MAGIC); + + if (params->flags & IB_SUNSUM) { + uint16_t sum; + + sum = compute_sunsum((uint16_t *)&bb); + if (! set_sunsum(params, (uint16_t *)&bb, sum)) + return (0); + } + + if (params->flags & IB_VERBOSE) + printf("%slearing boot block\n", + (params->flags & IB_NOWRITE) ? "Not c" : "C"); + if (params->flags & IB_NOWRITE) + return (1); + + rv = pwrite(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + return (0); + } else if (rv != sizeof(bb)) { + warnx("Writing `%s': short write", params->filesystem); + return (0); + } + + return (1); +} + +static int +pmax_setboot(ib_params *params) +{ + struct pmax_boot_block bb; + uint32_t startblock; + int retval; + char *bootstrapbuf; + size_t bootstrapsize; + uint32_t bootstrapload, bootstrapexec; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE); + + retval = 0; + bootstrapbuf = NULL; + + if (! load_bootstrap(params, &bootstrapbuf, &bootstrapload, + &bootstrapexec, &bootstrapsize)) + goto done; + + rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + goto done; + } else if (rv != sizeof(bb)) { + warnx("Reading `%s': short read", params->filesystem); + goto done; + } + + /* fill in the updated boot block fields */ + if (params->flags & IB_APPEND) { + if (! S_ISREG(params->fsstat.st_mode)) { + warnx( + "`%s' must be a regular file to append a bootstrap", + params->filesystem); + goto done; + } + startblock = howmany(params->fsstat.st_size, + PMAX_BOOT_BLOCK_BLOCKSIZE); + } else if (params->flags & IB_STAGE1START) { + startblock = params->s1start; + } else { + startblock = PMAX_BOOT_BLOCK_OFFSET / PMAX_BOOT_BLOCK_BLOCKSIZE + + 1; + } + + bb.map[0].start_block = htole32(startblock); + bb.map[0].num_blocks = + htole32(howmany(bootstrapsize, PMAX_BOOT_BLOCK_BLOCKSIZE)); + bb.magic = htole32(PMAX_BOOT_MAGIC); + bb.load_addr = htole32(bootstrapload); + bb.exec_addr = htole32(bootstrapexec); + bb.mode = htole32(PMAX_BOOTMODE_CONTIGUOUS); + + if (params->flags & IB_SUNSUM) { + uint16_t sum; + + sum = compute_sunsum((uint16_t *)&bb); + if (! set_sunsum(params, (uint16_t *)&bb, sum)) + goto done; + } + + if (params->flags & IB_VERBOSE) { + printf("Bootstrap start sector: %u\n", + le32toh(bb.map[0].start_block)); + printf("Bootstrap sector count: %u\n", + le32toh(bb.map[0].num_blocks)); + printf("Bootstrap load address: %#x\n", + le32toh(bb.load_addr)); + printf("Bootstrap exec address: %#x\n", + le32toh(bb.exec_addr)); + printf("%sriting bootstrap\n", + (params->flags & IB_NOWRITE) ? "Not w" : "W"); + } + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize, + startblock * PMAX_BOOT_BLOCK_BLOCKSIZE); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if ((size_t)rv != bootstrapsize) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } + + if (params->flags & IB_VERBOSE) + printf("Writing boot block\n"); + rv = pwrite(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if (rv != sizeof(bb)) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } else { + retval = 1; + } + + done: + if (bootstrapbuf) + free(bootstrapbuf); + return (retval); +} + + +#define MAX_SEGMENTS 10 /* We can load up to 10 segments */ + +struct seglist { + Elf32_Addr addr; + Elf32_Off f_offset; + Elf32_Word f_size; +}; + +static int +load_bootstrap(ib_params *params, char **data, + uint32_t *loadaddr, uint32_t *execaddr, size_t *len) +{ + int i, nsegs; + Elf32_Addr lowaddr, highaddr; + Elf32_Ehdr ehdr; + Elf32_Phdr phdr; + struct seglist seglist[MAX_SEGMENTS]; + + if ((pread(params->s1fd, &ehdr, sizeof(ehdr), 0)) != sizeof(ehdr)) { + warn("Reading `%s'", params->stage1); + return (0); + } + if ((memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) || + (ehdr.e_ident[EI_CLASS] != ELFCLASS32)) { + warnx("No ELF header in `%s'", params->stage1); + return (0); + } + + nsegs = highaddr = 0; + lowaddr = (uint32_t) ULONG_MAX; + + for (i = 0; i < le16toh(ehdr.e_phnum); i++) { + if (pread(params->s1fd, &phdr, sizeof(phdr), + (off_t) le32toh(ehdr.e_phoff) + i * sizeof(phdr)) + != sizeof(phdr)) { + warn("Reading `%s'", params->stage1); + return (0); + } + if (le32toh(phdr.p_type) != PT_LOAD) + continue; + + seglist[nsegs].addr = le32toh(phdr.p_paddr); + seglist[nsegs].f_offset = le32toh(phdr.p_offset); + seglist[nsegs].f_size = le32toh(phdr.p_filesz); + nsegs++; + + if (le32toh(phdr.p_paddr) < lowaddr) + lowaddr = le32toh(phdr.p_paddr); + if (le32toh(phdr.p_paddr) + le32toh(phdr.p_filesz) > highaddr) + highaddr = le32toh(phdr.p_paddr) + + le32toh(phdr.p_filesz); + } + + *loadaddr = lowaddr; + *execaddr = le32toh(ehdr.e_entry); + *len = roundup(highaddr - lowaddr, PMAX_BOOT_BLOCK_BLOCKSIZE); + if ((*data = malloc(*len)) == NULL) { + warn("Allocating %lu bytes", (unsigned long) *len); + return (0); + } + + /* Now load the bootstrap into memory */ + for (i = 0; i < nsegs; i++) { + if ((Elf32_Word)pread(params->s1fd, + *data + seglist[i].addr - lowaddr, + seglist[i].f_size, (off_t)seglist[i].f_offset) + != seglist[i].f_size) { + warn("Reading `%s'", params->stage1); + return (0); + } + } + return (1); +} diff --git a/usr.sbin/installboot/arch/sparc.c b/usr.sbin/installboot/arch/sparc.c new file mode 100644 index 000000000..2629442d9 --- /dev/null +++ b/usr.sbin/installboot/arch/sparc.c @@ -0,0 +1,128 @@ +/* $NetBSD: sparc.c,v 1.11 2008/04/28 20:24:16 martin Exp $ */ + +/*- + * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Paul Kranenburg and Luke Mewburn. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: sparc.c,v 1.11 2008/04/28 20:24:16 martin Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +static struct bbinfo_params bbparams = { + SPARC_BBINFO_MAGIC, + SPARC_BOOT_BLOCK_OFFSET, + SPARC_BOOT_BLOCK_BLOCKSIZE, + SPARC_BOOT_BLOCK_MAX_SIZE, + 32, /* leave room for a.out header */ + BBINFO_BIG_ENDIAN, +}; + +static int sparc_clearheader(ib_params *, struct bbinfo_params *, uint8_t *); +static int sparc_setheader(ib_params *, struct bbinfo_params *, uint8_t *); + +static int sparc_clearboot(ib_params *); +static int sparc_setboot(ib_params *); + +struct ib_mach ib_mach_sparc = + { "sparc", sparc_setboot, sparc_clearboot, no_editboot, + IB_STAGE2START }; + +static int +sparc_clearboot(ib_params *params) +{ + + assert(params != NULL); + + return (shared_bbinfo_clearboot(params, &bbparams, sparc_clearheader)); +} + +static int +sparc_setboot(ib_params *params) +{ + assert(params != NULL); + + return (shared_bbinfo_setboot(params, &bbparams, sparc_setheader)); +} + + +static int +sparc_clearheader(ib_params *params, struct bbinfo_params *bb_params, + uint8_t *bb) +{ + + assert(params != NULL); + assert(bb_params != NULL); + assert(bb != NULL); + + memset(bb, 0, bb_params->headeroffset); + return (1); +} + +static int +sparc_setheader(ib_params *params, struct bbinfo_params *bb_params, uint8_t *bb) +{ + + assert(params != NULL); + assert(bb_params != NULL); + assert(bb != NULL); + + /* + * sun4c/sun4m PROMs require an a.out(5) format header. + * Old-style sun4 PROMs do not expect a header at all. + * To deal with this, we construct a header that is also executable + * code containing a forward branch that gets us past the 32-byte + * header where the actual code begins. In assembly: + * .word MAGIC ! a NOP + * ba,a start ! + * .skip 24 ! pad + * start: + */ +#define SUN_MAGIC 0x01030107 +#define SUN4_BASTART 0x30800007 /* i.e.: ba,a `start' */ + *((uint32_t *)bb) = htobe32(SUN_MAGIC); + *((uint32_t *)bb + 1) = htobe32(SUN4_BASTART); + + return (1); +} diff --git a/usr.sbin/installboot/arch/sparc64.c b/usr.sbin/installboot/arch/sparc64.c new file mode 100644 index 000000000..4fc87721c --- /dev/null +++ b/usr.sbin/installboot/arch/sparc64.c @@ -0,0 +1,185 @@ +/* $NetBSD: sparc64.c,v 1.18 2010/01/14 16:27:49 tsutsui Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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. + */ + +/* + * Copyright (c) 2002 Matthew R. Green + * All rights reserved. + * + * 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 AUTHOR ``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 AUTHOR 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 +#if !defined(__lint) +__RCSID("$NetBSD: sparc64.c,v 1.18 2010/01/14 16:27:49 tsutsui Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +static int sparc64_clearboot(ib_params *); +static int sparc64_setboot(ib_params *); + +struct ib_mach ib_mach_sparc64 = + { "sparc64", sparc64_setboot, sparc64_clearboot, no_editboot, 0}; + +static int +sparc64_clearboot(ib_params *params) +{ + char bb[SPARC64_BOOT_BLOCK_MAX_SIZE]; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + + if (params->flags & (IB_STAGE1START | IB_STAGE2START)) { + warnx("`-b bno' and `-B bno' are not supported for %s", + params->machine->name); + return (0); + } + + /* first check that it _could_ exist here */ + rv = pread(params->fsfd, &bb, sizeof(bb), SPARC64_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + return (0); + } else if (rv != sizeof(bb)) { + warnx("Reading `%s': short read", params->filesystem); + return (0); + } + + /* now clear it out to nothing */ + memset(&bb, 0, sizeof(bb)); + + if (params->flags & IB_VERBOSE) + printf("%slearing boot block\n", + (params->flags & IB_NOWRITE) ? "Not c" : "C"); + if (params->flags & IB_NOWRITE) + return (1); + + rv = pwrite(params->fsfd, &bb, sizeof(bb), SPARC64_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + return (0); + } else if (rv != sizeof(bb)) { + warnx("Writing `%s': short write", params->filesystem); + return (0); + } + + return (1); +} + +static int +sparc64_setboot(ib_params *params) +{ + char bb[SPARC64_BOOT_BLOCK_MAX_SIZE]; + int retval; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + + retval = 0; + + if (params->flags & (IB_STAGE1START | IB_STAGE2START)) { + warnx("`-b bno' and `-B bno' are not supported for %s", + params->machine->name); + goto done; + } + + memset(&bb, 0, SPARC64_BOOT_BLOCK_MAX_SIZE); + rv = read(params->s1fd, &bb, sizeof(bb)); + if (rv == -1) { + warn("Reading `%s'", params->stage1); + goto done; + } + + if (params->flags & IB_VERBOSE) { + printf("Bootstrap start sector: %u\n", + SPARC64_BOOT_BLOCK_OFFSET / SPARC64_BOOT_BLOCK_BLOCKSIZE); + printf("Bootstrap byte count: %u\n", (unsigned)rv); + printf("%sriting bootstrap\n", + (params->flags & IB_NOWRITE) ? "Not w" : "W"); + } + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + rv = pwrite(params->fsfd, &bb, SPARC64_BOOT_BLOCK_MAX_SIZE, + SPARC64_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if (rv != SPARC64_BOOT_BLOCK_MAX_SIZE) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } else + retval = 1; + + done: + return (retval); +} diff --git a/usr.sbin/installboot/arch/sun68k.c b/usr.sbin/installboot/arch/sun68k.c new file mode 100644 index 000000000..a4c900b5a --- /dev/null +++ b/usr.sbin/installboot/arch/sun68k.c @@ -0,0 +1,85 @@ +/* $NetBSD: sun68k.c,v 1.21 2008/04/28 20:24:16 martin Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: sun68k.c,v 1.21 2008/04/28 20:24:16 martin Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include + +#include "installboot.h" + +static int sun68k_clearboot(ib_params *); +static int sun68k_setboot(ib_params *); + +struct ib_mach ib_mach_sun2 = + { "sun2", sun68k_setboot, sun68k_clearboot, no_editboot, + IB_STAGE2START }; + +struct ib_mach ib_mach_sun3 = + { "sun3", sun68k_setboot, sun68k_clearboot, no_editboot, + IB_STAGE2START }; + +static struct bbinfo_params bbparams = { + SUN68K_BBINFO_MAGIC, + SUN68K_BOOT_BLOCK_OFFSET, + SUN68K_BOOT_BLOCK_BLOCKSIZE, + SUN68K_BOOT_BLOCK_MAX_SIZE, + 0, + BBINFO_BIG_ENDIAN, +}; + +static int +sun68k_clearboot(ib_params *params) +{ + + assert(params != NULL); + + return (shared_bbinfo_clearboot(params, &bbparams, NULL)); +} + +static int +sun68k_setboot(ib_params *params) +{ + + assert(params != NULL); + + return (shared_bbinfo_setboot(params, &bbparams, NULL)); +} diff --git a/usr.sbin/installboot/arch/vax.c b/usr.sbin/installboot/arch/vax.c new file mode 100644 index 000000000..453fc9a65 --- /dev/null +++ b/usr.sbin/installboot/arch/vax.c @@ -0,0 +1,316 @@ +/* $NetBSD: vax.c,v 1.13 2009/04/05 11:55:39 lukem Exp $ */ + +/*- + * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Simon Burge. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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. + */ + +/* + * Copyright (c) 1999 Christopher G. Demetriou. All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christopher G. Demetriou + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 +#if !defined(__lint) +__RCSID("$NetBSD: vax.c,v 1.13 2009/04/05 11:55:39 lukem Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +static int load_bootstrap(ib_params *, char **, + uint32_t *, uint32_t *, size_t *); + +static int vax_clearboot(ib_params *); +static int vax_setboot(ib_params *); + +struct ib_mach ib_mach_vax = + { "vax", vax_setboot, vax_clearboot, no_editboot, + IB_STAGE1START | IB_APPEND | IB_SUNSUM }; + +static int +vax_clearboot(ib_params *params) +{ + struct vax_boot_block bb; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(sizeof(struct vax_boot_block) == VAX_BOOT_BLOCK_BLOCKSIZE); + + rv = pread(params->fsfd, &bb, sizeof(bb), VAX_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + return (0); + } else if (rv != sizeof(bb)) { + warnx("Reading `%s': short read", params->filesystem); + return (0); + } + + if (bb.bb_id_offset * 2 != offsetof(struct vax_boot_block, bb_magic1) + || bb.bb_magic1 != VAX_BOOT_MAGIC1) { + warnx( + "Old boot block magic number invalid; boot block invalid"); + return (0); + } + + bb.bb_id_offset = 1; + bb.bb_mbone = 0; + bb.bb_lbn_hi = 0; + bb.bb_lbn_low = 0; + + if (params->flags & IB_SUNSUM) { + uint16_t sum; + + sum = compute_sunsum((uint16_t *)&bb); + if (! set_sunsum(params, (uint16_t *)&bb, sum)) + return (0); + } + + if (params->flags & IB_VERBOSE) + printf("%slearing boot block\n", + (params->flags & IB_NOWRITE) ? "Not c" : "C"); + if (params->flags & IB_NOWRITE) + return (1); + + rv = pwrite(params->fsfd, &bb, sizeof(bb), VAX_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + return (0); + } else if (rv != sizeof(bb)) { + warnx("Writing `%s': short write", params->filesystem); + return (0); + } + + return (1); +} + +static int +vax_setboot(ib_params *params) +{ + struct stat bootstrapsb; + struct vax_boot_block bb; + uint32_t startblock; + int retval; + char *bootstrapbuf; + size_t bootstrapsize; + uint32_t bootstrapload, bootstrapexec; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + assert(sizeof(struct vax_boot_block) == VAX_BOOT_BLOCK_BLOCKSIZE); + + retval = 0; + bootstrapbuf = NULL; + + if (fstat(params->s1fd, &bootstrapsb) == -1) { + warn("Examining `%s'", params->stage1); + goto done; + } + if (!S_ISREG(bootstrapsb.st_mode)) { + warnx("`%s' must be a regular file", params->stage1); + goto done; + } + if (! load_bootstrap(params, &bootstrapbuf, &bootstrapload, + &bootstrapexec, &bootstrapsize)) + goto done; + + rv = pread(params->fsfd, &bb, sizeof(bb), VAX_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + goto done; + } else if (rv != sizeof(bb)) { + warnx("Reading `%s': short read", params->filesystem); + goto done; + } + + /* fill in the updated boot block fields */ + if (params->flags & IB_APPEND) { + struct stat filesyssb; + + if (fstat(params->fsfd, &filesyssb) == -1) { + warn("Examining `%s'", params->filesystem); + goto done; + } + if (!S_ISREG(filesyssb.st_mode)) { + warnx( + "`%s' must be a regular file to append a bootstrap", + params->filesystem); + goto done; + } + startblock = howmany(filesyssb.st_size, + VAX_BOOT_BLOCK_BLOCKSIZE); + } else if (params->flags & IB_STAGE1START) { + startblock = params->s1start; + } else { + startblock = VAX_BOOT_BLOCK_OFFSET / VAX_BOOT_BLOCK_BLOCKSIZE + + 1; + } + + bb.bb_id_offset = offsetof(struct vax_boot_block, bb_magic1) / 2; + bb.bb_mbone = 1; + bb.bb_lbn_hi = htole16((uint16_t) (startblock >> 16)); + bb.bb_lbn_low = htole16((uint16_t) (startblock >> 0)); + /* + * Now the identification block + */ + bb.bb_magic1 = VAX_BOOT_MAGIC1; + bb.bb_mbz1 = 0; + bb.bb_sum1 = ~(bb.bb_magic1 + bb.bb_mbz1 + bb.bb_pad1); + + bb.bb_mbz2 = 0; + bb.bb_volinfo = VAX_BOOT_VOLINFO_NONE; + bb.bb_pad2a = 0; + bb.bb_pad2b = 0; + + bb.bb_size = htole32(bootstrapsize / VAX_BOOT_BLOCK_BLOCKSIZE); + bb.bb_load = htole32(VAX_BOOT_LOAD); + bb.bb_entry = htole32(VAX_BOOT_ENTRY); + bb.bb_sum3 = htole32(le32toh(bb.bb_size) + le32toh(bb.bb_load) \ + + le32toh(bb.bb_entry)); + + if (params->flags & IB_SUNSUM) { + uint16_t sum; + + sum = compute_sunsum((uint16_t *)&bb); + if (! set_sunsum(params, (uint16_t *)&bb, sum)) + goto done; + } + + if (params->flags & IB_VERBOSE) { + printf("Bootstrap start sector: %u\n", startblock); + printf("Bootstrap sector count: %u\n", le32toh(bb.bb_size)); + printf("%sriting bootstrap\n", + (params->flags & IB_NOWRITE) ? "Not w" : "W"); + } + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize, + startblock * VAX_BOOT_BLOCK_BLOCKSIZE); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if ((size_t)rv != bootstrapsize) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } + + if (params->flags & IB_VERBOSE) + printf("Writing boot block\n"); + rv = pwrite(params->fsfd, &bb, sizeof(bb), VAX_BOOT_BLOCK_OFFSET); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if (rv != sizeof(bb)) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } else { + retval = 1; + } + + done: + if (bootstrapbuf) + free(bootstrapbuf); + return (retval); +} + +static int +load_bootstrap(ib_params *params, char **data, + uint32_t *loadaddr, uint32_t *execaddr, size_t *len) +{ + ssize_t cc; + size_t buflen; + + buflen = 512 * (VAX_BOOT_SIZE + 1); + *data = malloc(buflen); + if (*data == NULL) { + warn("Allocating %lu bytes", (unsigned long) buflen); + return (0); + } + + cc = pread(params->s1fd, *data, buflen, 0); + if (cc <= 0) { + warn("Reading `%s'", params->stage1); + return (0); + } + if (cc > 512 * VAX_BOOT_SIZE) { + warnx("`%s': too large", params->stage1); + return (0); + } + + *len = roundup(cc, VAX_BOOT_BLOCK_BLOCKSIZE); + *loadaddr = VAX_BOOT_LOAD; + *execaddr = VAX_BOOT_ENTRY; + return (1); +} diff --git a/usr.sbin/installboot/arch/x68k.c b/usr.sbin/installboot/arch/x68k.c new file mode 100644 index 000000000..ee78cf7ec --- /dev/null +++ b/usr.sbin/installboot/arch/x68k.c @@ -0,0 +1,181 @@ +/* $NetBSD: x68k.c,v 1.4 2008/04/28 20:24:16 martin Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: x68k.c,v 1.4 2008/04/28 20:24:16 martin Exp $"); +#endif /* !__lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +#define X68K_LABELOFFSET 64 +#define X68K_LABELSIZE 404 /* reserve 16 partitions */ + +static int x68k_clearheader(ib_params *, struct bbinfo_params *, uint8_t *); + +static int x68k_clearboot(ib_params *); +static int x68k_setboot(ib_params *); + +struct ib_mach ib_mach_x68k = + { "x68k", x68k_setboot, x68k_clearboot, no_editboot, + IB_STAGE1START | IB_STAGE2START }; + +static struct bbinfo_params bbparams = { + X68K_BBINFO_MAGIC, + X68K_BOOT_BLOCK_OFFSET, + X68K_BOOT_BLOCK_BLOCKSIZE, + X68K_BOOT_BLOCK_MAX_SIZE, + X68K_LABELOFFSET + X68K_LABELSIZE, /* XXX */ + BBINFO_BIG_ENDIAN, +}; + +static int +x68k_clearboot(ib_params *params) +{ + + assert(params != NULL); + + if (params->flags & IB_STAGE1START) { + warnx("`-b bno' is not supported for %s", + params->machine->name); + return 0; + } + return shared_bbinfo_clearboot(params, &bbparams, x68k_clearheader); +} + +static int +x68k_clearheader(ib_params *params, struct bbinfo_params *bb_params, + uint8_t *bb) +{ + + assert(params != NULL); + assert(bb_params != NULL); + assert(bb != NULL); + + memset(bb, 0, X68K_LABELOFFSET); + return 1; +} + +static int +x68k_setboot(ib_params *params) +{ + struct stat bootstrapsb; + char bb[X68K_BOOT_BLOCK_MAX_SIZE]; + char label[X68K_LABELSIZE]; + uint32_t s1start; + int retval; + ssize_t rv; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + + retval = 0; + + if (params->flags & IB_STAGE1START) + s1start = params->s1start; + else + s1start = X68K_BOOT_BLOCK_OFFSET / + X68K_BOOT_BLOCK_BLOCKSIZE; + + /* read disklabel on the target disk */ + rv = pread(params->fsfd, label, sizeof label, + s1start * X68K_BOOT_BLOCK_BLOCKSIZE + X68K_LABELOFFSET); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + goto done; + } else if (rv != sizeof label) { + warnx("Reading `%s': short read", params->filesystem); + goto done; + } + + if (fstat(params->s1fd, &bootstrapsb) == -1) { + warn("Examining `%s'", params->stage1); + goto done; + } + if (!S_ISREG(bootstrapsb.st_mode)) { + warnx("`%s' must be a regular file", params->stage1); + goto done; + } + + /* read boot loader */ + memset(&bb, 0, sizeof bb); + rv = read(params->s1fd, &bb, sizeof bb); + if (rv == -1) { + warn("Reading `%s'", params->stage1); + goto done; + } + /* then, overwrite disklabel */ + memcpy(&bb[X68K_LABELOFFSET], &label, sizeof label); + + if (params->flags & IB_VERBOSE) { + printf("Bootstrap start sector: %#x\n", s1start); + printf("Bootstrap byte count: %#x\n", (unsigned)rv); + printf("%sriting bootstrap\n", + (params->flags & IB_NOWRITE) ? "Not w" : "W"); + } + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + /* write boot loader and disklabel into the target disk */ + rv = pwrite(params->fsfd, &bb, X68K_BOOT_BLOCK_MAX_SIZE, + s1start * X68K_BOOT_BLOCK_BLOCKSIZE); + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if (rv != X68K_BOOT_BLOCK_MAX_SIZE) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } else + retval = 1; + + done: + return (retval); +} diff --git a/usr.sbin/installboot/bbinfo.c b/usr.sbin/installboot/bbinfo.c new file mode 100644 index 000000000..a0bbf5694 --- /dev/null +++ b/usr.sbin/installboot/bbinfo.c @@ -0,0 +1,330 @@ +/* $NetBSD: bbinfo.c,v 1.14 2009/04/05 11:55:39 lukem Exp $ */ + +/*- + * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Fredette, Paul Kranenburg, and Luke Mewburn. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: bbinfo.c,v 1.14 2009/04/05 11:55:39 lukem Exp $"); +#endif /* !__lint */ + +#include +#ifndef HAVE_NBTOOL_CONFIG_H +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +int +shared_bbinfo_clearboot(ib_params *params, struct bbinfo_params *bbparams, + int (*callback)(ib_params *, struct bbinfo_params *, uint8_t *)) +{ + uint8_t *bb; + ssize_t rv; + int retval; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(bbparams != NULL); + assert((strlen(bbparams->magic) + 1) == 32); + + retval = 0; + if ((bb = malloc(bbparams->maxsize)) == NULL) { + warn("Allocating %lu bytes for bbinfo", + (unsigned long) bbparams->maxsize); + goto done; + } + + /* First check that it _could_ exist here */ + rv = pread(params->fsfd, bb, bbparams->maxsize, bbparams->offset); + if (rv == -1) { + warn("Reading `%s'", params->filesystem); + goto done; + } else if ((uint32_t)rv != bbparams->maxsize) { + warnx("Reading `%s': short read", params->filesystem); + goto done; + } + + /* Now clear out (past the header offset) */ + memset(bb + bbparams->headeroffset, 0, + bbparams->maxsize - bbparams->headeroffset); + if (callback != NULL && ! (*callback)(params, bbparams, bb)) + goto done; + + if (params->flags & IB_VERBOSE) + printf("%slearing boot block\n", + (params->flags & IB_NOWRITE) ? "Not c" : "C"); + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + rv = pwrite(params->fsfd, bb, bbparams->maxsize, bbparams->offset); +#ifdef DIOCWLABEL + if (rv == -1 && errno == EROFS) { + /* + * The first sector might be protected by + * bounds_check_with_label(9) + */ + int enable; + + enable = 1; + rv = ioctl(params->fsfd, DIOCWLABEL, &enable); + if (rv != 0) { + warn("Cannot enable writes to the label sector"); + goto done; + } + + rv = pwrite(params->fsfd, bb, bbparams->maxsize, + bbparams->offset); + + /* Reset write-protect. */ + enable = 0; + (void)ioctl(params->fsfd, DIOCWLABEL, &enable); + } +#endif + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if ((uint32_t)rv != bbparams->maxsize) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } else + retval = 1; + + done: + if (bb != NULL) + free(bb); + return (retval); +} + +int +shared_bbinfo_setboot(ib_params *params, struct bbinfo_params *bbparams, + int (*callback)(ib_params *, struct bbinfo_params *, uint8_t *)) +{ + uint8_t *bb; + int retval; + ssize_t rv; + size_t bbi; + struct shared_bbinfo *bbinfop; /* bbinfo in prototype image */ + uint32_t maxblk, nblk, blk_i; + ib_block *blocks; + + assert(params != NULL); + assert(params->fsfd != -1); + assert(params->filesystem != NULL); + assert(params->fstype != NULL); + assert(params->s1fd != -1); + assert(params->stage1 != NULL); + assert(bbparams != NULL); + assert((strlen(bbparams->magic) + 1) == 32); + + bbinfop = NULL; /* XXXGCC -Wuninitialized [sparc64] */ + retval = 0; + blocks = NULL; + if ((bb = malloc(bbparams->maxsize)) == NULL) { + warn("Allocating %lu bytes for bbinfo", + (unsigned long) bbparams->maxsize); + goto done; + } + + if (params->stage2 == NULL) { + warnx("Name of secondary bootstrap not provided"); + goto done; + } + + if (params->s1stat.st_size > + bbparams->maxsize - bbparams->headeroffset) { + warnx("`%s' cannot be larger than %lu bytes", + params->stage1, (unsigned long)(bbparams->maxsize - + bbparams->headeroffset)); + goto done; + } + + memset(bb, 0, bbparams->maxsize); + rv = read(params->s1fd, bb + bbparams->headeroffset, + bbparams->maxsize - bbparams->headeroffset); + if (rv == -1) { + warn("Reading `%s'", params->stage1); + goto done; + } + + /* + * Quick sanity check that the bootstrap given + * is *not* an ELF executable. + */ + if (memcmp(bb + bbparams->headeroffset + 1, "ELF", strlen("ELF")) + == 0) { + warnx("`%s' is an ELF executable; need raw binary", + params->stage1); + goto done; + } + +#define HOSTTOTARGET32(x) ((bbparams->endian == BBINFO_LITTLE_ENDIAN) \ + ? (uint32_t)htole32((x)) : (uint32_t)htobe32((x))) +#define TARGET32TOHOST(x) ((bbparams->endian == BBINFO_LITTLE_ENDIAN) \ + ? (uint32_t)le32toh((x)) : (uint32_t)be32toh((x))) + + /* Look for the bbinfo structure. */ + bbinfop = NULL; + for (bbi = 0; bbi < bbparams->maxsize; bbi += sizeof(uint32_t)) { + bbinfop = (void *) (bb + bbparams->headeroffset + bbi); + if (memcmp(bbinfop->bbi_magic, bbparams->magic, + sizeof(bbinfop->bbi_magic)) == 0) + break; + } + if (bbi >= bbparams->maxsize) { + warnx("%s bbinfo structure not found in `%s'", + params->machine->name, params->stage1); + goto done; + } + maxblk = TARGET32TOHOST(bbinfop->bbi_block_count); + if (maxblk == 0 || maxblk > (bbparams->maxsize / sizeof(uint32_t))) { + warnx("%s bbinfo structure in `%s' has preposterous size `%u'", + params->machine->name, params->stage1, maxblk); + goto done; + } + + /* Allocate space for our block list. */ + blocks = malloc(sizeof(*blocks) * maxblk); + if (blocks == NULL) { + warn("Allocating %lu bytes", + (unsigned long)sizeof(*blocks) * maxblk); + goto done; + } + + if (S_ISREG(params->fsstat.st_mode)) { + if (fsync(params->fsfd) == -1) + warn("Synchronising file system `%s'", + params->filesystem); + } else { + /* Ensure the secondary bootstrap is on disk. */ + sync(); + } + + /* Collect the blocks for the secondary bootstrap. */ + nblk = maxblk; + if (! params->fstype->findstage2(params, &nblk, blocks)) + goto done; + if (nblk == 0) { + warnx("Secondary bootstrap `%s' is empty", + params->stage2); + goto done; + } + + /* Save those blocks in the primary bootstrap. */ + bbinfop->bbi_block_count = HOSTTOTARGET32(nblk); + bbinfop->bbi_block_size = HOSTTOTARGET32(blocks[0].blocksize); + for (blk_i = 0; blk_i < nblk; blk_i++) { + bbinfop->bbi_block_table[blk_i] = + HOSTTOTARGET32(blocks[blk_i].block); + if (blocks[blk_i].blocksize < blocks[0].blocksize && + blk_i + 1 != nblk) { + warnx("Secondary bootstrap `%s' blocks do not have " + "a uniform size", params->stage2); + goto done; + } + } + if (callback != NULL && ! (*callback)(params, bbparams, bb)) + goto done; + + if (params->flags & IB_VERBOSE) { + printf("Bootstrap start sector: %u\n", + bbparams->offset / bbparams->blocksize); + printf("Bootstrap byte count: %u\n", (unsigned)rv); + printf("Bootstrap block table: " + "%u entries of %u bytes available, %u used:", + maxblk, blocks[0].blocksize, nblk); + for (blk_i = 0; blk_i < nblk; blk_i++) + printf(" %llu", + (unsigned long long)blocks[blk_i].block); + printf("\n%sriting bootstrap\n", + (params->flags & IB_NOWRITE) ? "Not w" : "W"); + } + if (params->flags & IB_NOWRITE) { + retval = 1; + goto done; + } + + rv = pwrite(params->fsfd, bb, bbparams->maxsize, bbparams->offset); +#ifdef DIOCWLABEL + if (rv == -1 && errno == EROFS) { + /* + * The first sector might be protected by + * bounds_check_with_label(9) + */ + int enable; + + enable = 1; + rv = ioctl(params->fsfd, DIOCWLABEL, &enable); + if (rv != 0) { + warn("Cannot enable writes to the label sector"); + goto done; + } + + rv = pwrite(params->fsfd, bb, bbparams->maxsize, + bbparams->offset); + + /* Reset write-protect. */ + enable = 0; + (void)ioctl(params->fsfd, DIOCWLABEL, &enable); + } +#endif + if (rv == -1) { + warn("Writing `%s'", params->filesystem); + goto done; + } else if ((uint32_t)rv != bbparams->maxsize) { + warnx("Writing `%s': short write", params->filesystem); + goto done; + } else { + retval = 1; + } + + done: + if (blocks != NULL) + free(blocks); + if (bb != NULL) + free(bb); + return (retval); +} diff --git a/usr.sbin/installboot/ext2fs.c b/usr.sbin/installboot/ext2fs.c new file mode 100644 index 000000000..a1c37e3de --- /dev/null +++ b/usr.sbin/installboot/ext2fs.c @@ -0,0 +1,468 @@ +/* $NetBSD: ext2fs.c,v 1.6 2010/01/14 16:27:49 tsutsui Exp $ */ + +/* + * Copyright (c) 1997 Manuel Bouyer. + * + * 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 AUTHOR ``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 AUTHOR 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. + */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Fredette. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: ext2fs.c,v 1.6 2010/01/14 16:27:49 tsutsui Exp $"); +#endif /* !__lint */ + +#include + +#if !HAVE_NBTOOL_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +#include +#include +#include + +static int ext2fs_read_disk_block(ib_params *, uint64_t, int, uint8_t []); +static int ext2fs_read_sblock(ib_params *, struct m_ext2fs *fs); +static int ext2fs_read_gdblock(ib_params *, struct m_ext2fs *fs); +static int ext2fs_find_disk_blocks(ib_params *, ino_t, + int (*)(ib_params *, void *, uint64_t, uint32_t), void *); +static int ext2fs_findstage2_ino(ib_params *, void *, uint64_t, uint32_t); +static int ext2fs_findstage2_blocks(ib_params *, void *, uint64_t, + uint32_t); + + +/* This reads a disk block from the file system. */ +/* XXX: should be shared with ffs.c? */ +static int +ext2fs_read_disk_block(ib_params *params, uint64_t blkno, int size, + uint8_t blk[]) +{ + int rv; + + assert(params != NULL); + assert(params->filesystem != NULL); + assert(params->fsfd != -1); + assert(size > 0); + assert(blk != NULL); + + rv = pread(params->fsfd, blk, size, blkno * params->sectorsize); + if (rv == -1) { + warn("Reading block %llu in `%s'", + (unsigned long long)blkno, params->filesystem); + return 0; + } else if (rv != size) { + warnx("Reading block %llu in `%s': short read", + (unsigned long long)blkno, params->filesystem); + return 0; + } + + return 1; +} + +static int +ext2fs_read_sblock(ib_params *params, struct m_ext2fs *fs) +{ + uint8_t sbbuf[SBSIZE]; + + if (ext2fs_read_disk_block(params, SBOFF / params->sectorsize, SBSIZE, + sbbuf) == 0) + + e2fs_sbload((void *)sbbuf, &fs->e2fs); + + if (fs->e2fs.e2fs_magic != E2FS_MAGIC) + return 0; + + if (fs->e2fs.e2fs_rev > E2FS_REV1 || + (fs->e2fs.e2fs_rev == E2FS_REV1 && + (fs->e2fs.e2fs_first_ino != EXT2_FIRSTINO || + fs->e2fs.e2fs_inode_size != EXT2_DINODE_SIZE || + (fs->e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) != 0))) + return 0; + + fs->e2fs_ncg = + howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, + fs->e2fs.e2fs_bpg); + /* XXX assume hw bsize = 512 */ + fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1; + fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize; + fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; + fs->e2fs_qbmask = fs->e2fs_bsize - 1; + fs->e2fs_bmask = ~fs->e2fs_qbmask; + fs->e2fs_ngdb = + howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd)); + fs->e2fs_ipb = fs->e2fs_bsize / EXT2_DINODE_SIZE; + fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb; + + return 1; +} + +static int +ext2fs_read_gdblock(ib_params *params, struct m_ext2fs *fs) +{ + uint8_t gdbuf[MAXBSIZE]; + uint32_t gdpb; + int i; + + gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd); + + for (i = 0; i < fs->e2fs_ngdb; i++) { + if (ext2fs_read_disk_block(params, fsbtodb(fs, + fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), + SBSIZE, gdbuf) == 0) + return 0; + + e2fs_cgload((struct ext2_gd *)gdbuf, &fs->e2fs_gd[gdpb * i], + (i == (fs->e2fs_ngdb - 1)) ? + (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd): + fs->e2fs_bsize); + } + + return 1; +} + +/* + * This iterates over the data blocks belonging to an inode, + * making a callback each iteration with the disk block number + * and the size. + */ +static int +ext2fs_find_disk_blocks(ib_params *params, ino_t ino, + int (*callback)(ib_params *, void *, uint64_t, uint32_t), + void *state) +{ + uint8_t sbbuf[sizeof(struct m_ext2fs)]; + struct m_ext2fs *fs; + uint8_t inodebuf[MAXBSIZE]; + struct ext2fs_dinode inode_store, *inode; + int level_i; + int32_t blk, lblk, nblk; + int rv; +#define LEVELS 4 + struct { + uint32_t *blknums; + unsigned long blkcount; + uint8_t diskbuf[MAXBSIZE]; + } level[LEVELS]; + + assert(params != NULL); + assert(params->fstype != NULL); + assert(callback != NULL); + assert(state != NULL); + + /* Read the superblock. */ + fs = (void *)sbbuf; + if (ext2fs_read_sblock(params, fs) == 0) + return 0; + + fs->e2fs_gd = malloc(sizeof(struct ext2_gd) * fs->e2fs_ncg); + if (fs->e2fs_gd == NULL) { + warnx("Can't allocate memofy for group descriptors"); + return 0; + } + + if (ext2fs_read_gdblock(params, fs) == 0) { + warnx("Can't read group descriptors"); + return 0; + } + + if (fs->e2fs_ipb <= 0) { + warnx("Bad ipb %d in superblock in `%s'", + fs->e2fs_ipb, params->filesystem); + return 0; + } + + /* Read the inode. */ + if (ext2fs_read_disk_block(params, + fsbtodb(fs, ino_to_fsba(fs, ino)) + params->fstype->offset, + fs->e2fs_bsize, inodebuf)) + return 0; + inode = (void *)inodebuf; + e2fs_iload(&inode[ino_to_fsbo(fs, ino)], &inode_store); + inode = &inode_store; + + /* Get the block count and initialize for our block walk. */ + nblk = howmany(inode->e2di_size, fs->e2fs_bsize); + lblk = 0; + level_i = 0; + level[0].blknums = &inode->e2di_blocks[0]; + level[0].blkcount = NDADDR; + level[1].blknums = &inode->e2di_blocks[NDADDR + 0]; + level[1].blkcount = 1; + level[2].blknums = &inode->e2di_blocks[NDADDR + 1]; + level[2].blkcount = 1; + level[3].blknums = &inode->e2di_blocks[NDADDR + 2]; + level[3].blkcount = 1; + + /* Walk the data blocks. */ + while (nblk > 0) { + + /* + * If there are no more blocks at this indirection + * level, move up one indirection level and loop. + */ + if (level[level_i].blkcount == 0) { + if (++level_i == LEVELS) + break; + continue; + } + + /* Get the next block at this level. */ + blk = fs2h32(*(level[level_i].blknums++)); + level[level_i].blkcount--; + +#if 0 + fprintf(stderr, "ino %lu blk %lu level %d\n", ino, blk, + level_i); +#endif + + /* + * If we're not at the direct level, descend one + * level, read in that level's new block list, + * and loop. + */ + if (level_i > 0) { + level_i--; + if (blk == 0) + memset(level[level_i].diskbuf, 0, MAXBSIZE); + else if (ext2fs_read_disk_block(params, + fsbtodb(fs, blk) + params->fstype->offset, + fs->e2fs_bsize, level[level_i].diskbuf) == 0) + return 0; + /* XXX ondisk32 */ + level[level_i].blknums = + (uint32_t *)level[level_i].diskbuf; + level[level_i].blkcount = NINDIR(fs); + continue; + } + + /* blk is the next direct level block. */ +#if 0 + fprintf(stderr, "ino %lu db %lu blksize %lu\n", ino, + fsbtodb(fs, blk), sblksize(fs, inode->di_size, lblk)); +#endif + rv = (*callback)(params, state, + fsbtodb(fs, blk) + params->fstype->offset, fs->e2fs_bsize); + lblk++; + nblk--; + if (rv != 1) + return rv; + } + + if (nblk != 0) { + warnx("Inode %llu in `%s' ran out of blocks?", + (unsigned long long)ino, params->filesystem); + return 0; + } + + return 1; +} + +/* + * This callback reads a block of the root directory, + * searches for an entry for the secondary bootstrap, + * and saves the inode number if one is found. + */ +static int +ext2fs_findstage2_ino(ib_params *params, void *_ino, + uint64_t blk, uint32_t blksize) +{ + uint8_t dirbuf[MAXBSIZE]; + struct ext2fs_direct *de, *ede; + uint32_t ino; + + assert(params != NULL); + assert(params->fstype != NULL); + assert(params->stage2 != NULL); + assert(_ino != NULL); + + /* Skip directory holes. */ + if (blk == 0) + return 1; + + /* Read the directory block. */ + if (ext2fs_read_disk_block(params, blk, blksize, dirbuf) == 0) + return 0; + + /* Loop over the directory entries. */ + de = (struct ext2fs_direct *)&dirbuf[0]; + ede = (struct ext2fs_direct *)&dirbuf[blksize]; + while (de < ede) { + ino = fs2h32(de->e2d_ino); + if (ino != 0 && strcmp(de->e2d_name, params->stage2) == 0) { + *((uint32_t *)_ino) = ino; + return (2); + } + if (fs2h16(de->e2d_reclen) == 0) + break; + de = (struct ext2fs_direct *)((char *)de + + fs2h16(de->e2d_reclen)); + } + + return 1; +} + +struct findblks_state { + uint32_t maxblk; + uint32_t nblk; + ib_block *blocks; +}; + +/* This callback records the blocks of the secondary bootstrap. */ +static int +ext2fs_findstage2_blocks(ib_params *params, void *_state, + uint64_t blk, uint32_t blksize) +{ + struct findblks_state *state = _state; + + assert(params != NULL); + assert(params->stage2 != NULL); + assert(_state != NULL); + + if (state->nblk == state->maxblk) { + warnx("Secondary bootstrap `%s' has too many blocks (max %d)", + params->stage2, state->maxblk); + return (0); + } + state->blocks[state->nblk].block = blk; + state->blocks[state->nblk].blocksize = blksize; + state->nblk++; + return 1; +} + +/* + * publicly visible functions + */ + +int +ext2fs_match(ib_params *params) +{ + uint8_t sbbuf[sizeof(struct m_ext2fs)]; + struct m_ext2fs *fs; + + assert(params != NULL); + assert(params->fstype != NULL); + + /* Read the superblock. */ + fs = (void *)sbbuf; + if (ext2fs_read_sblock(params, fs) == 0) + return 0; + + params->fstype->needswap = 0; + params->fstype->blocksize = fs->e2fs_bsize; + params->fstype->offset = 0; + + return 1; +} + +int +ext2fs_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks) +{ + int rv; + uint32_t ino; + struct findblks_state state; + + assert(params != NULL); + assert(params->stage2 != NULL); + assert(maxblk != NULL); + assert(blocks != NULL); + + if (params->flags & IB_STAGE2START) + return hardcode_stage2(params, maxblk, blocks); + + /* The secondary bootstrap must be clearly in /. */ + if (params->stage2[0] == '/') + params->stage2++; + if (strchr(params->stage2, '/') != NULL) { + warnx("The secondary bootstrap `%s' must be in /", + params->stage2); + warnx("(Path must be relative to the file system in `%s')", + params->filesystem); + return 0; + } + + /* Get the inode number of the secondary bootstrap. */ + rv = ext2fs_find_disk_blocks(params, EXT2_ROOTINO, + ext2fs_findstage2_ino, &ino); + if (rv != 2) { + warnx("Could not find secondary bootstrap `%s' in `%s'", + params->stage2, params->filesystem); + warnx("(Path must be relative to the file system in `%s')", + params->filesystem); + return 0; + } + + /* Record the disk blocks of the secondary bootstrap. */ + state.maxblk = *maxblk; + state.nblk = 0; + state.blocks = blocks; + rv = ext2fs_find_disk_blocks(params, ino, + ext2fs_findstage2_blocks, &state); + if (rv == 0) + return 0; + + *maxblk = state.nblk; + return 1; +} diff --git a/usr.sbin/installboot/ffs.c b/usr.sbin/installboot/ffs.c new file mode 100644 index 000000000..178eb97a8 --- /dev/null +++ b/usr.sbin/installboot/ffs.c @@ -0,0 +1,592 @@ +/* $NetBSD: ffs.c,v 1.29 2010/01/14 16:27:49 tsutsui Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Fredette. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: ffs.c,v 1.29 2010/01/14 16:27:49 tsutsui Exp $"); +#endif /* !__lint */ + +#include + +#if !HAVE_NBTOOL_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +/* From */ +#define RF_PROTECTED_SECTORS 64L + +#undef DIRBLKSIZ + +#include +#include +#include +#include +#ifndef NO_FFS_SWAP +#include +#else +#define ffs_sb_swap(fs_a, fs_b) +#define ffs_dinode1_swap(inode_a, inode_b) +#define ffs_dinode2_swap(inode_a, inode_b) +#endif + +static int ffs_match_common(ib_params *, off_t); +static int ffs_read_disk_block(ib_params *, uint64_t, int, char []); +static int ffs_find_disk_blocks_ufs1(ib_params *, ino_t, + int (*)(ib_params *, void *, uint64_t, uint32_t), void *); +static int ffs_find_disk_blocks_ufs2(ib_params *, ino_t, + int (*)(ib_params *, void *, uint64_t, uint32_t), void *); +static int ffs_findstage2_ino(ib_params *, void *, uint64_t, uint32_t); +static int ffs_findstage2_blocks(ib_params *, void *, uint64_t, uint32_t); + +static int is_ufs2; + + +/* This reads a disk block from the filesystem. */ +static int +ffs_read_disk_block(ib_params *params, uint64_t blkno, int size, char blk[]) +{ + int rv; + + assert(params != NULL); + assert(params->filesystem != NULL); + assert(params->fsfd != -1); + assert(size > 0); + assert(blk != NULL); + + rv = pread(params->fsfd, blk, size, blkno * params->sectorsize); + if (rv == -1) { + warn("Reading block %llu in `%s'", + (unsigned long long)blkno, params->filesystem); + return (0); + } else if (rv != size) { + warnx("Reading block %llu in `%s': short read", + (unsigned long long)blkno, params->filesystem); + return (0); + } + + return (1); +} + +/* + * This iterates over the data blocks belonging to an inode, + * making a callback each iteration with the disk block number + * and the size. + */ +static int +ffs_find_disk_blocks_ufs1(ib_params *params, ino_t ino, + int (*callback)(ib_params *, void *, uint64_t, uint32_t), + void *state) +{ + char sbbuf[SBLOCKSIZE]; + struct fs *fs; + char inodebuf[MAXBSIZE]; + struct ufs1_dinode *inode; + int level_i; + int32_t blk, lblk, nblk; + int rv; +#define LEVELS 4 + struct { + int32_t *blknums; + unsigned long blkcount; + char diskbuf[MAXBSIZE]; + } level[LEVELS]; + + assert(params != NULL); + assert(params->fstype != NULL); + assert(callback != NULL); + assert(state != NULL); + + /* Read the superblock. */ + if (!ffs_read_disk_block(params, params->fstype->sblockloc, SBLOCKSIZE, + sbbuf)) + return (0); + fs = (struct fs *)sbbuf; +#ifndef NO_FFS_SWAP + if (params->fstype->needswap) + ffs_sb_swap(fs, fs); +#endif + + if (fs->fs_inopb <= 0) { + warnx("Bad inopb %d in superblock in `%s'", + fs->fs_inopb, params->filesystem); + return (0); + } + + /* Read the inode. */ + if (! ffs_read_disk_block(params, + fsbtodb(fs, ino_to_fsba(fs, ino)) + params->fstype->offset, + fs->fs_bsize, inodebuf)) + return (0); + inode = (struct ufs1_dinode *)inodebuf; + inode += ino_to_fsbo(fs, ino); +#ifndef NO_FFS_SWAP + if (params->fstype->needswap) + ffs_dinode1_swap(inode, inode); +#endif + + /* Get the block count and initialize for our block walk. */ + nblk = howmany(inode->di_size, fs->fs_bsize); + lblk = 0; + level_i = 0; + level[0].blknums = &inode->di_db[0]; + level[0].blkcount = NDADDR; + level[1].blknums = &inode->di_ib[0]; + level[1].blkcount = 1; + level[2].blknums = &inode->di_ib[1]; + level[2].blkcount = 1; + level[3].blknums = &inode->di_ib[2]; + level[3].blkcount = 1; + + /* Walk the data blocks. */ + while (nblk > 0) { + + /* + * If there are no more blocks at this indirection + * level, move up one indirection level and loop. + */ + if (level[level_i].blkcount == 0) { + if (++level_i == LEVELS) + break; + continue; + } + + /* Get the next block at this level. */ + blk = *(level[level_i].blknums++); + level[level_i].blkcount--; + if (params->fstype->needswap) + blk = bswap32(blk); + +#if 0 + fprintf(stderr, "ino %lu blk %lu level %d\n", ino, blk, + level_i); +#endif + + /* + * If we're not at the direct level, descend one + * level, read in that level's new block list, + * and loop. + */ + if (level_i > 0) { + level_i--; + if (blk == 0) + memset(level[level_i].diskbuf, 0, MAXBSIZE); + else if (! ffs_read_disk_block(params, + fsbtodb(fs, blk) + params->fstype->offset, + fs->fs_bsize, level[level_i].diskbuf)) + return (0); + /* XXX ondisk32 */ + level[level_i].blknums = + (int32_t *)level[level_i].diskbuf; + level[level_i].blkcount = NINDIR(fs); + continue; + } + + /* blk is the next direct level block. */ +#if 0 + fprintf(stderr, "ino %lu db %lu blksize %lu\n", ino, + fsbtodb(fs, blk), sblksize(fs, inode->di_size, lblk)); +#endif + rv = (*callback)(params, state, + fsbtodb(fs, blk) + params->fstype->offset, + sblksize(fs, (int64_t)inode->di_size, lblk)); + lblk++; + nblk--; + if (rv != 1) + return (rv); + } + + if (nblk != 0) { + warnx("Inode %llu in `%s' ran out of blocks?", + (unsigned long long)ino, params->filesystem); + return (0); + } + + return (1); +} + +/* + * This iterates over the data blocks belonging to an inode, + * making a callback each iteration with the disk block number + * and the size. + */ +static int +ffs_find_disk_blocks_ufs2(ib_params *params, ino_t ino, + int (*callback)(ib_params *, void *, uint64_t, uint32_t), + void *state) +{ + char sbbuf[SBLOCKSIZE]; + struct fs *fs; + char inodebuf[MAXBSIZE]; + struct ufs2_dinode *inode; + int level_i; + int64_t blk, lblk, nblk; + int rv; +#define LEVELS 4 + struct { + int64_t *blknums; + unsigned long blkcount; + char diskbuf[MAXBSIZE]; + } level[LEVELS]; + + assert(params != NULL); + assert(params->fstype != NULL); + assert(callback != NULL); + assert(state != NULL); + + /* Read the superblock. */ + if (!ffs_read_disk_block(params, params->fstype->sblockloc, SBLOCKSIZE, + sbbuf)) + return (0); + fs = (struct fs *)sbbuf; +#ifndef NO_FFS_SWAP + if (params->fstype->needswap) + ffs_sb_swap(fs, fs); +#endif + + if (fs->fs_inopb <= 0) { + warnx("Bad inopb %d in superblock in `%s'", + fs->fs_inopb, params->filesystem); + return (0); + } + + /* Read the inode. */ + if (! ffs_read_disk_block(params, + fsbtodb(fs, ino_to_fsba(fs, ino)) + params->fstype->offset, + fs->fs_bsize, inodebuf)) + return (0); + inode = (struct ufs2_dinode *)inodebuf; + inode += ino_to_fsbo(fs, ino); +#ifndef NO_FFS_SWAP + if (params->fstype->needswap) + ffs_dinode2_swap(inode, inode); +#endif + + /* Get the block count and initialize for our block walk. */ + nblk = howmany(inode->di_size, fs->fs_bsize); + lblk = 0; + level_i = 0; + level[0].blknums = &inode->di_db[0]; + level[0].blkcount = NDADDR; + level[1].blknums = &inode->di_ib[0]; + level[1].blkcount = 1; + level[2].blknums = &inode->di_ib[1]; + level[2].blkcount = 1; + level[3].blknums = &inode->di_ib[2]; + level[3].blkcount = 1; + + /* Walk the data blocks. */ + while (nblk > 0) { + + /* + * If there are no more blocks at this indirection + * level, move up one indirection level and loop. + */ + if (level[level_i].blkcount == 0) { + if (++level_i == LEVELS) + break; + continue; + } + + /* Get the next block at this level. */ + blk = *(level[level_i].blknums++); + level[level_i].blkcount--; + if (params->fstype->needswap) + blk = bswap64(blk); + +#if 0 + fprintf(stderr, "ino %lu blk %llu level %d\n", ino, + (unsigned long long)blk, level_i); +#endif + + /* + * If we're not at the direct level, descend one + * level, read in that level's new block list, + * and loop. + */ + if (level_i > 0) { + level_i--; + if (blk == 0) + memset(level[level_i].diskbuf, 0, MAXBSIZE); + else if (! ffs_read_disk_block(params, + fsbtodb(fs, blk) + params->fstype->offset, + fs->fs_bsize, level[level_i].diskbuf)) + return (0); + level[level_i].blknums = + (int64_t *)level[level_i].diskbuf; + level[level_i].blkcount = NINDIR(fs); + continue; + } + + /* blk is the next direct level block. */ +#if 0 + fprintf(stderr, "ino %lu db %llu blksize %lu\n", ino, + fsbtodb(fs, blk), sblksize(fs, inode->di_size, lblk)); +#endif + rv = (*callback)(params, state, + fsbtodb(fs, blk) + params->fstype->offset, + sblksize(fs, (int64_t)inode->di_size, lblk)); + lblk++; + nblk--; + if (rv != 1) + return (rv); + } + + if (nblk != 0) { + warnx("Inode %llu in `%s' ran out of blocks?", + (unsigned long long)ino, params->filesystem); + return (0); + } + + return (1); +} + +/* + * This callback reads a block of the root directory, + * searches for an entry for the secondary bootstrap, + * and saves the inode number if one is found. + */ +static int +ffs_findstage2_ino(ib_params *params, void *_ino, + uint64_t blk, uint32_t blksize) +{ + char dirbuf[MAXBSIZE]; + struct direct *de, *ede; + uint32_t ino; + + assert(params != NULL); + assert(params->fstype != NULL); + assert(params->stage2 != NULL); + assert(_ino != NULL); + + /* Skip directory holes. */ + if (blk == 0) + return (1); + + /* Read the directory block. */ + if (! ffs_read_disk_block(params, blk, blksize, dirbuf)) + return (0); + + /* Loop over the directory entries. */ + de = (struct direct *)&dirbuf[0]; + ede = (struct direct *)&dirbuf[blksize]; + while (de < ede) { + ino = de->d_fileno; + if (params->fstype->needswap) { + ino = bswap32(ino); + de->d_reclen = bswap16(de->d_reclen); + } + if (ino != 0 && strcmp(de->d_name, params->stage2) == 0) { + *((uint32_t *)_ino) = ino; + return (2); + } + if (de->d_reclen == 0) + break; + de = (struct direct *)((char *)de + de->d_reclen); + } + + return (1); +} + +struct findblks_state { + uint32_t maxblk; + uint32_t nblk; + ib_block *blocks; +}; + +/* This callback records the blocks of the secondary bootstrap. */ +static int +ffs_findstage2_blocks(ib_params *params, void *_state, + uint64_t blk, uint32_t blksize) +{ + struct findblks_state *state = _state; + + assert(params != NULL); + assert(params->stage2 != NULL); + assert(_state != NULL); + + if (state->nblk == state->maxblk) { + warnx("Secondary bootstrap `%s' has too many blocks (max %d)", + params->stage2, state->maxblk); + return (0); + } + state->blocks[state->nblk].block = blk; + state->blocks[state->nblk].blocksize = blksize; + state->nblk++; + return (1); +} + +/* + * publicly visible functions + */ + +static off_t sblock_try[] = SBLOCKSEARCH; + +int +ffs_match(ib_params *params) +{ + return ffs_match_common(params, (off_t) 0); +} + +int +raid_match(ib_params *params) +{ + /* XXX Assumes 512 bytes / sector */ + if (params->sectorsize != 512) { + warnx("Media is %d bytes/sector." + " RAID is only supported on 512 bytes/sector media.", + params->sectorsize); + return 0; + } + return ffs_match_common(params, (off_t) RF_PROTECTED_SECTORS); +} + +int +ffs_match_common(ib_params *params, off_t offset) +{ + char sbbuf[SBLOCKSIZE]; + struct fs *fs; + int i; + off_t loc; + + assert(params != NULL); + assert(params->fstype != NULL); + + fs = (struct fs *)sbbuf; + for (i = 0; sblock_try[i] != -1; i++) { + loc = sblock_try[i] / params->sectorsize + offset; + if (!ffs_read_disk_block(params, loc, SBLOCKSIZE, sbbuf)) + continue; + switch (fs->fs_magic) { + case FS_UFS2_MAGIC: + is_ufs2 = 1; + /* FALLTHROUGH */ + case FS_UFS1_MAGIC: + params->fstype->needswap = 0; + params->fstype->blocksize = fs->fs_bsize; + params->fstype->sblockloc = loc; + params->fstype->offset = offset; + break; +#ifndef FFS_NO_SWAP + case FS_UFS2_MAGIC_SWAPPED: + is_ufs2 = 1; + /* FALLTHROUGH */ + case FS_UFS1_MAGIC_SWAPPED: + params->fstype->needswap = 1; + params->fstype->blocksize = bswap32(fs->fs_bsize); + params->fstype->sblockloc = loc; + params->fstype->offset = offset; + break; +#endif + default: + continue; + } + if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2) + continue; + return 1; + } + + return (0); +} + +int +ffs_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks) +{ + int rv; + uint32_t ino; + struct findblks_state state; + + assert(params != NULL); + assert(params->stage2 != NULL); + assert(maxblk != NULL); + assert(blocks != NULL); + + if (params->flags & IB_STAGE2START) + return (hardcode_stage2(params, maxblk, blocks)); + + /* The secondary bootstrap must be clearly in /. */ + if (params->stage2[0] == '/') + params->stage2++; + if (strchr(params->stage2, '/') != NULL) { + warnx("The secondary bootstrap `%s' must be in /", + params->stage2); + warnx("(Path must be relative to the file system in `%s')", + params->filesystem); + return (0); + } + + /* Get the inode number of the secondary bootstrap. */ + if (is_ufs2) + rv = ffs_find_disk_blocks_ufs2(params, ROOTINO, + ffs_findstage2_ino, &ino); + else + rv = ffs_find_disk_blocks_ufs1(params, ROOTINO, + ffs_findstage2_ino, &ino); + if (rv != 2) { + warnx("Could not find secondary bootstrap `%s' in `%s'", + params->stage2, params->filesystem); + warnx("(Path must be relative to the file system in `%s')", + params->filesystem); + return (0); + } + + /* Record the disk blocks of the secondary bootstrap. */ + state.maxblk = *maxblk; + state.nblk = 0; + state.blocks = blocks; + if (is_ufs2) + rv = ffs_find_disk_blocks_ufs2(params, ino, + ffs_findstage2_blocks, &state); + else + rv = ffs_find_disk_blocks_ufs1(params, ino, + ffs_findstage2_blocks, &state); + if (! rv) { + return (0); + } + + *maxblk = state.nblk; + return (1); +} diff --git a/usr.sbin/installboot/fstypes.c b/usr.sbin/installboot/fstypes.c new file mode 100644 index 000000000..1b77f974f --- /dev/null +++ b/usr.sbin/installboot/fstypes.c @@ -0,0 +1,133 @@ +/* $NetBSD: fstypes.c,v 1.13 2010/01/14 16:27:49 tsutsui Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Fredette and Luke Mewburn. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: fstypes.c,v 1.13 2010/01/14 16:27:49 tsutsui Exp $"); +#endif /* !__lint */ + +#include + +#include +#include +#include + +#include "installboot.h" + +struct ib_fs fstypes[] = { +#ifndef NO_STAGE2 + { .name = "ffs", .match = ffs_match, .findstage2 = ffs_findstage2 }, + { .name = "raid", .match = raid_match, .findstage2 = ffs_findstage2 }, + { .name = "raw", .match = raw_match, .findstage2 = raw_findstage2 }, +#endif + { .name = NULL, } +}; + +#ifndef NO_STAGE2 +int +hardcode_stage2(ib_params *params, uint32_t *maxblk, ib_block *blocks) +{ + struct stat s2sb; + uint32_t nblk, i; + + assert(params != NULL); + assert(params->stage2 != NULL); + assert(maxblk != NULL); + assert(blocks != NULL); + assert((params->flags & IB_STAGE2START) != 0); + assert(params->fstype != NULL); + assert(params->fstype->blocksize != 0); + + if (stat(params->stage2, &s2sb) == -1) { + warn("Examining `%s'", params->stage2); + return (0); + } + if (!S_ISREG(s2sb.st_mode)) { + warnx("`%s' must be a regular file", params->stage2); + return (0); + } + + nblk = s2sb.st_size / params->fstype->blocksize; + if (s2sb.st_size % params->fstype->blocksize != 0) + nblk++; +#if 0 + fprintf(stderr, "for %s got size %lld blksize %u blocks %u\n", + params->stage2, s2sb.st_size, params->fstype->blocksize, nblk); +#endif + if (nblk > *maxblk) { + warnx("Secondary bootstrap `%s' has too many blocks " + "(calculated %u, maximum %u)", + params->stage2, nblk, *maxblk); + return (0); + } + + for (i = 0; i < nblk; i++) { + blocks[i].block = params->s2start + + i * (params->fstype->blocksize / params->sectorsize); + blocks[i].blocksize = params->fstype->blocksize; + } + *maxblk = nblk; + + return (1); +} + + +int +raw_match(ib_params *params) +{ + + assert(params != NULL); + assert(params->fstype != NULL); + + params->fstype->blocksize = 8192; // XXX: hardcode + return (1); /* can always write to a "raw" file system */ +} + +int +raw_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks) +{ + + assert(params != NULL); + assert(params->stage2 != NULL); + assert(maxblk != NULL); + assert(blocks != NULL); + + if ((params->flags & IB_STAGE2START) == 0) { + warnx("Need `-B bno' for raw file systems"); + return (0); + } + return (hardcode_stage2(params, maxblk, blocks)); +} +#endif diff --git a/usr.sbin/installboot/installboot.8 b/usr.sbin/installboot/installboot.8 new file mode 100644 index 000000000..cab63aadd --- /dev/null +++ b/usr.sbin/installboot/installboot.8 @@ -0,0 +1,895 @@ +.\" $NetBSD: installboot.8,v 1.79 2011/11/03 20:09:18 martin Exp $ +.\" +.\" Copyright (c) 2002-2009 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Luke Mewburn of Wasabi Systems. +.\" +.\" 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. +.\" +.Dd August 3, 2011 +.Dt INSTALLBOOT 8 +.Os +.Sh NAME +.Nm installboot +.Nd install disk bootstrap software +. +.Sh SYNOPSIS +.Nm +.Op Fl fnv +.Op Fl B Ar s2bno +.Op Fl b Ar s1bno +.Op Fl m Ar machine +.Op Fl o Ar options +.Op Fl t Ar fstype +.Ar filesystem +.Ar primary +.Op Ar secondary +.Nm +.Fl c +.Op Fl fnv +.Op Fl m Ar machine +.Op Fl o Ar options +.Op Fl t Ar fstype +.Ar filesystem +.Nm +.Fl e +.Op Fl fnv +.Op Fl m Ar machine +.Op Fl o Ar options +.Ar bootstrap +. +.Sh DESCRIPTION +The +.Nm +utility installs and removes +.Nx +disk bootstrap software into a file system. +.Nm +can install +.Ar primary +into +.Ar filesystem , +or disable an existing bootstrap in +.Ar filesystem . +.Pp +On some architectures the options of an existing installed bootstrap, +or those of a bootstrap file can be changed. +Installing a new primary bootstrap will reset those options to default +values. +.Pp +Generally, +.Nx +disk bootstrap software consists of two parts: a +.Dq primary +bootstrap program usually written into the disklabel area of the +file system by +.Nm , +and a +.Dq secondary +bootstrap program that usually resides as an ordinary file in the file system. +.Pp +When booting, the primary bootstrap program is loaded and invoked by +the machine's PROM or BIOS. +After receiving control of the system it loads and runs the secondary +bootstrap program, which in turn loads and runs the kernel. +The secondary bootstrap may allow control over various boot parameters +passed to the kernel. +.Pp +Perform the following steps to make a file system bootable: +.Bl -enum +.It +Copy the secondary bootstrap (usually +.Pa /usr/mdec/boot. Ns Sy MACHINE +or +.Pa /usr/mdec/boot ) +to the root directory of the target file system. +.Pp +. +.It +Use +.Nm +to install the primary bootstrap program +(usually +.Pa /usr/mdec/bootxx_ Ns Sy FSTYPE ) +into +.Ar filesystem . +.Pp +The following platforms do not require this step if the primary bootstrap +already exists and the secondary bootstrap file is just being updated: +.Sy alpha , +.Sy amd64 , +.Sy amiga , +.Sy i386 , +.Sy pmax , +.Sy sparc64 , +and +.Sy vax . +.Pp +The following platform does not require the first step since a +single bootstrap file is used. +The single bootstrap is installed like the primary bootstrap on +other platforms: +.Sy next68k . +.Pp +.El +.Pp +The options and arguments recognized by +.Nm +are as follows: +. +.Bl -tag -width "optionsxxx" +. +.It Fl B Ar s2bno +When hard-coding the blocks of +.Ar secondary +into +.Ar primary , +start from block +.Ar s2bno +instead of trying to determine the block numbers occupied by +.Ar secondary +by examining +.Ar filesystem . +If this option is supplied, +.Ar secondary +should refer to an actual secondary bootstrap (rather than the +file name of the one present in +.Ar filesystem ) +so that its size can be determined. +. +.It Fl b Ar s1bno +Install +.Ar primary +at block number +.Ar s1bno +instead of the default location for the machine and file system type. +.Sy [ alpha , +.Sy pmax , +.Sy vax ] +. +.It Fl c +Clear (remove) any existing bootstrap instead of installing one. +. +.It Fl e +Edit the options of an existing bootstrap. +This can be use to change the options in bootxx_xxxfs files, +raw disk partitions, and the +.Pa pxeboot_ia32.bin +file. +With +.Fl v +and without +.Fl o , +show the current options. +.Sy [ amd64 , i386 ] +. +.It Fl f +Forces +.Nm +to ignore some errors. +. +.It Fl m Ar machine +Use +.Ar machine +as the target machine type. +The default machine is determined from +.Xr uname 3 +and then +.Ev MACHINE . +The following machines are currently supported by +.Nm : +.Bd -ragged -offset indent +.Sy alpha , +.Sy amd64 , +.Sy amiga , +.Sy ews4800mips , +.Sy hp300 , +.Sy hp700 , +.Sy i386 , +.Sy landisk , +.Sy macppc , +.Sy news68k , +.Sy newsmips , +.Sy next68k , +.Sy pmax , +.Sy sparc , +.Sy sparc64 , +.Sy sun2 , +.Sy sun3 , +.Sy vax , +.Sy x68k +.Ed +. +. +.It Fl n +Do not write to +.Ar filesystem . +. +.It Fl o Ar options +Machine specific +.Nm +options, comma separated. +.Pp +Supported options are (with the machines for they are valid in brackets): +. +.Bl -tag -offset indent -width alphasum +. +.It Sy alphasum +.Sy [ alpha ] +Recalculate and restore the Alpha checksum. +This is the default for +.Nx Ns Tn /alpha . +. +.It Sy append +.Sy [ alpha , +.Sy pmax , +.Sy vax ] +Append +.Ar primary +to the end of +.Ar filesystem , +which must be a regular file in this case. +. +.It Sy bootconf +.Sy [ amd64 , +.Sy i386 ] +(Don't) read a +.Dq boot.cfg +file. +. +.It Sy command=\*[Lt]boot command\*[Gt] +.Sy [ amiga ] +Modify the default boot command line. +. +.It Sy console=\*[Lt]console name\*[Gt] +.Sy [ amd64 , +.Sy i386 ] +Set the console device, \*[Lt]console name\*[Gt] must be one of: +pc, com0, com1, com2, com3, com0kbd, com1kbd, com2kbd or com3kbd. +. +.It Sy ioaddr=\*[Lt]ioaddr\*[Gt] +.Sy [ amd64 , +.Sy i386 ] +Set the IO address to be used for the console serial port. +Defaults to the IO address used by the system BIOS for the specified port. +. +.It Sy keymap=\*[Lt]keymap\*[Gt] +.Sy [ amd64 , +.Sy i386 ] +Set a boot time keyboard translation map. +Each character in \*[Lt]keymap\*[Gt] will be replaced by the one following it. +For example, an argument of +.Dq zyz +would swap the lowercase letters +.Sq y +and +.Sq z . +. +.It Sy modules +.Sy [ amd64 , +.Sy i386 ] +(Don't) load kernel modules. +. +.It Sy password=\*[Lt]password\*[Gt] +.Sy [ amd64 , +.Sy i386 ] +Set the password which must be entered before the boot menu can be accessed. +. +.It Sy resetvideo +.Sy [ amd64 , +.Sy i386 ] +Reset the video before booting. +. +.It Sy speed=\*[Lt]baud rate\*[Gt] +.Sy [ amd64 , +.Sy i386 ] +Set the baud rate for the serial console. +If a value of zero is specified, then the current baud rate (set by the +BIOS) will be used. +. +.It Sy sunsum +.Sy [ alpha , +.Sy pmax , +.Sy vax ] +Recalculate and restore the Sun and +.Nx Ns Tn /sparc +compatible checksum. +.Em Note : +The existing +.Nx Ns Tn /sparc +disklabel should use no more than 4 partitions. +. +.It Sy timeout=\*[Lt]seconds\*[Gt] +.Sy [ amd64 , +.Sy i386 ] +Set the timeout before the automatic boot begins to the given number of seconds. +.El +. +.It Fl t Ar fstype +Use +.Ar fstype +as the type of +.Ar filesystem . +The default operation is to attempt to auto-detect this setting. +The following file system types are currently supported by +.Nm : +. +.Bl -tag -offset indent -width raid +. +.It Sy ffs +.Bx +Fast File System. +. +.It Sy raid +Mirrored RAIDframe File System. +. +.It Sy raw +.Sq Raw +image. +Note: if a platform needs to hard-code the block offset of the secondary +bootstrap, it cannot be searched for on this file system type, and must +be provided with +.Fl B Ar s2bno . +.El +. +.It Fl v +Verbose operation. +. +.It Ar filesystem +The path name of the device or file system image that +.Nm +is to operate on. +It is not necessary for +.Ar filesystem +to be a currently mounted file system. +. +.It Ar primary +The path name of the +.Dq primary +boot block to install. +The path name must refer to a file in a file system that is currently +mounted. +. +.It Ar secondary +The path name of the +.Dq secondary +boot block, relative to the root of +the file system in the device or image specified by the +.Ar filesystem +argument. +Note that this may refer to a file in a file system that is not mounted. +Most systems require +.Ar secondary +to be in the +.Dq root +directory of the file system, so the leading +.Dq Pa / +is not necessary on +.Ar secondary . +.Pp +Only certain combinations of +platform +.Pq Fl m Ar machine +and file system type +.Pq Fl t Ar fstype +require that the name of the secondary bootstrap is +supplied as +.Ar secondary , +so that information such as the disk block numbers occupied +by the secondary bootstrap can be stored in the primary bootstrap. +These are: +.Bl -column "Platform" "File systems" -offset indent +.It Sy "Platform" Ta Sy "File systems" +.It macppc Ta ffs, raw +.It news68k Ta ffs, raw +.It newsmips Ta ffs, raw +.It sparc Ta ffs, raid, raw +.It sun2 Ta ffs, raw +.It sun3 Ta ffs, raw +.El +.El +.Pp +.Nm +exits 0 on success, and \*[Gt]0 if an error occurs. +. +.Sh ENVIRONMENT +.Nm +uses the following environment variables: +. +.Bl -tag -width "MACHINE" +. +.It Ev MACHINE +Default value for +.Ar machine , +overriding the result from +.Xr uname 3 . +. +.El +. +.Sh FILES +Most +.Nx +ports will contain variations of the following files: +.Pp +.Bl -tag -width /usr/mdec/bootxx_ustarfs +. +.It Pa /usr/mdec/bootxx_ Ns Sy FSTYPE +Primary bootstrap for file system type +.Sy FSTYPE . +Installed into the bootstrap area of the file system by +.Nm . +. +.It Pa /usr/mdec/bootxx_fat16 +Primary bootstrap for +.Tn MS-DOS +.Sy FAT16 +file systems. +This differs from +.Nm bootxx_msdos +in that it doesn't require the filesystem to have been initialised with +any +.Ql reserved sectors . +It also uses the information in the +.Ql Boot Parameter Block +to get the media and filesytem properties. +. +.It Pa /usr/mdec/bootxx_ffsv1 +Primary bootstrap for +.Sy FFSv1 +file systems +(the "traditional" +.Nx +file system). +Use +.Xr dumpfs 8 +to confirm the file system format is +.Sy FFSv1 . +. +.It Pa /usr/mdec/bootxx_ffsv2 +Primary bootstrap for +.Sy FFSv2 +file systems. +Use +.Xr dumpfs 8 +to confirm the file system format is +.Sy FFSv2 . +. +.It Pa /usr/mdec/bootxx_lfsv1 +Primary bootstrap for +.Sy LFSv1 +file systems. +. +.It Pa /usr/mdec/bootxx_lfsv2 +Primary bootstrap for +.Sy LFSv2 +file systems +(the default LFS version). +. +.It Pa /usr/mdec/bootxx_msdos +Primary bootstrap for +.Tn MS-DOS +.Sy FAT +file systems. +. +.It Pa /usr/mdec/bootxx_ustarfs +Primary bootstrap for +.Sy TARFS +boot images. +This is used by various install media. +. +.It Pa /usr/mdec/boot. Ns Sy MACHINE +Secondary bootstrap for machine type +.Sy MACHINE . +This should be installed into the file system before +.Nm +is run. +. +.It Pa /usr/mdec/boot +Synonym for +.Pa /usr/mdec/boot. Ns Sy MACHINE +. +.It Pa /boot. Ns Sy MACHINE +Installed copy of secondary bootstrap for machine type +.Sy MACHINE . +. +.It Pa /boot +Installed copy of secondary bootstrap. +Searched for by the primary bootstrap if +.Pa /boot. Ns Sy MACHINE +is not found. +. +.El +. +.Ss Nx Ns Tn /macppc files +. +.Bl -tag -width /usr/mdec/bootxx_ustarfs +. +.It Pa /usr/mdec/bootxx +.Nx Ns Tn /macppc +primary bootstrap. +. +.It Pa /usr/mdec/ofwboot +.Nx Ns Tn /macppc +secondary bootstrap. +. +.It Pa /ofwboot +Installed copy of +.Nx Ns Tn /macppc +secondary bootstrap. +. +.El +. +.Ss Nx Ns Tn /next68k files +. +.Bl -tag -width /usr/mdec/bootxx_ustarfs +. +.It Pa /usr/mdec/boot +.Nx Ns Tn /next68k +bootstrap. +. +.El +. +.Ss Nx Ns Tn /sparc64 files +. +.Bl -tag -width /usr/mdec/bootxx_ustarfs +. +.It Pa /usr/mdec/bootblk +.Nx Ns Tn /sparc64 +primary bootstrap. +. +.It Pa /usr/mdec/ofwboot +.Nx Ns Tn /sparc64 +secondary bootstrap. +. +.It Pa /ofwboot +Installed copy of +.Nx Ns Tn /sparc64 +secondary bootstrap. +. +.El +. +.Sh EXAMPLES +. +.Ss common +Verbosely install the Berkeley Fast File System primary bootstrap on to disk +.Sq sd0 : +.Dl Ic installboot -v /dev/rsd0c /usr/mdec/bootxx_ffs +Note: the +.Dq whole disk +partition (c on some ports, d on others) is used here, since the a partition +probably is already opened (mounted as +.Pa / ) , +so +.Nm +would not be able to access it. +.Pp +Remove the primary bootstrap from disk +.Sq sd1 : +.Dl Ic installboot -c /dev/rsd1c +. +.Ss Nx Ns Tn /amiga +Modify the command line to change the default from "netbsd -ASn2" to +"netbsd -S": +.Dl Ic installboot -m amiga -o command="netbsd -S" /dev/rsd0a /usr/mdec/bootxx_ffs +. +.Ss Nx Ns Tn /ews4800mips +Install the System V Boot File System primary bootstrap on to disk +.Sq sd0 , +with the secondary bootstrap +.Sq Pa /boot +already present in the SysVBFS partition on the disk: +.Dl Ic installboot /dev/rsd0c /usr/mdec/bootxx_bfs +. +.Ss Nx Ns Tn /i386 and Nx Ns Tn /amd64 +Install new boot blocks on an existing mounted root file system on +.Sq wd0 , +setting the timeout to five seconds, after copying a new secondary +bootstrap: +.Dl Ic cp /usr/mdec/boot /boot +.Dl Ic installboot -v -o timeout=5 /dev/rwd0a /usr/mdec/bootxx_ffsv1 +. +.Pp +Create a bootable CD-ROM with an ISO9660 +file system for an i386 system with a serial console: +.Dl Ic mkdir cdrom +.Dl Ic cp sys/arch/i386/compile/mykernel/netbsd cdrom/netbsd +.Dl Ic cp /usr/mdec/boot cdrom/boot +.Dl Ic cp /usr/mdec/bootxx_cd9660 bootxx +.Dl Ic installboot -o console=com0,speed=19200 -m i386 -e bootxx +.Dl Ic makefs -t cd9660 -o 'bootimage=i386;bootxx,no-emul-boot' boot.iso \ + cdrom +. +.Pp +Create a bootable floppy disk with an FFSv1 +file system for a small custom kernel (note: bigger kernels needing +multiple disks are handled with the ustarfs file system): +.Dl Ic newfs -s 1440k /dev/rfd0a +.Bd -ragged -offset indent-two -compact +.Em Note : +Ignore the warnings that +.Xr newfs 8 +displays; it can not write a disklabel, +which is not a problem for a floppy disk. +.Ed +.Dl Ic mount /dev/fd0a /mnt +.Dl Ic cp /usr/mdec/boot /mnt/boot +.Dl Ic gzip -9 \*[Lt] sys/arch/i386/compile/mykernel/netbsd \*[Gt] /mnt/netbsd.gz +.Dl Ic umount /mnt +.Dl Ic installboot -v /dev/rfd0a /usr/mdec/bootxx_ffsv1 +. +.Pp +Create a bootable FAT file system on +.Sq wd1a , +which should have the same offset and size as a FAT primary partition +in the Master Boot Record (MBR): +.Dl Ic newfs_msdos -r 16 /dev/rwd1a +.Bd -ragged -offset indent-two -compact +.Em Notes : +The +.Fl r Ar 16 +is to reserve space for the primary bootstrap. +.Xr newfs_msdos 8 +will display an +.Dq MBR type +such as +.Ql 1 , +.Ql 4 , +or +.Ql 6 ; +the MBR partition type of the appropriate primary partition should be +changed to this value. +.Ed +.Dl Ic mount -t msdos /dev/wd1a /mnt +.Dl Ic cp /usr/mdec/boot /mnt/boot +.Dl Ic cp path/to/kernel /mnt/netbsd +.Dl Ic umount /mnt +.Dl Ic installboot -t raw /dev/rwd1a /usr/mdec/bootxx_msdos +.Pp +Make the existing FAT16 filesystem on +.Sq sd0e +bootable. +This can be used to make USB memory bootable provided it has 512 byte +sectors and that the manufacturer correctly initialised the file system. +.Dl Ic mount -t msdos /dev/sd0e /mnt +.Dl Ic cp /usr/mdec/boot /mnt/boot +.Dl Ic cp path/to/kernel /mnt/netbsd +.Dl Ic umount /mnt +.Dl Ic installboot /dev/rsd0e /usr/mdec/bootxx_fat16 +It may also be necessary to use +.Nm fdisk +to make the device itself bootable. +. +.Pp +Switch the existing installed bootstrap to use a serial console without +reinstalling or altering other options such as timeout. +.Dl Ic installboot -e -o console=com0 /dev/rwd0a +.Ss Nx Ns Tn /macppc +Note the +.Nm +utility is only required for macppc machines with OpenFirmware version 2 +to boot. +OpenFirmware 3 cannot load bootblocks specified in the Apple partition +map. +.Pp +Install the Berkeley Fast File System primary bootstrap on to disk +.Sq wd0 : +.Dl Ic installboot /dev/rwd0c /usr/mdec/bootxx /ofwboot +.Pp +The secondary +.Nx Ns Tn /macppc +bootstrap is located in +.Pa /usr/mdec/ofwboot . +.Pp +The primary bootstrap requires the raw +.Pa ofwboot +for the secondary bootstrap, not +.Pa ofwboot.xcf , +which is used for the OpenFirmware to load kernels. +.Ss Nx Ns Tn /next68k +Install the bootstrap on to disk +.Sq sd0 : +.Dl Ic installboot /dev/rsd0c /usr/mdec/boot +.Pp +. +.Ss Nx Ns Tn /pmax +Install the Berkeley Fast File System primary bootstrap on to disk +.Sq sd0 : +.Dl Ic installboot /dev/rsd0c /usr/mdec/bootxx_ffs +.Pp +.Nx Ns Tn /pmax +requires that this file system starts at block 0 of the disk. +.Pp +Install the ISO 9660 primary bootstrap in the file +.Pa /tmp/cd-image : +.Dl Ic installboot -m pmax /tmp/cd-image /usr/mdec/bootxx_cd9660 +.Pp +Make an ISO 9660 filesystem in the file +.Pa /tmp/cd-image +and install the ISO 9660 primary bootstrap in the filesystem, where the +source directory for the ISO 9660 filesystem contains a kernel, the +primary bootstrap +.Pa bootxx_cd9660 +and the secondary bootstrap +.Pa boot.pmax : +.Dl Ic mkisofs -o /tmp/cd-image -a -l -v iso-source-dir +.Dl ... +.Dl 48 51 iso-source-dir/bootxx_cd9660 +.Dl ... +.Dl Ic installboot -b `expr 48 \e* 4` /tmp/cd-image /usr/mdec/bootxx_cd9660 +. +.Ss Nx Ns Tn /sparc +Install the Berkeley Fast File System primary bootstrap on to disk +.Sq sd0 , +with the secondary bootstrap +.Sq Pa /boot +already present: +.Dl Ic installboot /dev/rsd0c /usr/mdec/bootxx /boot +. +.Ss Nx Ns Tn /sparc64 +Install the primary bootstrap on to disk +.Sq sd0 : +.Dl Ic installboot /dev/rsd0c /usr/mdec/bootblk +.Pp +The secondary +.Nx Ns Tn /sparc64 +bootstrap is located in +.Pa /usr/mdec/ofwboot . +. +.Ss Nx Ns Tn /sun2 and Nx Ns Tn /sun3 +Install the Berkeley Fast File System primary bootstrap on to disk +.Sq sd0 , +with the secondary bootstrap +.Sq Pa /boot +already present: +.Dl Ic installboot /dev/rsd0c /usr/mdec/bootxx /boot +. +.Sh SEE ALSO +.Xr uname 3 , +.Xr boot 8 , +.Xr disklabel 8 , +.Xr dumpfs 8 , +.Xr fdisk 8 , +.Xr pxeboot 8 +. +.Sh HISTORY +This implementation of +.Nm +appeared in +.Nx 1.6 . +. +.Sh AUTHORS +The machine independent portion of this implementation of +.Nm +was written by Luke Mewburn. +The following people contributed to the various machine dependent +back-ends: +Simon Burge (pmax), +Chris Demetriou (alpha), +Matthew Fredette (sun2, sun3), +Matthew Green (sparc64), +Ross Harvey (alpha), +Michael Hitch (amiga), +Paul Kranenburg (sparc), +David Laight (i386), +Christian Limpach (next68k), +Luke Mewburn (macppc), +Matt Thomas (vax), +Izumi Tsutsui (news68k, newsmips), +and +UCHIYAMA Yasushi (ews4800mips). +. +.Sh BUGS +There are not currently primary bootstraps to support all file systems +types which are capable of being the root file system. +.Pp +If a disk has been converted from +.Sy FFS +to +.Sy RAID +without the contents of the disk erased, then the original +.Sy FFS +installation may be auto-detected instead of the +.Sy RAID +installation. +In this case, the +.Fl t Ar raid +option must be provided. +. +.Ss Nx Ns Tn /alpha +The +.Nx Ns Tn /alpha +primary bootstrap program can only load the secondary bootstrap program +from file systems starting at the beginning (block 0) of disks. +Similarly, the secondary bootstrap program can only load kernels from +file systems starting at the beginning of disks. +.Pp +The size of primary bootstrap programs is restricted to 7.5KB, even +though some file systems (e.g., ISO 9660) are able to accommodate larger +ones. +. +.Ss Nx Ns Tn /hp300 +The disk must have a boot partition large enough to hold the bootstrap code. +Currently the primary bootstrap must be a LIF format file. +. +.Ss Nx Ns Tn /i386 and Nx Ns Tn /amd64 +The bootstrap must be installed in the +.Nx +partition that starts at the beginning of the mbr partition. +If that is a valid filesystem and contains the +.Pa /boot +program then it will be used as the root filesystem, otherwise the +.Sq a +partition will be booted. +.Pp +The size of primary bootstrap programs is restricted to 8KB, even +though some file systems (e.g., ISO 9660) are able to accommodate larger +ones. +. +.Ss Nx Ns Tn /macppc +Due to restrictions in +.Nm +and the secondary bootstrap implementation, file systems where kernels exist +must start at the beginning of disks. +.Pp +Currently, +.Nm +doesn't recognize an existing Apple partition map on the disk +and always writes a faked map to make disks bootable. +.Pp +The +.Nx Ns Tn /macppc +bootstrap program can't load kernels from +.Sy FFSv2 +partitions. +.Ss Nx Ns Tn /next68k +The size of bootstrap programs is restricted to the free space before +the file system at the beginning of the disk minus 8KB. +. +.Ss Nx Ns Tn /pmax +The +.Nx Ns Tn /pmax +secondary bootstrap program can only load kernels from file +systems starting at the beginning of disks. +.Pp +The size of primary bootstrap programs is restricted to 7.5KB, even +though some file systems (e.g., ISO 9660) are able to accommodate larger +ones. +. +.Ss Nx Ns Tn /sun2 and Nx Ns Tn /sun3 +The +.Nx Ns Tn /sun2 +and +.Nx Ns Tn /sun3 +secondary bootstrap program can only load kernels from file +systems starting at the beginning of disks. +. +.Ss Nx Ns Tn /vax +The +.Nx Ns Tn /vax +secondary bootstrap program can only load kernels from file systems +starting at the beginning of disks. +.Pp +The size of primary bootstrap programs is restricted to 7.5KB, even +though some file systems (e.g., ISO 9660) are able to accommodate larger +ones. diff --git a/usr.sbin/installboot/installboot.c b/usr.sbin/installboot/installboot.c new file mode 100644 index 000000000..4de3603f5 --- /dev/null +++ b/usr.sbin/installboot/installboot.c @@ -0,0 +1,569 @@ +/* $NetBSD: installboot.c,v 1.36 2011/11/03 20:46:41 martin Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: installboot.c,v 1.36 2011/11/03 20:46:41 martin Exp $"); +#endif /* !__lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "installboot.h" + +static void getmachine(ib_params *, const char *, const char *); +static void getfstype(ib_params *, const char *, const char *); +static void parseoptions(ib_params *, const char *); +__dead static void usage(void); +static void options_usage(void); +static void machine_usage(void); +static void fstype_usage(void); + +static ib_params installboot_params; + +#define OFFSET(field) offsetof(ib_params, field) +const struct option { + const char *name; /* Name of option */ + ib_flags flag; /* Corresponding IB_xxx flag */ + enum { /* Type of option value... */ + OPT_BOOL, /* no value */ + OPT_INT, /* numeric value */ + OPT_WORD, /* space/tab/, terminated */ + OPT_STRING /* null terminated */ + } type; + int offset; /* of field in ib_params */ +} options[] = { + { "alphasum", IB_ALPHASUM, OPT_BOOL, 0 }, + { "append", IB_APPEND, OPT_BOOL, 0 }, + { "command", IB_COMMAND, OPT_STRING, OFFSET(command) }, + { "console", IB_CONSOLE, OPT_WORD, OFFSET(console) }, + { "ioaddr", IB_CONSADDR, OPT_INT, OFFSET(consaddr) }, + { "keymap", IB_KEYMAP, OPT_WORD, OFFSET(keymap) }, + { "password", IB_PASSWORD, OPT_WORD, OFFSET(password) }, + { "resetvideo", IB_RESETVIDEO, OPT_BOOL, 0 }, + { "speed", IB_CONSPEED, OPT_INT, OFFSET(conspeed) }, + { "sunsum", IB_SUNSUM, OPT_BOOL, 0 }, + { "timeout", IB_TIMEOUT, OPT_INT, OFFSET(timeout) }, + { "modules", IB_MODULES, OPT_BOOL, 0 }, + { "bootconf", IB_BOOTCONF, OPT_BOOL, 0 }, + { .name = NULL }, +}; +#undef OFFSET +#define OPTION(params, type, opt) (*(type *)((char *)(params) + (opt)->offset)) + +#define DFL_SECSIZE 512 /* Don't use DEV_BSIZE. It's host's value. */ + +int +main(int argc, char *argv[]) +{ + struct utsname utsname; + ib_params *params; + unsigned long lval; + int ch, rv, mode; + char *p; + const char *op; + ib_flags unsupported_flags; + + setprogname(argv[0]); + params = &installboot_params; + memset(params, 0, sizeof(*params)); + params->fsfd = -1; + params->s1fd = -1; + if ((p = getenv("MACHINE")) != NULL) + getmachine(params, p, "$MACHINE"); + + while ((ch = getopt(argc, argv, "b:B:cefm:no:t:v")) != -1) { + switch (ch) { + + case 'b': + case 'B': + if (*optarg == '\0') + goto badblock; + lval = strtoul(optarg, &p, 0); + if (lval > UINT32_MAX || *p != '\0') { + badblock: + errx(1, "Invalid block number `%s'", optarg); + } + if (ch == 'b') { + params->s1start = (uint32_t)lval; + params->flags |= IB_STAGE1START; + } else { + params->s2start = (uint32_t)lval; + params->flags |= IB_STAGE2START; + } + break; + + case 'c': + params->flags |= IB_CLEAR; + break; + + case 'e': + params->flags |= IB_EDIT; + break; + + case 'f': + params->flags |= IB_FORCE; + break; + + case 'm': + getmachine(params, optarg, "-m"); + break; + + case 'n': + params->flags |= IB_NOWRITE; + break; + + case 'o': + parseoptions(params, optarg); + break; + + case 't': + getfstype(params, optarg, "-t"); + break; + + case 'v': + params->flags |= IB_VERBOSE; + break; + + case '?': + default: + usage(); + /* NOTREACHED */ + + } + } + argc -= optind; + argv += optind; + + if (params->flags & IB_CLEAR && params->flags & IB_EDIT) + usage(); + if (argc < 1 || argc + 2 * !!(params->flags & (IB_CLEAR | IB_EDIT)) > 3) + usage(); + + /* set missing defaults */ + if (params->machine == NULL) { + if (uname(&utsname) == -1) + err(1, "Determine uname"); + getmachine(params, utsname.machine, "uname()"); + } + + /* Check that options are supported by this system */ + unsupported_flags = params->flags & ~params->machine->valid_flags; + unsupported_flags &= ~(IB_VERBOSE | IB_NOWRITE | IB_CLEAR | IB_EDIT + | IB_FORCE); + if (unsupported_flags != 0) { + int ndx; + for (ndx = 0; options[ndx].name != NULL; ndx++) { + if (unsupported_flags & options[ndx].flag) { + unsupported_flags &= ~options[ndx].flag; + warnx("`-o %s' is not supported for %s", + options[ndx].name, params->machine->name); + } + } + if (unsupported_flags & IB_STAGE1START) + warnx("`-b bno' is not supported for %s", + params->machine->name); + if (unsupported_flags & IB_STAGE2START) + warnx("`-B bno' is not supported for %s", + params->machine->name); + unsupported_flags &= ~(IB_STAGE1START | IB_STAGE2START); + if (unsupported_flags != 0) + warnx("Unknown unsupported flag %#x (coding error!)", + unsupported_flags); + exit(1); + } + /* and some illegal combinations */ + if (params->flags & IB_STAGE1START && params->flags & IB_APPEND) { + warnx("Can't use `-b bno' with `-o append'"); + exit(1); + } + if (params->flags & IB_CLEAR && + params->flags & (IB_STAGE1START | IB_STAGE2START | IB_APPEND)) { + warnx("Can't use `-b bno', `-B bno' or `-o append' with `-c'"); + exit(1); + } + + if (argc >= 3) { + params->stage2 = argv[2]; + } + + params->filesystem = argv[0]; + if (params->flags & IB_NOWRITE) { + op = "only"; + mode = O_RDONLY; + } else { + op = "write"; + mode = O_RDWR; + } + /* XXX should be specified via option */ + params->sectorsize = DFL_SECSIZE; + if ((params->fsfd = open(params->filesystem, mode, 0600)) == -1) + err(1, "Opening file system `%s' read-%s", + params->filesystem, op); + if (fstat(params->fsfd, ¶ms->fsstat) == -1) + err(1, "Examining file system `%s'", params->filesystem); + if (params->fstype != NULL) { + if (! params->fstype->match(params)) + errx(1, "File system `%s' is not of type %s", + params->filesystem, params->fstype->name); + } else { + if (params->stage2 != NULL) { + params->fstype = &fstypes[0]; + while (params->fstype->name != NULL && + !params->fstype->match(params)) + params->fstype++; + if (params->fstype->name == NULL) + errx(1, "File system `%s' is of an unknown type", + params->filesystem); + } + } + + 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]); + params->stage1 = argv[1]; + } + assert(params->machine != NULL); + + if (params->flags & IB_VERBOSE) { + printf("File system: %s\n", params->filesystem); + if (params->fstype) + printf("File system type: %s (blocksize %u, " + "needswap %d)\n", + params->fstype->name, params->fstype->blocksize, + params->fstype->needswap); + if (!(params->flags & IB_EDIT)) + printf("Primary bootstrap: %s\n", + (params->flags & IB_CLEAR) ? "(to be cleared)" + : params->stage1 ? params->stage1 : "(none)" ); + if (params->stage2 != NULL) + printf("Secondary bootstrap: %s\n", params->stage2); + } + + if (params->flags & IB_EDIT) { + op = "Edit"; + rv = params->machine->editboot(params); + } else if (params->flags & IB_CLEAR) { + op = "Clear"; + rv = params->machine->clearboot(params); + } else { + if (argc < 2) + errx(EXIT_FAILURE, "Please specify the primary " + "bootstrap file"); + op = "Set"; + rv = params->machine->setboot(params); + } + if (rv == 0) + errx(1, "%s bootstrap operation failed", op); + + if (S_ISREG(params->fsstat.st_mode)) { + if (fsync(params->fsfd) == -1) + err(1, "Synchronising file system `%s'", + params->filesystem); + } else { + /* Sync filesystems (to clean in-memory superblock?) */ + sync(); + } + if (close(params->fsfd) == -1) + err(1, "Closing file system `%s'", params->filesystem); + if (argc == 2) + if (close(params->s1fd) == -1) + err(1, "Closing primary bootstrap `%s'", + params->stage1); + + exit(0); + /* NOTREACHED */ +} + +static void +parseoptions(ib_params *params, const char *option) +{ + char *cp; + const struct option *opt; + int len; + unsigned long val; + + assert(params != NULL); + assert(option != NULL); + + for (;; option += len) { + option += strspn(option, ", \t"); + if (*option == 0) + return; + len = strcspn(option, "=,"); + for (opt = options; opt->name != NULL; opt++) { + if (memcmp(option, opt->name, len) == 0 + && opt->name[len] == 0) + break; + } + if (opt->name == NULL) { + len = strcspn(option, ","); + warnx("Unknown option `-o %.*s'", len, option); + break; + } + params->flags |= opt->flag; + if (opt->type == OPT_BOOL) { + if (option[len] != '=') + continue; + warnx("Option `%s' must not have a value", opt->name); + break; + } + if (option[len] != '=') { + warnx("Option `%s' must have a value", opt->name); + break; + } + option += len + 1; + len = strcspn(option, ","); + switch (opt->type) { + case OPT_STRING: + len = strlen(option); + /* FALLTHROUGH */ + case OPT_WORD: + cp = strdup(option); + if (cp == NULL) + err(1, "strdup"); + cp[len] = 0; + OPTION(params, char *, opt) = cp; + continue; + case OPT_INT: + val = strtoul(option, &cp, 0); + if (cp > option + len || (*cp != 0 && *cp != ',')) + break; + if (val > INT_MAX) + break; + OPTION(params, int, opt) = (int)val; + continue; + default: + errx(1, "Internal error: option `%s' has invalid type %d", + opt->name, opt->type); + } + warnx("Invalid option value `%s=%.*s'", opt->name, len, option); + break; + } + options_usage(); + exit(1); +} + +static void +options_usage(void) +{ + int ndx; + const char *pfx; + + warnx("Valid options are:"); + pfx = "\t"; + for (ndx = 0; options[ndx].name != 0; ndx++) { + fprintf(stderr, "%s%s", pfx, options[ndx].name); + switch (options[ndx].type) { + case OPT_INT: + fprintf(stderr, "=number"); + break; + case OPT_WORD: + fprintf(stderr, "=word"); + break; + case OPT_STRING: + fprintf(stderr, "=string"); + break; + default: + break; + } + if ((ndx % 5) == 4) + pfx = ",\n\t"; + else + pfx = ", "; + } + fprintf(stderr, "\n"); +} + +int +no_setboot(ib_params *params) +{ + + assert(params != NULL); + + warnx("%s: bootstrap installation is not supported", + params->machine->name); + return (0); +} + +int +no_clearboot(ib_params *params) +{ + + assert(params != NULL); + + warnx("%s: bootstrap removal is not supported", + params->machine->name); + return (0); +} + +int +no_editboot(ib_params *params) +{ + + assert(params != NULL); + + warnx("%s: bootstrap editing is not supported", + params->machine->name); + return (0); +} + + +static void +getmachine(ib_params *param, const char *mach, const char *provider) +{ + int i; + + assert(param != NULL); + assert(mach != NULL); + assert(provider != NULL); + + for (i = 0; machines[i] != NULL; i++) { + if (machines[i]->name == NULL) + continue; + if (strcmp(machines[i]->name, mach) == 0) { + param->machine = machines[i]; + return; + } + } + warnx("Invalid machine `%s' from %s", mach, provider); + machine_usage(); + exit(1); +} + +static void +machine_usage(void) +{ + const char *prefix; + int i; + int col, len; + const char *name; + int wincol=80; +#ifdef TIOCGWINSZ + struct winsize win; + + if (ioctl(fileno(stderr), TIOCGWINSZ, &win) == 0 && win.ws_col > 0) + wincol = win.ws_col; +#endif + + warnx("Supported machines are:"); + prefix="\t"; + col = 8 + 3; + for (i = 0; machines[i] != NULL; i++) { + name = machines[i]->name; + if (name == NULL) + continue; + len = strlen(name); + if (col + len > wincol) { + prefix=",\n\t"; + col = -2 + 8 + 3; + } + col += fprintf(stderr, "%s%s", prefix, name); + prefix=", "; + } + fputs("\n", stderr); +} + +static void +getfstype(ib_params *param, const char *fstype, const char *provider) +{ + int i; + + assert(param != NULL); + assert(fstype != NULL); + assert(provider != NULL); + + for (i = 0; fstypes[i].name != NULL; i++) { + if (strcmp(fstypes[i].name, fstype) == 0) { + param->fstype = &fstypes[i]; + return; + } + } + warnx("Invalid file system type `%s' from %s", fstype, provider); + fstype_usage(); + exit(1); +} + +static void +fstype_usage(void) +{ +#ifndef NO_STAGE2 + const char *prefix; + int i; + + warnx("Supported file system types are:"); +#define FSTYPES_PER_LINE 9 + prefix="\t"; + for (i = 0; fstypes[i].name != NULL; i++) { + if (i && (i % FSTYPES_PER_LINE) == 0) + prefix=",\n\t"; + fprintf(stderr, "%s%s", prefix, fstypes[i].name); + prefix=", "; + } + fputs("\n", stderr); +#endif +} + +static void +usage(void) +{ + const char *prog; + + prog = getprogname(); + fprintf(stderr, +"usage: %s [-fnv] [-B s2bno] [-b s1bno] [-m machine] [-o options]\n" +"\t\t [-t fstype] filesystem primary [secondary]\n" +"usage: %s -c [-fnv] [-m machine] [-o options] [-t fstype] filesystem\n" +"usage: %s -e [-fnv] [-m machine] [-o options] bootstrap\n", + prog, prog, prog); + machine_usage(); + fstype_usage(); + options_usage(); + exit(1); +} diff --git a/usr.sbin/installboot/installboot.h b/usr.sbin/installboot/installboot.h new file mode 100644 index 000000000..00cb0c999 --- /dev/null +++ b/usr.sbin/installboot/installboot.h @@ -0,0 +1,185 @@ +/* $NetBSD: installboot.h,v 1.38 2011/06/14 05:35:08 matt Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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_H +#define _INSTALLBOOT_H + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#include "../../sys/sys/bootblock.h" +#else +#include +#include +#endif + +#include +#include + +typedef enum { + /* flags from global options */ + IB_VERBOSE = 1<<0, /* verbose operation */ + IB_NOWRITE = 1<<1, /* don't write */ + IB_CLEAR = 1<<2, /* clear boot block */ + IB_EDIT = 1<<3, /* edit boot parameters */ + IB_FORCE = 1<<4, /* Ignore some consistency checks */ + + /* flags from -o options */ + IB_ALPHASUM = 1<<8, /* set Alpha checksum */ + IB_APPEND = 1<<9, /* append stage 1 to EO(regular)F */ + IB_SUNSUM = 1<<10, /* set Sun checksum */ + IB_STAGE1START= 1<<11, /* start block for stage 1 provided */ + IB_STAGE2START= 1<<12, /* start block for stage 2 provided */ + IB_COMMAND = 1<<13, /* Amiga commandline option */ + IB_RESETVIDEO = 1<<14, /* i386 reset video */ + IB_CONSOLE = 1<<15, /* i386 console */ + IB_CONSPEED = 1<<16, /* i386 console baud rate */ + IB_TIMEOUT = 1<<17, /* i386 boot timeout */ + IB_PASSWORD = 1<<18, /* i386 boot password */ + IB_KEYMAP = 1<<19, /* i386 console keymap */ + IB_CONSADDR = 1<<20, /* i386 console io address */ + IB_MODULES = 1<<21, /* i386: load modules */ + IB_BOOTCONF = 1<<22, /* i386: read boot.conf */ +} ib_flags; + +typedef struct { + ib_flags flags; /* flags (see above) */ + struct ib_mach *machine; /* machine details (see below) */ + struct ib_fs *fstype; /* file system details (see below) */ + const char *filesystem; /* name of target file system */ + int fsfd; /* open fd to filesystem */ + struct stat fsstat; /* fstat(2) of fsfd */ + const char *stage1; /* name of stage1 bootstrap */ + int s1fd; /* open fd to stage1 */ + struct stat s1stat; /* fstat(2) of s1fd */ + uint64_t s1start; /* start block of stage1 */ + const char *stage2; /* name of stage2 bootstrap */ + uint64_t s2start; /* start block of stage2 */ + uint32_t sectorsize; /* sector size of target fs */ + /* parsed -o option=value data */ + const char *command; /* name of command string */ + const char *console; /* name of console */ + int conspeed; /* console baud rate */ + int consaddr; /* console io address */ + const char *password; /* boot password */ + int timeout; /* interactive boot timeout */ + const char *keymap; /* keyboard translations */ +} ib_params; + +typedef struct { + uint64_t block; + uint32_t blocksize; +} ib_block; + +struct ib_mach { + const char *name; + int (*setboot) (ib_params *); + int (*clearboot) (ib_params *); + int (*editboot) (ib_params *); + ib_flags valid_flags; +}; + +struct ib_fs { + /* compile time parameters */ + const char *name; + int (*match) (ib_params *); + int (*findstage2) (ib_params *, uint32_t *, ib_block *); + /* run time fs specific parameters */ + uint32_t blocksize; + uint32_t needswap; + off_t sblockloc; /* location of superblock */ + off_t offset; /* file system offset (e.g. RAID) */ +}; + +typedef enum { + BBINFO_BIG_ENDIAN = 0, + BBINFO_LITTLE_ENDIAN = 1, +} bbinfo_endian; + +struct bbinfo_params { + const char *magic; /* magic string to look for */ + uint32_t offset; /* offset to write start of stage1 */ + uint32_t blocksize; /* blocksize of stage1 */ + uint32_t maxsize; /* max size of stage1 */ + uint32_t headeroffset; /* + * header offset (relative to offset) + * to read stage1 into + */ + bbinfo_endian endian; +}; + +extern struct ib_mach * const machines[]; +extern struct ib_fs fstypes[]; + + /* installboot.c */ +uint16_t compute_sunsum(const uint16_t *); +int set_sunsum(ib_params *, uint16_t *, uint16_t); +int no_setboot(ib_params *); +int no_clearboot(ib_params *); +int no_editboot(ib_params *); + + /* bbinfo.c */ +int shared_bbinfo_clearboot(ib_params *, struct bbinfo_params *, + int (*)(ib_params *, struct bbinfo_params *, uint8_t *)); +int shared_bbinfo_setboot(ib_params *, struct bbinfo_params *, + int (*)(ib_params *, struct bbinfo_params *, uint8_t *)); + + /* fstypes.c */ +int hardcode_stage2(ib_params *, uint32_t *, ib_block *); +int ffs_match(ib_params *); +int ffs_findstage2(ib_params *, uint32_t *, ib_block *); +int raid_match(ib_params *); +int raw_match(ib_params *); +int raw_findstage2(ib_params *, uint32_t *, ib_block *); +int ext2fs_match(ib_params *); +int ext2fs_findstage2(ib_params *, uint32_t *, ib_block *); + + /* machines.c */ +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_ews4800mips; +extern struct ib_mach ib_mach_hp300; +extern struct ib_mach ib_mach_hp700; +extern struct ib_mach ib_mach_i386; +extern struct ib_mach ib_mach_landisk; +extern struct ib_mach ib_mach_macppc; +extern struct ib_mach ib_mach_news68k; +extern struct ib_mach ib_mach_newsmips; +extern struct ib_mach ib_mach_next68k; +extern struct ib_mach ib_mach_pmax; +extern struct ib_mach ib_mach_sparc; +extern struct ib_mach ib_mach_sparc64; +extern struct ib_mach ib_mach_sun2; +extern struct ib_mach ib_mach_sun3; +extern struct ib_mach ib_mach_vax; +extern struct ib_mach ib_mach_x68k; + +#endif /* _INSTALLBOOT_H */ diff --git a/usr.sbin/installboot/machines.c b/usr.sbin/installboot/machines.c new file mode 100644 index 000000000..9320b0afe --- /dev/null +++ b/usr.sbin/installboot/machines.c @@ -0,0 +1,97 @@ +/* $NetBSD: machines.c,v 1.38 2011/06/14 05:35:08 matt Exp $ */ + +/*- + * Copyright (c) 2002-2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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 +#if !defined(__lint) +__RCSID("$NetBSD: machines.c,v 1.38 2011/06/14 05:35:08 matt Exp $"); +#endif /* !__lint */ + +#include +#include "installboot.h" + +/* + * Define these here so they end up as zero-filled bss if installboot + * isn't built with all the architectures defined. + * A lot simpler that conditionally including the definitions themselves. + */ +struct ib_mach + ib_mach_alpha, + ib_mach_amd64, + ib_mach_amiga, + ib_mach_emips, + ib_mach_ews4800mips, + ib_mach_hp300, + ib_mach_hp700, + ib_mach_i386, + ib_mach_landisk, + ib_mach_macppc, + ib_mach_news68k, + ib_mach_newsmips, + ib_mach_next68k, + ib_mach_pmax, + ib_mach_sparc, + ib_mach_sparc64, + ib_mach_sun2, + ib_mach_sun3, + ib_mach_vax, + ib_mach_x68k; + +struct ib_mach * const machines[] = { + &ib_mach_alpha, + &ib_mach_amd64, + &ib_mach_amiga, + &ib_mach_emips, + &ib_mach_ews4800mips, + &ib_mach_hp300, + &ib_mach_hp700, + &ib_mach_i386, + &ib_mach_landisk, + &ib_mach_macppc, + &ib_mach_news68k, + &ib_mach_newsmips, + &ib_mach_next68k, + &ib_mach_pmax, + &ib_mach_sparc, + &ib_mach_sparc64, + &ib_mach_sun2, + &ib_mach_sun3, + &ib_mach_vax, + &ib_mach_x68k, + NULL +}; + +#if 0 + { "shark", no_setboot, no_clearboot, no_editboot, 0 }, +#endif diff --git a/usr.sbin/installboot/sum.c b/usr.sbin/installboot/sum.c new file mode 100644 index 000000000..87c7f495f --- /dev/null +++ b/usr.sbin/installboot/sum.c @@ -0,0 +1,108 @@ +/* $NetBSD: sum.c,v 1.5 2010/01/14 16:27:49 tsutsui Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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. + */ + +/* + * Copyright (c) 1999 Ross Harvey. All rights reserved. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ross Harvey + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 +#if !defined(__lint) +__RCSID("$NetBSD: sum.c,v 1.5 2010/01/14 16:27:49 tsutsui Exp $"); +#endif /* !__lint */ + +#include + +#include +#include + +#include "installboot.h" + + +uint16_t +compute_sunsum(const uint16_t *bb16) +{ + uint16_t i, s; + + assert(bb16 != NULL); + + s = 0; + for (i = 0; i < 255; ++i) + s ^= bb16[i]; + return (s); +} + +int +set_sunsum(ib_params *params, uint16_t *bb16, uint16_t sum) +{ + + assert(params != NULL); + assert(bb16 != NULL); + +#define SUNSUM_OFFSET 255 + if (params->flags & IB_VERBOSE) { + printf("Old Sun checksum: 0x%04x\n", + be16toh(bb16[SUNSUM_OFFSET])); + printf("Recalculated Sun checksum: 0x%04x\n", be16toh(sum)); + } + // XXX: does this need to be big endian? + bb16[SUNSUM_OFFSET] = sum; + return (1); +}