1 /* $NetBSD: i386.c,v 1.28 2007/06/23 23:18:29 christos 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 #if HAVE_NBTOOL_CONFIG_H 40 #include "nbtool_config.h" 41 #endif 42 43 #include <sys/cdefs.h> 44 #if !defined(__lint) 45 __RCSID("$NetBSD: i386.c,v 1.28 2007/06/23 23:18:29 christos Exp $"); 46 #endif /* !__lint */ 47 48 #include <sys/param.h> 49 #ifndef HAVE_NBTOOL_CONFIG_H 50 #include <sys/ioctl.h> 51 #include <sys/dkio.h> 52 #endif 53 54 #include <assert.h> 55 #include <errno.h> 56 #include <err.h> 57 #include <md5.h> 58 #include <stddef.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 #include "installboot.h" 65 66 #define nelem(x) (sizeof (x)/sizeof *(x)) 67 68 static const struct console_name { 69 const char *name; /* Name of console selection */ 70 const int dev; /* value matching CONSDEV_* from sys/arch/i386/stand/lib/libi386.h */ 71 } consoles[] = { 72 { "pc", 0 /* CONSDEV_PC */ }, 73 { "com0", 1 /* CONSDEV_COM0 */ }, 74 { "com1", 2 /* CONSDEV_COM1 */ }, 75 { "com2", 3 /* CONSDEV_COM2 */ }, 76 { "com3", 4 /* CONSDEV_COM3 */ }, 77 { "com0kbd", 5 /* CONSDEV_COM0KBD */ }, 78 { "com1kbd", 6 /* CONSDEV_COM1KBD */ }, 79 { "com2kbd", 7 /* CONSDEV_COM2KBD */ }, 80 { "com3kbd", 8 /* CONSDEV_COM3KBD */ }, 81 { "auto", -1 /* CONSDEV_AUTO */ }, 82 }; 83 84 static int i386_setboot(ib_params *); 85 static int i386_editboot(ib_params *); 86 87 struct ib_mach ib_mach_i386 = 88 { "i386", i386_setboot, no_clearboot, i386_editboot, 89 IB_RESETVIDEO | IB_CONSOLE | IB_CONSPEED | IB_CONSADDR | 90 IB_KEYMAP | IB_PASSWORD | IB_TIMEOUT }; 91 92 struct ib_mach ib_mach_amd64 = 93 { "amd64", i386_setboot, no_clearboot, i386_editboot, 94 IB_RESETVIDEO | IB_CONSOLE | IB_CONSPEED | IB_CONSADDR | 95 IB_KEYMAP | IB_PASSWORD | IB_TIMEOUT }; 96 97 /* 98 * Attempting to write the 'labelsector' (or a sector near it - within 8k?) 99 * using the non-raw disk device fails silently. This can be detected (today) 100 * by doing a fsync() and a read back. 101 * This is very likely to affect installboot, indeed the code may need to 102 * be written into the 'labelsector' itself - especially on non-512 byte media. 103 * We do all writes with a read verify. 104 * If EROFS is returned we also try to enable writes to the label sector. 105 * (Maybe these functions should be in the generic part of installboot.) 106 */ 107 static int 108 pwrite_validate(int fd, const void *buf, size_t n_bytes, off_t offset) 109 { 110 void *r_buf; 111 ssize_t rv; 112 113 r_buf = malloc(n_bytes); 114 if (r_buf == NULL) 115 return -1; 116 rv = pwrite(fd, buf, n_bytes, offset); 117 if (rv == -1) { 118 free(r_buf); 119 return -1; 120 } 121 fsync(fd); 122 if (pread(fd, r_buf, rv, offset) == rv && memcmp(r_buf, buf, rv) == 0) 123 return rv; 124 errno = EROFS; 125 return -1; 126 } 127 128 static int 129 write_boot_area(ib_params *params, void *v_buf, int len) 130 { 131 int rv, i; 132 uint8_t *buf = v_buf; 133 134 /* 135 * Writing the 'label' sector (likely to be bytes 512-1023) could 136 * fail, so we try to avoid writing that area. 137 * Unfortunately, if we are accessing the raw disk, and the sector 138 * size is larger than 512 bytes that is also doomed. 139 * See how we get on.... 140 * 141 * NB: Even if the physical sector size is not 512, the space for 142 * the label is 512 bytes from the start of the disk. 143 * So all the '512' constants in these functions are correct. 144 */ 145 146 /* Write out first 512 bytes - the pbr code */ 147 rv = pwrite_validate(params->fsfd, buf, 512, 0); 148 if (rv == 512) { 149 /* That worked, do the rest */ 150 if (len == 512) 151 return 1; 152 len -= 512 * 2; 153 rv = pwrite_validate(params->fsfd, buf + 512 * 2, len, 512 * 2); 154 if (rv != len) 155 goto bad_write; 156 return 1; 157 } 158 if (rv != -1 || (errno != EINVAL && errno != EROFS)) 159 goto bad_write; 160 161 if (errno == EINVAL) { 162 /* Assume the failure was due to to the sector size > 512 */ 163 rv = pwrite_validate(params->fsfd, buf, len, 0); 164 if (rv == len) 165 return 1; 166 if (rv != -1 || (errno != EROFS)) 167 goto bad_write; 168 } 169 170 #ifdef DIOCWLABEL 171 /* Pesky label is protected, try to unprotect it */ 172 i = 1; 173 rv = ioctl(params->fsfd, DIOCWLABEL, &i); 174 if (rv != 0) { 175 warn("Cannot enable writes to the label sector"); 176 return 0; 177 } 178 /* Try again with label write-enabled */ 179 rv = pwrite_validate(params->fsfd, buf, len, 0); 180 181 /* Reset write-protext */ 182 i = 0; 183 ioctl(params->fsfd, DIOCWLABEL, &i); 184 if (rv == len) 185 return 1; 186 #endif 187 188 bad_write: 189 if (rv == -1) 190 warn("Writing `%s'", params->filesystem); 191 else 192 warnx("Writing `%s': short write, %u bytes", 193 params->filesystem, rv); 194 return 0; 195 } 196 197 static void 198 show_i386_boot_params(struct x86_boot_params *bpp) 199 { 200 size_t i; 201 202 printf("Boot options: "); 203 printf("timeout %d, ", le32toh(bpp->bp_timeout)); 204 printf("flags %x, ", le32toh(bpp->bp_flags)); 205 printf("speed %d, ", le32toh(bpp->bp_conspeed)); 206 printf("ioaddr %x, ", le32toh(bpp->bp_consaddr)); 207 for (i = 0; i < nelem(consoles); i++) { 208 if (consoles[i].dev == le32toh(bpp->bp_consdev)) 209 break; 210 } 211 if (i == nelem(consoles)) 212 printf("console %d\n", le32toh(bpp->bp_consdev)); 213 else 214 printf("console %s\n", consoles[i].name); 215 if (bpp->bp_keymap[0]) 216 printf(" keymap %s\n", bpp->bp_keymap); 217 } 218 219 static int 220 is_zero(const uint8_t *p, unsigned int len) 221 { 222 return len == 0 || (p[0] == 0 && memcmp(p, p + 1, len - 1) == 0); 223 } 224 225 static int 226 update_i386_boot_params(ib_params *params, struct x86_boot_params *bpp) 227 { 228 struct x86_boot_params bp; 229 int bplen; 230 size_t i; 231 232 bplen = le32toh(bpp->bp_length); 233 if (bplen > sizeof bp) 234 /* Ignore pad space in bootxx */ 235 bplen = sizeof bp; 236 237 /* Take (and update) local copy so we handle size mismatches */ 238 memset(&bp, 0, sizeof bp); 239 memcpy(&bp, bpp, bplen); 240 241 if (params->flags & IB_TIMEOUT) 242 bp.bp_timeout = htole32(params->timeout); 243 if (params->flags & IB_RESETVIDEO) 244 bp.bp_flags ^= htole32(X86_BP_FLAGS_RESET_VIDEO); 245 if (params->flags & IB_CONSPEED) 246 bp.bp_conspeed = htole32(params->conspeed); 247 if (params->flags & IB_CONSADDR) 248 bp.bp_consaddr = htole32(params->consaddr); 249 if (params->flags & IB_CONSOLE) { 250 for (i = 0; i < nelem(consoles); i++) 251 if (strcmp(consoles[i].name, params->console) == 0) 252 break; 253 254 if (i == nelem(consoles)) { 255 warnx("invalid console name, valid names are:"); 256 (void)fprintf(stderr, "\t%s", consoles[0].name); 257 for (i = 1; consoles[i].name != NULL; i++) 258 (void)fprintf(stderr, ", %s", consoles[i].name); 259 (void)fprintf(stderr, "\n"); 260 return 1; 261 } 262 bp.bp_consdev = htole32(consoles[i].dev); 263 } 264 if (params->flags & IB_PASSWORD) { 265 if (params->password[0]) { 266 MD5_CTX md5ctx; 267 MD5Init(&md5ctx); 268 MD5Update(&md5ctx, params->password, 269 strlen(params->password)); 270 MD5Final(bp.bp_password, &md5ctx); 271 bp.bp_flags |= htole32(X86_BP_FLAGS_PASSWORD); 272 } else { 273 memset(&bp.bp_password, 0, sizeof bp.bp_password); 274 bp.bp_flags &= ~htole32(X86_BP_FLAGS_PASSWORD); 275 } 276 } 277 if (params->flags & IB_KEYMAP) 278 strlcpy(bp.bp_keymap, params->keymap, sizeof bp.bp_keymap); 279 280 if (params->flags & (IB_NOWRITE | IB_VERBOSE)) 281 show_i386_boot_params(&bp); 282 283 /* Check we aren't trying to set anything we can't save */ 284 if (!is_zero((char *)&bp + bplen, sizeof bp - bplen)) { 285 warnx("Patch area in stage1 bootstrap is too small"); 286 return 1; 287 } 288 memcpy(bpp, &bp, bplen); 289 return 0; 290 } 291 292 static int 293 i386_setboot(ib_params *params) 294 { 295 unsigned int u; 296 ssize_t rv; 297 uint32_t *magic, expected_magic; 298 union { 299 struct mbr_sector mbr; 300 uint8_t b[8192]; 301 } disk_buf, bootstrap; 302 303 assert(params != NULL); 304 assert(params->fsfd != -1); 305 assert(params->filesystem != NULL); 306 assert(params->s1fd != -1); 307 assert(params->stage1 != NULL); 308 309 /* 310 * There is only 8k of space in a UFSv1 partition (and ustarfs) 311 * so ensure we don't splat over anything important. 312 */ 313 if (params->s1stat.st_size > sizeof bootstrap) { 314 warnx("stage1 bootstrap `%s' (%u bytes) is larger than 8192 bytes", 315 params->stage1, (unsigned int)params->s1stat.st_size); 316 return 0; 317 } 318 if (params->s1stat.st_size < 3 * 512 && params->s1stat.st_size != 512) { 319 warnx("stage1 bootstrap `%s' (%u bytes) is too small", 320 params->stage1, (unsigned int)params->s1stat.st_size); 321 return 0; 322 } 323 324 /* Read in the existing disk header and boot code */ 325 rv = pread(params->fsfd, &disk_buf, sizeof (disk_buf), 0); 326 if (rv != sizeof(disk_buf)) { 327 if (rv == -1) 328 warn("Reading `%s'", params->filesystem); 329 else 330 warnx("Reading `%s': short read, %ld bytes" 331 " (should be %ld)", params->filesystem, (long)rv, 332 (long)sizeof(disk_buf)); 333 return 0; 334 } 335 336 if (disk_buf.mbr.mbr_magic != le16toh(MBR_MAGIC)) { 337 if (params->flags & IB_VERBOSE) { 338 printf( 339 "Ignoring PBR with invalid magic in sector 0 of `%s'\n", 340 params->filesystem); 341 } 342 memset(&disk_buf, 0, 512); 343 } 344 345 /* Read the new bootstrap code. */ 346 rv = pread(params->s1fd, &bootstrap, params->s1stat.st_size, 0); 347 if (rv != params->s1stat.st_size) { 348 if (rv == -1) 349 warn("Reading `%s'", params->stage1); 350 else 351 warnx("Reading `%s': short read, %ld bytes" 352 " (should be %ld)", params->stage1, (long)rv, 353 (long)params->s1stat.st_size); 354 return 0; 355 } 356 357 /* 358 * The bootstrap code is either 512 bytes for booting FAT16, or best 359 * part of 8k (with bytes 512-1023 all zeros). 360 */ 361 if (params->s1stat.st_size == 512) { 362 /* Magic number is at end of pbr code */ 363 magic = (void *)(bootstrap.b + 512 - 16 + 4); 364 expected_magic = htole32(X86_BOOT_MAGIC_FAT); 365 } else { 366 /* Magic number is at start of sector following label */ 367 magic = (void *)(bootstrap.b + 512 * 2 + 4); 368 expected_magic = htole32(X86_BOOT_MAGIC_1); 369 /* 370 * For a variety of reasons we restrict our 'normal' partition 371 * boot code to a size which enable it to be used as mbr code. 372 * IMHO this is bugus (dsl). 373 */ 374 if (!is_zero(bootstrap.b + 512-2-64, 64)) { 375 warnx("Data in mbr partition table of new bootstrap"); 376 return 0; 377 } 378 if (!is_zero(bootstrap.b + 512, 512)) { 379 warnx("Data in label part of new bootstrap"); 380 return 0; 381 } 382 /* Copy mbr table and label from existing disk buffer */ 383 memcpy(bootstrap.b + 512-2-64, disk_buf.b + 512-2-64, 64); 384 memcpy(bootstrap.b + 512, disk_buf.b + 512, 512); 385 } 386 387 /* Validate the 'magic number' that marks the parameter block */ 388 if (*magic != expected_magic) { 389 warnx("Invalid magic in stage1 bootstrap %x != %x", 390 *magic, expected_magic); 391 return 0; 392 } 393 394 /* 395 * If the partion has a FAT (or NTFS) filesystem, then we must 396 * preserve the BIOS Parameter Block (BPB). 397 * It is also very likely that there isn't 8k of space available 398 * for (say) bootxx_msdos, and that blindly installing it will trash 399 * the FAT filesystem. 400 * To avoid this we check the number of 'reserved' sectors to ensure 401 * there there is enough space. 402 * Unfortunately newfs(8) doesn't (yet) splat the BPB (which is 403 * effectively the FAT superblock) when a filesystem is initailised 404 * so this code tends to complain rather too often, 405 * Specifying 'installboot -f' will delete the old BPB info. 406 */ 407 if (!(params->flags & IB_FORCE)) { 408 /* 409 * For FAT compatibility, the pbr code starts 'jmp xx; nop' 410 * followed by the BIOS Parameter Block (BPB). 411 * The 2nd byte (jump offset) is the size of the nop + BPB. 412 */ 413 if (bootstrap.b[0] != 0xeb || bootstrap.b[2] != 0x90) { 414 warnx("No BPB in new bootstrap %02x:%02x:%02x, use -f", 415 bootstrap.b[0], bootstrap.b[1], bootstrap.b[2]); 416 return 0; 417 } 418 419 /* Find size of old BPB, and copy into new bootcode */ 420 if (!is_zero(disk_buf.b + 3 + 8, disk_buf.b[1] - 1 - 8)) { 421 struct mbr_bpbFAT16 *bpb = (void *)(disk_buf.b + 3 + 8); 422 /* Check enough space before the FAT for the bootcode */ 423 u = le16toh(bpb->bpbBytesPerSec) 424 * le16toh(bpb->bpbResSectors); 425 if (u != 0 && u < params->s1stat.st_size) { 426 warnx("Insufficient reserved space before FAT (%u bytes available), use -f", u); 427 return 0; 428 } 429 /* Check we have enough space for the old bpb */ 430 if (disk_buf.b[1] > bootstrap.b[1]) { 431 /* old BPB is larger, allow if extra zeros */ 432 if (!is_zero(disk_buf.b + 2 + bootstrap.b[1], 433 disk_buf.b[1] - bootstrap.b[1])) { 434 warnx("Old BPB too big, use -f"); 435 return 0; 436 } 437 u = bootstrap.b[1]; 438 } else { 439 /* Old BPB is shorter, leave zero filled */ 440 u = disk_buf.b[1]; 441 } 442 memcpy(bootstrap.b + 2, disk_buf.b + 2, u); 443 } 444 } 445 446 /* 447 * Fill in any user-specified options into the 448 * struct x86_boot_params 449 * that follows the magic number. 450 * See sys/arch/i386/stand/bootxx/bootxx.S for more information. 451 */ 452 if (update_i386_boot_params(params, (void *)(magic + 1))) 453 return 0; 454 455 if (params->flags & IB_NOWRITE) { 456 return 1; 457 } 458 459 /* Copy new bootstrap data into disk buffer, ignoring label area */ 460 memcpy(&disk_buf, &bootstrap, 512); 461 if (params->s1stat.st_size > 512 * 2) { 462 memcpy(disk_buf.b + 2 * 512, bootstrap.b + 2 * 512, 463 params->s1stat.st_size - 2 * 512); 464 /* Zero pad to 512 byte sector boundary */ 465 memset(disk_buf.b + params->s1stat.st_size, 0, 466 (8192 - params->s1stat.st_size) & 511); 467 } 468 469 return write_boot_area(params, &disk_buf, sizeof disk_buf); 470 } 471 472 static int 473 i386_editboot(ib_params *params) 474 { 475 int retval; 476 uint8_t buf[512]; 477 ssize_t rv; 478 uint32_t magic; 479 uint32_t offset; 480 struct x86_boot_params *bpp; 481 482 assert(params != NULL); 483 assert(params->fsfd != -1); 484 assert(params->filesystem != NULL); 485 486 retval = 0; 487 488 /* 489 * Read in the existing bootstrap. 490 * Look in any of the first 4 sectors. 491 */ 492 493 bpp = NULL; 494 for (offset = 0; offset < 4 * 512; offset += 512) { 495 rv = pread(params->fsfd, &buf, sizeof buf, offset); 496 if (rv == -1) { 497 warn("Reading `%s'", params->filesystem); 498 goto done; 499 } else if (rv != sizeof buf) { 500 warnx("Reading `%s': short read", params->filesystem); 501 goto done; 502 } 503 504 /* Magic number is 4 bytes in (to allow for a jmps) */ 505 /* Also allow any of the magic numbers. */ 506 magic = le32toh(*(uint32_t *)(buf + 4)) | 0xf; 507 if (magic != (X86_BOOT_MAGIC_1 | 0xf)) 508 continue; 509 510 /* The parameters are just after the magic number */ 511 bpp = (void *)(buf + 8); 512 break; 513 } 514 if (bpp == NULL) { 515 warnx("Invalid magic in existing bootstrap"); 516 goto done; 517 } 518 519 /* 520 * Fill in any user-specified options into the 521 * struct x86_boot_params 522 * that's 8 bytes in from the start of the third sector. 523 * See sys/arch/i386/stand/bootxx/bootxx.S for more information. 524 */ 525 if (update_i386_boot_params(params, bpp)) 526 goto done; 527 528 if (params->flags & IB_NOWRITE) { 529 retval = 1; 530 goto done; 531 } 532 533 /* 534 * Write boot code back 535 */ 536 rv = pwrite(params->fsfd, buf, sizeof buf, offset); 537 if (rv == -1) { 538 warn("Writing `%s'", params->filesystem); 539 goto done; 540 } else if (rv != sizeof buf) { 541 warnx("Writing `%s': short write, %ld bytes (should be %ld)", 542 params->filesystem, (long)rv, (long)sizeof(buf)); 543 goto done; 544 } 545 546 retval = 1; 547 548 done: 549 return retval; 550 } 551