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