[BACK]Return to installboot.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc64 / stand / installboot

Annotation of sys/arch/sparc64/stand/installboot/installboot.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: installboot.c,v 1.6 2004/06/24 16:31:02 deraadt Exp $ */
                      2: /*     $NetBSD: installboot.c,v 1.8 2001/02/19 22:48:59 cgd Exp $ */
                      3:
                      4: /*-
                      5:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by Paul Kranenburg.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: #include <sys/param.h>
                     41: #include <sys/mount.h>
                     42: #include <sys/time.h>
                     43: #include <sys/stat.h>
                     44: #include <sys/sysctl.h>
                     45: #include <sys/mman.h>
                     46: #include <sys/utsname.h>
                     47: #include <ufs/ufs/dinode.h>
                     48: #include <ufs/ufs/dir.h>
                     49: #include <ufs/ffs/fs.h>
                     50: #include <err.h>
                     51: #include <a.out.h>
                     52: #include <fcntl.h>
                     53: #include <nlist.h>
                     54: #include <stdlib.h>
                     55: #include <stdio.h>
                     56: #include <string.h>
                     57: #include <unistd.h>
                     58:
                     59: #include "loadfile.h"
                     60:
                     61: int    verbose, nowrite, sparc64, uflag, hflag = 1;
                     62: char   *boot, *proto, *dev;
                     63:
                     64: #if 0
                     65: #ifdef __ELF__
                     66: #define SYMNAME(a)     a
                     67: #else
                     68: #define SYMNAME(a)     __CONCAT("_",a)
                     69: #endif
                     70: #else
                     71: /* XXX: Hack in libc nlist works with both formats */
                     72: #define SYMNAME(a)     "_"a
                     73: #endif
                     74:
                     75: struct nlist nl[] = {
                     76: #define X_BLOCKTABLE   0
                     77:        { {SYMNAME("block_table")} },
                     78: #define X_BLOCKCOUNT   1
                     79:        { {SYMNAME("block_count")} },
                     80: #define X_BLOCKSIZE    2
                     81:        { {SYMNAME("block_size")} },
                     82:        { {NULL} }
                     83: };
                     84: daddr_t        *block_table;           /* block number array in prototype image */
                     85: int32_t        *block_count_p;         /* size of this array */
                     86: int32_t        *block_size_p;          /* filesystem block size */
                     87: int32_t        max_block_count;
                     88:
                     89: char           *loadprotoblocks(char *, size_t *);
                     90: int            loadblocknums(char *, int);
                     91: static void    devread(int, void *, daddr_t, size_t, char *);
                     92: static void    usage(void);
                     93: int            main(int, char *[]);
                     94:
                     95: static void
                     96: usage()
                     97: {
                     98:        extern char *__progname;
                     99:        const char *progname = __progname;
                    100:
                    101:        if (sparc64)
                    102:                (void)fprintf(stderr,
                    103:                    "Usage: %s [-nv] <bootblk> <device>\n"
                    104:                    "       %s -U [-nv] <boot> <proto> <device>\n",
                    105:                    progname, progname);
                    106:        else
                    107:                (void)fprintf(stderr,
                    108:                    "Usage: %s [-nv] <boot> <proto> <device>\n"
                    109:                    "       %s -u [-n] [-v] <bootblk> <device>\n",
                    110:                    progname, progname);
                    111:        exit(1);
                    112: }
                    113:
                    114: int
                    115: main(argc, argv)
                    116:        int argc;
                    117:        char *argv[];
                    118: {
                    119:        int     c;
                    120:        int     devfd;
                    121:        char    *protostore;
                    122:        size_t  protosize;
                    123:        struct  utsname utsname;
                    124:
                    125:        /*
                    126:         * For UltraSPARC machines, we turn on the uflag by default.
                    127:         */
                    128:        if (uname(&utsname) == -1)
                    129:                err(1, "uname");
                    130:        if (strcmp(utsname.machine, "sparc64") == 0)
                    131:                sparc64 = uflag = 1;
                    132:
                    133:        while ((c = getopt(argc, argv, "a:nhuUv")) != -1) {
                    134:                switch (c) {
                    135:                case 'a':
                    136:                        warnx("-a option is obsolete");
                    137:                        break;
                    138:                case 'h':       /* Note: for backwards compatibility */
                    139:                        /* Don't strip a.out header */
                    140:                        warnx("-h option is obsolete");
                    141:                        break;
                    142:                case 'n':
                    143:                        /* Do not actually write the bootblock to disk */
                    144:                        nowrite = 1;
                    145:                        break;
                    146:                case 'u':
                    147:                        /* UltraSPARC boot block */
                    148:                        uflag = 1;
                    149:                        break;
                    150:                case 'U':
                    151:                        /* Force non-ultrasparc */
                    152:                        uflag = 0;
                    153:                        break;
                    154:                case 'v':
                    155:                        /* Chat */
                    156:                        verbose = 1;
                    157:                        break;
                    158:                default:
                    159:                        usage();
                    160:                }
                    161:        }
                    162:
                    163:        if (uflag) {
                    164:                if (argc - optind < 2)
                    165:                        usage();
                    166:        } else {
                    167:                if (argc - optind < 3)
                    168:                        usage();
                    169:                boot = argv[optind++];
                    170:        }
                    171:
                    172:        proto = argv[optind++];
                    173:        dev = argv[optind];
                    174:
                    175:        if (verbose) {
                    176:                if (!uflag)
                    177:                        printf("boot: %s\n", boot);
                    178:                printf("proto: %s\n", proto);
                    179:                printf("device: %s\n", dev);
                    180:        }
                    181:
                    182:        /* Load proto blocks into core */
                    183:        if (uflag == 0) {
                    184:                if ((protostore = loadprotoblocks(proto, &protosize)) == NULL)
                    185:                        exit(1);
                    186:
                    187:                /* Open and check raw disk device */
                    188:                if ((devfd = open(dev, O_RDONLY, 0)) < 0)
                    189:                        err(1, "open: %s", dev);
                    190:
                    191:                /* Extract and load block numbers */
                    192:                if (loadblocknums(boot, devfd) != 0)
                    193:                        exit(1);
                    194:
                    195:                (void)close(devfd);
                    196:        } else {
                    197:                struct stat sb;
                    198:                int protofd;
                    199:                size_t blanklen;
                    200:
                    201:                if ((protofd = open(proto, O_RDONLY)) < 0)
                    202:                        err(1, "open: %s", proto);
                    203:
                    204:                if (fstat(protofd, &sb) < 0)
                    205:                        err(1, "fstat: %s", proto);
                    206:
                    207:                /* there must be a better way */
                    208:                blanklen = DEV_BSIZE - ((sb.st_size + DEV_BSIZE) & (DEV_BSIZE - 1));
                    209:                protosize = sb.st_size + blanklen;
                    210:                if ((protostore = mmap(0, (size_t)protosize,
                    211:                    PROT_READ|PROT_WRITE, MAP_PRIVATE,
                    212:                    protofd, 0)) == MAP_FAILED)
                    213:                        err(1, "mmap: %s", proto);
                    214:                /* and provide the rest of the block */
                    215:                if (blanklen)
                    216:                        memset(protostore + sb.st_size, 0, blanklen);
                    217:        }
                    218:
                    219:        if (nowrite)
                    220:                return 0;
                    221:
                    222:        /* Write patched proto bootblocks into the superblock */
                    223:        if (protosize > SBSIZE - DEV_BSIZE)
                    224:                errx(1, "proto bootblocks too big");
                    225:
                    226:        if ((devfd = open(dev, O_RDWR, 0)) < 0)
                    227:                err(1, "open: %s", dev);
                    228:
                    229:        if (lseek(devfd, DEV_BSIZE, SEEK_SET) != DEV_BSIZE)
                    230:                err(1, "lseek bootstrap");
                    231:
                    232:        /* Sync filesystems (to clean in-memory superblock?) */
                    233:        sync();
                    234:
                    235:        if (write(devfd, protostore, protosize) != protosize)
                    236:                err(1, "write bootstrap");
                    237:        (void)close(devfd);
                    238:        return 0;
                    239: }
                    240:
                    241: char *
                    242: loadprotoblocks(fname, size)
                    243:        char *fname;
                    244:        size_t *size;
                    245: {
                    246:        int     fd, sz;
                    247:        u_long  ap, bp, st, en;
                    248:        u_long  marks[MARK_MAX];
                    249:
                    250:        /* Locate block number array in proto file */
                    251:        if (nlist(fname, nl) != 0) {
                    252:                warnx("nlist: %s: symbols not found", fname);
                    253:                return NULL;
                    254:        }
                    255:        if (nl[X_BLOCKTABLE].n_type != N_DATA + N_EXT) {
                    256:                warnx("nlist: %s: wrong type", nl[X_BLOCKTABLE].n_un.n_name);
                    257:                return NULL;
                    258:        }
                    259:        if (nl[X_BLOCKCOUNT].n_type != N_DATA + N_EXT) {
                    260:                warnx("nlist: %s: wrong type", nl[X_BLOCKCOUNT].n_un.n_name);
                    261:                return NULL;
                    262:        }
                    263:        if (nl[X_BLOCKSIZE].n_type != N_DATA + N_EXT) {
                    264:                warnx("nlist: %s: wrong type", nl[X_BLOCKSIZE].n_un.n_name);
                    265:                return NULL;
                    266:        }
                    267:
                    268:        marks[MARK_START] = 0;
                    269:        if ((fd = loadfile(fname, marks, COUNT_TEXT|COUNT_DATA)) == -1)
                    270:                return NULL;
                    271:        (void)close(fd);
                    272:
                    273:        sz = (marks[MARK_END] - marks[MARK_START]) + (hflag ? 32 : 0);
                    274:        sz = roundup(sz, DEV_BSIZE);
                    275:        st = marks[MARK_START];
                    276:        en = marks[MARK_ENTRY];
                    277:
                    278:        if ((ap = (u_long)malloc(sz)) == NULL) {
                    279:                warn("malloc: %s", "");
                    280:                return NULL;
                    281:        }
                    282:
                    283:        bp = ap + (hflag ? 32 : 0);
                    284:        marks[MARK_START] = bp - st;
                    285:        if ((fd = loadfile(fname, marks, LOAD_TEXT|LOAD_DATA)) == -1) {
                    286:                free((void *)ap);
                    287:                return NULL;
                    288:        }
                    289:        (void)close(fd);
                    290:
                    291:        block_table = (daddr_t *) (bp + nl[X_BLOCKTABLE].n_value - st);
                    292:        block_count_p = (int32_t *)(bp + nl[X_BLOCKCOUNT].n_value - st);
                    293:        block_size_p = (int32_t *) (bp + nl[X_BLOCKSIZE].n_value - st);
                    294:        if ((int)(u_long)block_table & 3) {
                    295:                warn("%s: invalid address: block_table = %p",
                    296:                     fname, block_table);
                    297:                free((void *)ap);
                    298:                return NULL;
                    299:        }
                    300:        if ((int)(u_long)block_count_p & 3) {
                    301:                warn("%s: invalid address: block_count_p = %p",
                    302:                     fname, block_count_p);
                    303:                free((void *)ap);
                    304:                return NULL;
                    305:        }
                    306:        if ((int)(u_long)block_size_p & 3) {
                    307:                warn("%s: invalid address: block_size_p = %p",
                    308:                     fname, block_size_p);
                    309:                free((void *)ap);
                    310:                return NULL;
                    311:        }
                    312:        max_block_count = *block_count_p;
                    313:
                    314:        if (verbose) {
                    315:                printf("%s: entry point %#lx\n", fname, en);
                    316:                printf("%s: a.out header %s\n", fname,
                    317:                    hflag ? "left on" : "stripped off");
                    318:                printf("proto bootblock size %d\n", sz);
                    319:                printf("room for %d filesystem blocks at %#lx\n",
                    320:                    max_block_count, nl[X_BLOCKTABLE].n_value);
                    321:        }
                    322:
                    323:        if (hflag) {
                    324:                /*
                    325:                 * We convert the a.out header in-vitro into something that
                    326:                 * Sun PROMs understand.
                    327:                 * Old-style (sun4) ROMs do not expect a header at all, so
                    328:                 * we turn the first two words into code that gets us past
                    329:                 * the 32-byte header where the actual code begins. In assembly
                    330:                 * speak:
                    331:                 *      .word   MAGIC           ! a NOP
                    332:                 *      ba,a    start           !
                    333:                 *      .skip   24              ! pad
                    334:                 * start:
                    335:                 */
                    336: #define SUN_MAGIC      0x01030107
                    337: #define SUN4_BASTART   0x30800007      /* i.e.: ba,a `start' */
                    338:                *((int *)ap) = SUN_MAGIC;
                    339:                *((int *)ap + 1) = SUN4_BASTART;
                    340:        }
                    341:
                    342:        *size = sz;
                    343:        return (char *)ap;
                    344: }
                    345:
                    346: static void
                    347: devread(fd, buf, blk, size, msg)
                    348:        int     fd;
                    349:        void    *buf;
                    350:        daddr_t blk;
                    351:        size_t  size;
                    352:        char    *msg;
                    353: {
                    354:        if (lseek(fd, dbtob(blk), SEEK_SET) != dbtob(blk))
                    355:                err(1, "%s: devread: lseek", msg);
                    356:
                    357:        if (read(fd, buf, size) != size)
                    358:                err(1, "%s: devread: read", msg);
                    359: }
                    360:
                    361: static char sblock[SBSIZE];
                    362:
                    363: int
                    364: loadblocknums(boot, devfd)
                    365: char   *boot;
                    366: int    devfd;
                    367: {
                    368:        int             i, fd;
                    369:        struct  stat    statbuf;
                    370:        struct  statfs  statfsbuf;
                    371:        struct fs       *fs;
                    372:        char            *buf;
                    373:        daddr_t         blk, *ap;
                    374:        struct ufs1_dinode      *ip;
                    375:        int             ndb;
                    376:
                    377:        /*
                    378:         * Open 2nd-level boot program and record the block numbers
                    379:         * it occupies on the filesystem represented by `devfd'.
                    380:         */
                    381:        if ((fd = open(boot, O_RDONLY)) < 0)
                    382:                err(1, "open: %s", boot);
                    383:
                    384:        if (fstatfs(fd, &statfsbuf) != 0)
                    385:                err(1, "statfs: %s", boot);
                    386:
                    387:        if (strncmp(statfsbuf.f_fstypename, "ffs", MFSNAMELEN) &&
                    388:            strncmp(statfsbuf.f_fstypename, "ufs", MFSNAMELEN)) {
                    389:                errx(1, "%s: must be on an FFS filesystem", boot);
                    390:        }
                    391:
                    392:        if (fsync(fd) != 0)
                    393:                err(1, "fsync: %s", boot);
                    394:
                    395:        if (fstat(fd, &statbuf) != 0)
                    396:                err(1, "fstat: %s", boot);
                    397:
                    398:        close(fd);
                    399:
                    400:        /* Read superblock */
                    401:        devread(devfd, sblock, btodb(SBOFF), SBSIZE, "superblock");
                    402:        fs = (struct fs *)sblock;
                    403:
                    404:        /* Read inode */
                    405:        if ((buf = malloc(fs->fs_bsize)) == NULL)
                    406:                errx(1, "No memory for filesystem block");
                    407:
                    408:        blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));
                    409:        devread(devfd, buf, blk, fs->fs_bsize, "inode");
                    410:        ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);
                    411:
                    412:        /*
                    413:         * Register filesystem block size.
                    414:         */
                    415:        *block_size_p = fs->fs_bsize;
                    416:
                    417:        /*
                    418:         * Get the block numbers; we don't handle fragments
                    419:         */
                    420:        ndb = howmany(ip->di_size, fs->fs_bsize);
                    421:        if (ndb > max_block_count)
                    422:                errx(1, "%s: Too many blocks", boot);
                    423:
                    424:        /*
                    425:         * Register block count.
                    426:         */
                    427:        *block_count_p = ndb;
                    428:
                    429:        if (verbose)
                    430:                printf("%s: block numbers: ", boot);
                    431:        ap = ip->di_db;
                    432:        for (i = 0; i < NDADDR && *ap && ndb; i++, ap++, ndb--) {
                    433:                blk = fsbtodb(fs, *ap);
                    434:                block_table[i] = blk;
                    435:                if (verbose)
                    436:                        printf("%d ", blk);
                    437:        }
                    438:        if (verbose)
                    439:                printf("\n");
                    440:
                    441:        if (ndb == 0)
                    442:                return 0;
                    443:
                    444:        /*
                    445:         * Just one level of indirections; there isn't much room
                    446:         * for more in the 1st-level bootblocks anyway.
                    447:         */
                    448:        if (verbose)
                    449:                printf("%s: block numbers (indirect): ", boot);
                    450:        blk = ip->di_ib[0];
                    451:        devread(devfd, buf, blk, fs->fs_bsize, "indirect block");
                    452:        ap = (daddr_t *)buf;
                    453:        for (; i < NINDIR(fs) && *ap && ndb; i++, ap++, ndb--) {
                    454:                blk = fsbtodb(fs, *ap);
                    455:                block_table[i] = blk;
                    456:                if (verbose)
                    457:                        printf("%d ", blk);
                    458:        }
                    459:        if (verbose)
                    460:                printf("\n");
                    461:
                    462:        if (ndb)
                    463:                errx(1, "%s: Too many blocks", boot);
                    464:        return 0;
                    465: }

CVSweb