1 /* $NetBSD: i386.c,v 1.7 2003/07/04 07:45:06 dsl Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by David Laight. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #if defined(__RCSID) && !defined(__lint) 41 __RCSID("$NetBSD: i386.c,v 1.7 2003/07/04 07:45:06 dsl Exp $"); 42 #endif /* __RCSID && !__lint */ 43 44 #if HAVE_CONFIG_H 45 #include "config.h" 46 #endif 47 48 #include <sys/param.h> 49 50 #include <assert.h> 51 #include <err.h> 52 #include <md5.h> 53 #include <stddef.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <unistd.h> 58 59 #include "installboot.h" 60 61 int 62 i386_setboot(ib_params *params) 63 { 64 int retval; 65 char *bootstrapbuf; 66 uint bootstrapsize; 67 ssize_t rv; 68 uint32_t magic; 69 struct i386_boot_params *bp; 70 int i; 71 72 assert(params != NULL); 73 assert(params->fsfd != -1); 74 assert(params->filesystem != NULL); 75 assert(params->s1fd != -1); 76 assert(params->stage1 != NULL); 77 78 retval = 0; 79 bootstrapbuf = NULL; 80 81 /* 82 * There is only 8k of space in a UFSv1 partition (and ustarfs) 83 * so ensure we don't splat over anything important. 84 */ 85 if (params->s1stat.st_size > 8192) { 86 warnx("stage1 bootstrap `%s' is larger than 8192 bytes", 87 params->stage1); 88 return 0; 89 } 90 /* 91 * Allocate a buffer, with space to round up the input file 92 * to the next block size boundary, and with space for the boot 93 * block. 94 */ 95 bootstrapsize = roundup(params->s1stat.st_size, 512); 96 97 bootstrapbuf = malloc(bootstrapsize); 98 if (bootstrapbuf == NULL) { 99 warn("Allocating %u bytes", bootstrapsize); 100 goto done; 101 } 102 memset(bootstrapbuf, 0, bootstrapsize); 103 104 /* read the file into the buffer */ 105 rv = pread(params->s1fd, bootstrapbuf, params->s1stat.st_size, 0); 106 if (rv == -1) { 107 warn("Reading `%s'", params->stage1); 108 return 0; 109 } else if (rv != params->s1stat.st_size) { 110 warnx("Reading `%s': short read", params->stage1); 111 return 0; 112 } 113 114 magic = *(uint32_t *)(bootstrapbuf + 512 * 2 + 4); 115 if (magic != htole32(X86_BOOT_MAGIC_1)) { 116 warnx("Invalid magic in stage1 boostrap %x != %x", 117 magic, htole32(X86_BOOT_MAGIC_1)); 118 goto done; 119 } 120 121 /* Fill in any user-specified options */ 122 bp = (void *)(bootstrapbuf + 512 * 2 + 8); 123 if (le32toh(bp->bp_length) < sizeof *bp) { 124 warnx("Patch area in stage1 bootstrap is too small"); 125 goto done; 126 } 127 if (params->flags & IB_TIMEOUT) 128 bp->bp_timeout = htole32(params->timeout); 129 if (params->flags & IB_RESETVIDEO) 130 bp->bp_flags |= htole32(BP_RESET_VIDEO); 131 if (params->flags & IB_CONSPEED) 132 bp->bp_conspeed = htole32(params->conspeed); 133 if (params->flags & IB_CONSOLE) { 134 static const char *names[] = { 135 "pc", "com0", "com1", "com2", "com3", 136 "com0kbd", "com1kbd", "com2kbd", "com3kbd", 137 NULL }; 138 for (i = 0; ; i++) { 139 if (names[i] == NULL) { 140 warnx("invalid console name, valid names are:"); 141 fprintf(stderr, "\t%s", names[0]); 142 for (i = 1; names[i] != NULL; i++) 143 fprintf(stderr, ", %s", names[i]); 144 fprintf(stderr, "\n"); 145 goto done; 146 } 147 if (strcmp(names[i], params->console) == 0) 148 break; 149 } 150 bp->bp_consdev = htole32(i); 151 } 152 if (params->flags & IB_PASSWORD) { 153 MD5_CTX md5ctx; 154 MD5Init(&md5ctx); 155 MD5Update(&md5ctx, params->password, strlen(params->password)); 156 MD5Final(bp->bp_password, &md5ctx); 157 bp->bp_flags |= htole32(BP_PASSWORD); 158 } 159 160 if (params->flags & IB_NOWRITE) { 161 retval = 1; 162 goto done; 163 } 164 165 /* Write pbr code to sector zero */ 166 rv = pwrite(params->fsfd, bootstrapbuf, 512, 0); 167 if (rv == -1) { 168 warn("Writing `%s'", params->filesystem); 169 goto done; 170 } else if (rv != 512) { 171 warnx("Writing `%s': short write", params->filesystem); 172 goto done; 173 } 174 175 /* Skip disklabel and write bootxx to sectors 2 + */ 176 rv = pwrite(params->fsfd, bootstrapbuf + 512 * 2, 177 bootstrapsize - 512 * 2, 512 * 2); 178 if (rv == -1) { 179 warn("Writing `%s'", params->filesystem); 180 goto done; 181 } else if (rv != bootstrapsize - 512 * 2) { 182 warnx("Writing `%s': short write", params->filesystem); 183 goto done; 184 } 185 186 retval = 1; 187 188 done: 189 if (bootstrapbuf) 190 free(bootstrapbuf); 191 return retval; 192 } 193