Home | History | Annotate | Line # | Download | only in arch
i386.c revision 1.15.2.1
      1  1.15.2.1    tron /* $NetBSD: i386.c,v 1.15.2.1 2004/06/22 07:20:18 tron Exp $ */
      2       1.1     dsl 
      3       1.1     dsl /*-
      4       1.1     dsl  * Copyright (c) 2003 The NetBSD Foundation, Inc.
      5       1.1     dsl  * All rights reserved.
      6       1.1     dsl  *
      7       1.1     dsl  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1     dsl  * by David Laight.
      9       1.1     dsl  *
     10       1.1     dsl  * Redistribution and use in source and binary forms, with or without
     11       1.1     dsl  * modification, are permitted provided that the following conditions
     12       1.1     dsl  * are met:
     13       1.1     dsl  * 1. Redistributions of source code must retain the above copyright
     14       1.1     dsl  *    notice, this list of conditions and the following disclaimer.
     15       1.1     dsl  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1     dsl  *    notice, this list of conditions and the following disclaimer in the
     17       1.1     dsl  *    documentation and/or other materials provided with the distribution.
     18       1.1     dsl  * 3. All advertising materials mentioning features or use of this software
     19       1.1     dsl  *    must display the following acknowledgement:
     20       1.1     dsl  *        This product includes software developed by the NetBSD
     21       1.1     dsl  *        Foundation, Inc. and its contributors.
     22       1.1     dsl  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23       1.1     dsl  *    contributors may be used to endorse or promote products derived
     24       1.1     dsl  *    from this software without specific prior written permission.
     25       1.1     dsl  *
     26       1.1     dsl  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27       1.1     dsl  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28       1.1     dsl  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29       1.1     dsl  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30       1.1     dsl  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31       1.1     dsl  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32       1.1     dsl  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33       1.1     dsl  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34       1.1     dsl  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35       1.1     dsl  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36       1.1     dsl  * POSSIBILITY OF SUCH DAMAGE.
     37       1.1     dsl  */
     38       1.1     dsl 
     39      1.12   lukem #if HAVE_NBTOOL_CONFIG_H
     40      1.12   lukem #include "nbtool_config.h"
     41      1.12   lukem #endif
     42      1.12   lukem 
     43       1.1     dsl #include <sys/cdefs.h>
     44      1.12   lukem #if !defined(__lint)
     45  1.15.2.1    tron __RCSID("$NetBSD: i386.c,v 1.15.2.1 2004/06/22 07:20:18 tron Exp $");
     46      1.13   lukem #endif /* !__lint */
     47       1.1     dsl 
     48       1.1     dsl #include <sys/param.h>
     49       1.1     dsl 
     50       1.1     dsl #include <assert.h>
     51       1.1     dsl #include <err.h>
     52       1.5   bjh21 #include <md5.h>
     53       1.1     dsl #include <stddef.h>
     54       1.1     dsl #include <stdio.h>
     55       1.1     dsl #include <stdlib.h>
     56       1.1     dsl #include <string.h>
     57       1.1     dsl #include <unistd.h>
     58       1.1     dsl 
     59       1.1     dsl #include "installboot.h"
     60       1.1     dsl 
     61       1.1     dsl int
     62       1.1     dsl i386_setboot(ib_params *params)
     63       1.1     dsl {
     64      1.11   lukem 	int		retval, i, bpbsize;
     65      1.11   lukem 	uint8_t		*bootstrapbuf;
     66  1.15.2.1    tron 	u_int		bootstrapsize;
     67       1.1     dsl 	ssize_t		rv;
     68       1.1     dsl 	uint32_t	magic;
     69       1.9   lukem 	struct x86_boot_params	*bp;
     70       1.9   lukem 	struct mbr_sector	mbr;
     71       1.1     dsl 
     72       1.1     dsl 	assert(params != NULL);
     73       1.1     dsl 	assert(params->fsfd != -1);
     74       1.1     dsl 	assert(params->filesystem != NULL);
     75       1.1     dsl 	assert(params->s1fd != -1);
     76       1.1     dsl 	assert(params->stage1 != NULL);
     77       1.1     dsl 
     78       1.1     dsl 	retval = 0;
     79       1.1     dsl 	bootstrapbuf = NULL;
     80       1.1     dsl 
     81       1.2     dsl 	/*
     82       1.2     dsl 	 * There is only 8k of space in a UFSv1 partition (and ustarfs)
     83       1.2     dsl 	 * so ensure we don't splat over anything important.
     84       1.2     dsl 	 */
     85       1.2     dsl 	if (params->s1stat.st_size > 8192) {
     86       1.2     dsl 		warnx("stage1 bootstrap `%s' is larger than 8192 bytes",
     87       1.2     dsl 			params->stage1);
     88       1.9   lukem 		goto done;
     89       1.9   lukem 	}
     90       1.9   lukem 
     91       1.9   lukem 	/*
     92       1.9   lukem 	 * Read in the existing MBR.
     93       1.9   lukem 	 */
     94       1.9   lukem 	rv = pread(params->fsfd, &mbr, sizeof(mbr), MBR_BBSECTOR);
     95       1.9   lukem 	if (rv == -1) {
     96       1.9   lukem 		warn("Reading `%s'", params->filesystem);
     97       1.9   lukem 		goto done;
     98       1.9   lukem 	} else if (rv != sizeof(mbr)) {
     99       1.9   lukem 		warnx("Reading `%s': short read", params->filesystem);
    100       1.9   lukem 		goto done;
    101       1.1     dsl 	}
    102      1.10   lukem 	if (mbr.mbr_magic != le16toh(MBR_MAGIC)) {
    103       1.9   lukem 		if (params->flags & IB_VERBOSE) {
    104       1.9   lukem 			printf(
    105       1.9   lukem 		    "Ignoring MBR with invalid magic in sector 0 of `%s'\n",
    106       1.9   lukem 			    params->filesystem);
    107       1.9   lukem 		}
    108       1.9   lukem 		memset(&mbr, 0, sizeof(mbr));
    109       1.9   lukem 	}
    110       1.9   lukem 
    111       1.1     dsl 	/*
    112       1.1     dsl 	 * Allocate a buffer, with space to round up the input file
    113       1.1     dsl 	 * to the next block size boundary, and with space for the boot
    114       1.1     dsl 	 * block.
    115       1.1     dsl 	 */
    116       1.1     dsl 	bootstrapsize = roundup(params->s1stat.st_size, 512);
    117       1.1     dsl 
    118       1.1     dsl 	bootstrapbuf = malloc(bootstrapsize);
    119       1.1     dsl 	if (bootstrapbuf == NULL) {
    120       1.1     dsl 		warn("Allocating %u bytes",  bootstrapsize);
    121       1.1     dsl 		goto done;
    122       1.1     dsl 	}
    123       1.1     dsl 	memset(bootstrapbuf, 0, bootstrapsize);
    124       1.1     dsl 
    125       1.9   lukem 	/*
    126       1.9   lukem 	 * Read the file into the buffer.
    127       1.9   lukem 	 */
    128       1.1     dsl 	rv = pread(params->s1fd, bootstrapbuf, params->s1stat.st_size, 0);
    129       1.1     dsl 	if (rv == -1) {
    130       1.1     dsl 		warn("Reading `%s'", params->stage1);
    131       1.9   lukem 		goto done;
    132       1.1     dsl 	} else if (rv != params->s1stat.st_size) {
    133       1.1     dsl 		warnx("Reading `%s': short read", params->stage1);
    134       1.9   lukem 		goto done;
    135       1.1     dsl 	}
    136       1.1     dsl 
    137       1.1     dsl 	magic = *(uint32_t *)(bootstrapbuf + 512 * 2 + 4);
    138       1.7     dsl 	if (magic != htole32(X86_BOOT_MAGIC_1)) {
    139       1.1     dsl 		warnx("Invalid magic in stage1 boostrap %x != %x",
    140       1.7     dsl 			magic, htole32(X86_BOOT_MAGIC_1));
    141       1.2     dsl 		goto done;
    142       1.2     dsl 	}
    143       1.2     dsl 
    144       1.9   lukem 	/*
    145      1.11   lukem 	 * Determine size of BIOS Parameter Block (BPB) to copy from
    146      1.11   lukem 	 * original MBR to the temporary buffer by examining the first
    147      1.11   lukem 	 * few instruction in the new bootblock.  Supported values:
    148      1.11   lukem 	 *	eb 3c 90	jmp ENDOF(mbr_bpbFAT16)+1, nop
    149      1.11   lukem 	 *	eb 58 90	jmp ENDOF(mbr_bpbFAT32)+1, nop
    150      1.11   lukem 	 *      (anything else)	; don't preserve
    151      1.11   lukem 	 */
    152      1.11   lukem 	bpbsize = 0;
    153      1.11   lukem 	if (bootstrapbuf[0] == 0xeb && bootstrapbuf[2] == 0x90 &&
    154      1.11   lukem 	    (bootstrapbuf[1] == 0x3c || bootstrapbuf[1] == 0x58))
    155      1.11   lukem 		bpbsize = bootstrapbuf[1] + 2 - MBR_BPB_OFFSET;
    156      1.11   lukem 
    157      1.11   lukem 	/*
    158      1.15   lukem 	 * Ensure bootxx hasn't got any code or data (i.e, non-zero bytes) in
    159      1.11   lukem 	 * the partition table.
    160       1.9   lukem 	 */
    161       1.9   lukem 	for (i = 0; i < sizeof(mbr.mbr_parts); i++) {
    162       1.9   lukem 		if (*(uint8_t *)(bootstrapbuf + MBR_PART_OFFSET + i) != 0) {
    163       1.9   lukem 			warnx(
    164       1.9   lukem 		    "Partition table has non-zero byte at offset %d in `%s'",
    165       1.9   lukem 			    MBR_PART_OFFSET + i, params->stage1);
    166       1.9   lukem 			goto done;
    167       1.9   lukem 		}
    168       1.9   lukem 	}
    169       1.9   lukem 
    170       1.9   lukem 	/*
    171       1.9   lukem 	 * Copy the BPB and the partition table from the original MBR to the
    172       1.9   lukem 	 * temporary buffer so that they're written back to the fs.
    173       1.9   lukem 	 */
    174      1.11   lukem 	if (bpbsize != 0) {
    175      1.11   lukem 		if (params->flags & IB_VERBOSE)
    176      1.11   lukem 			printf("Preserving %d (%#x) bytes of the BPB\n",
    177      1.11   lukem 			    bpbsize, bpbsize);
    178      1.11   lukem 		memcpy(bootstrapbuf + MBR_BPB_OFFSET, &mbr.mbr_bpb, bpbsize);
    179      1.11   lukem 	}
    180       1.9   lukem 	memcpy(bootstrapbuf + MBR_PART_OFFSET, &mbr.mbr_parts,
    181       1.9   lukem 	    sizeof(mbr.mbr_parts));
    182       1.9   lukem 
    183       1.9   lukem 	/*
    184      1.15   lukem 	 * Fill in any user-specified options into the
    185      1.15   lukem 	 *	struct x86_boot_params
    186      1.15   lukem 	 * that's 8 bytes in from the start of the third sector.
    187      1.15   lukem 	 * See sys/arch/i386/stand/bootxx/bootxx.S for more information.
    188       1.9   lukem 	 */
    189       1.2     dsl 	bp = (void *)(bootstrapbuf + 512 * 2 + 8);
    190       1.3     dsl 	if (le32toh(bp->bp_length) < sizeof *bp) {
    191       1.2     dsl 		warnx("Patch area in stage1 bootstrap is too small");
    192       1.1     dsl 		goto done;
    193       1.2     dsl 	}
    194       1.2     dsl 	if (params->flags & IB_TIMEOUT)
    195       1.3     dsl 		bp->bp_timeout = htole32(params->timeout);
    196       1.2     dsl 	if (params->flags & IB_RESETVIDEO)
    197       1.9   lukem 		bp->bp_flags |= htole32(X86_BP_FLAGS_RESET_VIDEO);
    198       1.2     dsl 	if (params->flags & IB_CONSPEED)
    199       1.3     dsl 		bp->bp_conspeed = htole32(params->conspeed);
    200       1.2     dsl 	if (params->flags & IB_CONSOLE) {
    201       1.2     dsl 		static const char *names[] = {
    202       1.2     dsl 			"pc", "com0", "com1", "com2", "com3",
    203       1.2     dsl 			"com0kbd", "com1kbd", "com2kbd", "com3kbd",
    204       1.2     dsl 			NULL };
    205       1.2     dsl 		for (i = 0; ; i++) {
    206       1.2     dsl 			if (names[i] == NULL) {
    207       1.2     dsl 				warnx("invalid console name, valid names are:");
    208       1.2     dsl 				fprintf(stderr, "\t%s", names[0]);
    209       1.2     dsl 				for (i = 1; names[i] != NULL; i++)
    210       1.2     dsl 					fprintf(stderr, ", %s", names[i]);
    211       1.6  petrov 				fprintf(stderr, "\n");
    212       1.2     dsl 				goto done;
    213       1.2     dsl 			}
    214       1.2     dsl 			if (strcmp(names[i], params->console) == 0)
    215       1.2     dsl 				break;
    216       1.2     dsl 		}
    217       1.3     dsl 		bp->bp_consdev = htole32(i);
    218       1.2     dsl 	}
    219       1.2     dsl 	if (params->flags & IB_PASSWORD) {
    220       1.2     dsl 		MD5_CTX md5ctx;
    221       1.2     dsl 		MD5Init(&md5ctx);
    222       1.2     dsl 		MD5Update(&md5ctx, params->password, strlen(params->password));
    223       1.2     dsl 		MD5Final(bp->bp_password, &md5ctx);
    224       1.9   lukem 		bp->bp_flags |= htole32(X86_BP_FLAGS_PASSWORD);
    225       1.1     dsl 	}
    226      1.14     dsl 	if (params->flags & IB_KEYMAP)
    227      1.14     dsl 		strlcpy(bp->bp_keymap, params->keymap, sizeof bp->bp_keymap);
    228       1.1     dsl 
    229       1.1     dsl 	if (params->flags & IB_NOWRITE) {
    230       1.1     dsl 		retval = 1;
    231       1.1     dsl 		goto done;
    232       1.1     dsl 	}
    233       1.1     dsl 
    234       1.9   lukem 	/*
    235       1.9   lukem 	 * Write MBR code to sector zero.
    236       1.9   lukem 	 */
    237       1.1     dsl 	rv = pwrite(params->fsfd, bootstrapbuf, 512, 0);
    238       1.1     dsl 	if (rv == -1) {
    239       1.1     dsl 		warn("Writing `%s'", params->filesystem);
    240       1.1     dsl 		goto done;
    241       1.1     dsl 	} else if (rv != 512) {
    242       1.1     dsl 		warnx("Writing `%s': short write", params->filesystem);
    243       1.1     dsl 		goto done;
    244       1.1     dsl 	}
    245       1.1     dsl 
    246       1.9   lukem 	/*
    247       1.9   lukem 	 * Skip disklabel in sector 1 and write bootxx to sectors 2..N.
    248       1.9   lukem 	 */
    249       1.1     dsl 	rv = pwrite(params->fsfd, bootstrapbuf + 512 * 2,
    250       1.1     dsl 		    bootstrapsize - 512 * 2, 512 * 2);
    251       1.1     dsl 	if (rv == -1) {
    252       1.1     dsl 		warn("Writing `%s'", params->filesystem);
    253       1.1     dsl 		goto done;
    254       1.1     dsl 	} else if (rv != bootstrapsize - 512 * 2) {
    255       1.1     dsl 		warnx("Writing `%s': short write", params->filesystem);
    256       1.1     dsl 		goto done;
    257       1.1     dsl 	}
    258       1.1     dsl 
    259       1.1     dsl 	retval = 1;
    260       1.1     dsl 
    261       1.1     dsl  done:
    262       1.1     dsl 	if (bootstrapbuf)
    263       1.1     dsl 		free(bootstrapbuf);
    264       1.1     dsl 	return retval;
    265       1.1     dsl }
    266