1 /* $OpenBSD: i386_installboot.c,v 1.38 2020/07/22 05:06:38 deraadt Exp $ */ 2 /* $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */ 3 4 /* 5 * Copyright (c) 2013 Pedro Martelletto 6 * Copyright (c) 2011 Joel Sing <jsing@openbsd.org> 7 * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com> 8 * Copyright (c) 1997 Michael Shalayeff 9 * Copyright (c) 1994 Paul Kranenburg 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by Paul Kranenburg. 23 * 4. The name of the author may not be used to endorse or promote products 24 * derived from this software without specific prior written permission 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #define ELFSIZE 32 39 40 #include <sys/param.h> /* DEV_BSIZE */ 41 #include <sys/disklabel.h> 42 #include <sys/dkio.h> 43 #include <sys/ioctl.h> 44 #include <sys/mount.h> 45 #include <sys/reboot.h> 46 #include <sys/stat.h> 47 #include <sys/sysctl.h> 48 #include <sys/time.h> 49 50 #include <ufs/ufs/dinode.h> 51 #include <ufs/ufs/dir.h> 52 #include <ufs/ffs/fs.h> 53 54 #include <machine/cpu.h> 55 #include <machine/biosvar.h> 56 57 #include <elf.h> 58 #include <err.h> 59 #include <errno.h> 60 #include <fcntl.h> 61 #include <nlist.h> 62 #include <stdlib.h> 63 #include <stdio.h> 64 #include <stdint.h> 65 #include <string.h> 66 #include <unistd.h> 67 #include <util.h> 68 #include <uuid.h> 69 70 #include "installboot.h" 71 #include "i386_installboot.h" 72 73 char *bootldr; 74 75 char *blkstore; 76 size_t blksize; 77 78 struct sym_data pbr_symbols[] = { 79 {"_fs_bsize_p", 2}, 80 {"_fs_bsize_s", 2}, 81 {"_fsbtodb", 1}, 82 {"_p_offset", 4}, 83 {"_inodeblk", 4}, 84 {"_inodedbl", 4}, 85 {"_nblocks", 2}, 86 {"_blkincr", 1}, 87 {NULL} 88 }; 89 90 static void devread(int, void *, daddr_t, size_t, char *); 91 static u_int findopenbsd(int, struct disklabel *); 92 static int getbootparams(char *, int, struct disklabel *); 93 static char *loadproto(char *, long *); 94 static int gpt_chk_mbr(struct dos_partition *, u_int64_t); 95 static int sbchk(struct fs *, daddr_t); 96 static void sbread(int, daddr_t, struct fs **, char *); 97 98 static const daddr_t sbtry[] = SBLOCKSEARCH; 99 100 /* 101 * Read information about /boot's inode and filesystem parameters, then 102 * put biosboot (partition boot record) on the target drive with these 103 * parameters patched in. 104 */ 105 106 void 107 md_init(void) 108 { 109 stages = 2; 110 stage1 = "/usr/mdec/biosboot"; 111 stage2 = "/usr/mdec/boot"; 112 113 bootldr = "/boot"; 114 } 115 116 void 117 md_loadboot(void) 118 { 119 /* Load prototype boot blocks. */ 120 if ((blkstore = loadproto(stage1, &blksize)) == NULL) 121 exit(1); 122 123 /* XXX - Paranoia: Make sure size is aligned! */ 124 if (blksize & (DEV_BSIZE - 1)) 125 errx(1, "proto %s bad size=%ld", stage1, blksize); 126 127 if (blksize > SBSIZE - DEV_BSIZE) 128 errx(1, "proto bootblocks too big"); 129 } 130 131 void 132 md_installboot(int devfd, char *dev) 133 { 134 struct disklabel dl; 135 int part; 136 137 /* Get and check disklabel. */ 138 if (ioctl(devfd, DIOCGDINFO, &dl) == -1) 139 err(1, "disklabel: %s", dev); 140 if (dl.d_magic != DISKMAGIC) 141 errx(1, "bad disklabel magic=0x%08x", dl.d_magic); 142 143 /* Warn on unknown disklabel types. */ 144 if (dl.d_type == 0) 145 warnx("disklabel type unknown"); 146 147 part = findgptefisys(devfd, &dl); 148 if (part != -1) { 149 write_filesystem(&dl, (char)part); 150 return; 151 } 152 153 bootldr = fileprefix(root, bootldr); 154 if (bootldr == NULL) 155 exit(1); 156 if (verbose) 157 fprintf(stderr, "%s %s to %s\n", 158 (nowrite ? "would copy" : "copying"), stage2, bootldr); 159 if (!nowrite) 160 if (filecopy(stage2, bootldr) == -1) 161 exit(1); 162 163 /* Get bootstrap parameters to patch into proto. */ 164 if (getbootparams(bootldr, devfd, &dl) != 0) 165 exit(1); 166 167 /* Write boot blocks to device. */ 168 write_bootblocks(devfd, dev, &dl); 169 } 170 171 void 172 write_bootblocks(int devfd, char *dev, struct disklabel *dl) 173 { 174 struct stat sb; 175 u_int8_t *secbuf; 176 u_int start = 0; 177 178 /* Write patched proto bootblock(s) into the superblock. */ 179 if (fstat(devfd, &sb) == -1) 180 err(1, "fstat: %s", dev); 181 182 if (!S_ISCHR(sb.st_mode)) 183 errx(1, "%s: not a character device", dev); 184 185 /* Patch the parameters into the proto bootstrap sector. */ 186 pbr_set_symbols(stage1, blkstore, pbr_symbols); 187 188 if (!nowrite) { 189 /* Sync filesystems (to clean in-memory superblock?). */ 190 sync(); sleep(1); 191 } 192 193 /* 194 * Find OpenBSD partition. Floppies are special, getting an 195 * everything-in-one /boot starting at sector 0. 196 */ 197 if (dl->d_type != DTYPE_FLOPPY) { 198 start = findopenbsd(devfd, dl); 199 if (start == (u_int)-1) 200 errx(1, "no OpenBSD partition"); 201 } 202 203 if (verbose) 204 fprintf(stderr, "%s will be written at sector %u\n", 205 stage1, start); 206 207 if (start + (blksize / dl->d_secsize) > BOOTBIOS_MAXSEC) 208 warnx("%s extends beyond sector %u. OpenBSD might not boot.", 209 stage1, BOOTBIOS_MAXSEC); 210 211 if (!nowrite) { 212 secbuf = calloc(1, dl->d_secsize); 213 if (pread(devfd, secbuf, dl->d_secsize, (off_t)start * 214 dl->d_secsize) != dl->d_secsize) 215 err(1, "pread boot sector"); 216 bcopy(blkstore, secbuf, blksize); 217 if (pwrite(devfd, secbuf, dl->d_secsize, (off_t)start * 218 dl->d_secsize) != dl->d_secsize) 219 err(1, "pwrite bootstrap"); 220 free(secbuf); 221 } 222 } 223 224 void 225 write_filesystem(struct disklabel *dl, char part) 226 { 227 static char *fsckfmt = "/sbin/fsck_msdos %s >/dev/null"; 228 static char *newfsfmt ="/sbin/newfs_msdos %s >/dev/null"; 229 struct msdosfs_args args; 230 char cmd[60]; 231 char dst[PATH_MAX]; 232 char *src; 233 size_t mntlen, pathlen, srclen; 234 int rslt; 235 236 src = NULL; 237 238 /* Create directory for temporary mount point. */ 239 strlcpy(dst, "/tmp/installboot.XXXXXXXXXX", sizeof(dst)); 240 if (mkdtemp(dst) == NULL) 241 err(1, "mkdtemp('%s') failed", dst); 242 mntlen = strlen(dst); 243 244 /* Mount <duid>.<part> as msdos filesystem. */ 245 memset(&args, 0, sizeof(args)); 246 rslt = asprintf(&args.fspec, 247 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 248 dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3], 249 dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7], 250 part); 251 if (rslt == -1) { 252 warn("bad special device"); 253 goto rmdir; 254 } 255 256 args.export_info.ex_root = -2; /* unchecked anyway on DOS fs */ 257 args.export_info.ex_flags = 0; 258 args.flags = MSDOSFSMNT_LONGNAME; 259 260 if (mount(MOUNT_MSDOS, dst, 0, &args) == -1) { 261 /* Try fsck'ing it. */ 262 rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec); 263 if (rslt >= sizeof(cmd)) { 264 warnx("can't build fsck command"); 265 rslt = -1; 266 goto rmdir; 267 } 268 rslt = system(cmd); 269 if (rslt == -1) { 270 warn("system('%s') failed", cmd); 271 goto rmdir; 272 } 273 if (mount(MOUNT_MSDOS, dst, 0, &args) == -1) { 274 /* Try newfs'ing it. */ 275 rslt = snprintf(cmd, sizeof(cmd), newfsfmt, 276 args.fspec); 277 if (rslt >= sizeof(cmd)) { 278 warnx("can't build newfs command"); 279 rslt = -1; 280 goto rmdir; 281 } 282 rslt = system(cmd); 283 if (rslt == -1) { 284 warn("system('%s') failed", cmd); 285 goto rmdir; 286 } 287 rslt = mount(MOUNT_MSDOS, dst, 0, &args); 288 if (rslt == -1) { 289 warn("unable to mount EFI System partition"); 290 goto rmdir; 291 } 292 } 293 } 294 295 /* Create "/efi/BOOT" directory in <duid>.<part>. */ 296 if (strlcat(dst, "/efi", sizeof(dst)) >= sizeof(dst)) { 297 rslt = -1; 298 warn("unable to build /efi directory"); 299 goto umount; 300 } 301 rslt = mkdir(dst, 0); 302 if (rslt == -1 && errno != EEXIST) { 303 warn("mkdir('%s') failed", dst); 304 goto umount; 305 } 306 if (strlcat(dst, "/BOOT", sizeof(dst)) >= sizeof(dst)) { 307 rslt = -1; 308 warn("unable to build /BOOT directory"); 309 goto umount; 310 } 311 rslt = mkdir(dst, 0); 312 if (rslt == -1 && errno != EEXIST) { 313 warn("mkdir('%s') failed", dst); 314 goto umount; 315 } 316 317 /* 318 * Copy BOOTIA32.EFI and BOOTX64.EFI to /efi/BOOT/. 319 * 320 * N.B.: BOOTIA32.EFI is longer than BOOTX64.EFI, so src can be reused! 321 */ 322 pathlen = strlen(dst); 323 if (strlcat(dst, "/BOOTIA32.EFI", sizeof(dst)) >= sizeof(dst)) { 324 rslt = -1; 325 warn("unable to build /BOOTIA32.EFI path"); 326 goto umount; 327 } 328 src = fileprefix(root, "/usr/mdec/BOOTIA32.EFI"); 329 if (src == NULL) { 330 rslt = -1; 331 goto umount; 332 } 333 srclen = strlen(src); 334 if (verbose) 335 fprintf(stderr, "%s %s to %s\n", 336 (nowrite ? "would copy" : "copying"), src, dst); 337 if (!nowrite) { 338 rslt = filecopy(src, dst); 339 if (rslt == -1) 340 goto umount; 341 } 342 src[srclen - strlen("/BOOTIA32.EFI")] = '\0'; 343 344 dst[pathlen] = '\0'; 345 if (strlcat(dst, "/BOOTX64.EFI", sizeof(dst)) >= sizeof(dst)) { 346 rslt = -1; 347 warn("unable to build /BOOTX64.EFI dst path"); 348 goto umount; 349 } 350 if (strlcat(src, "/BOOTX64.EFI", srclen+1) >= srclen+1) { 351 rslt = -1; 352 warn("unable to build /BOOTX64.EFI src path"); 353 goto umount; 354 } 355 if (verbose) 356 fprintf(stderr, "%s %s to %s\n", 357 (nowrite ? "would copy" : "copying"), src, dst); 358 if (!nowrite) { 359 rslt = filecopy(src, dst); 360 if (rslt == -1) 361 goto umount; 362 } 363 364 rslt = 0; 365 366 umount: 367 dst[mntlen] = '\0'; 368 if (unmount(dst, MNT_FORCE) == -1) 369 err(1, "unmount('%s') failed", dst); 370 371 rmdir: 372 free(args.fspec); 373 dst[mntlen] = '\0'; 374 if (rmdir(dst) == -1) 375 err(1, "rmdir('%s') failed", dst); 376 377 free(src); 378 379 if (rslt == -1) 380 exit(1); 381 } 382 383 u_int 384 findopenbsd(int devfd, struct disklabel *dl) 385 { 386 struct dos_mbr mbr; 387 u_int mbroff = DOSBBSECTOR; 388 u_int mbr_eoff = DOSBBSECTOR; /* Offset of extended part. */ 389 struct dos_partition *dp; 390 u_int8_t *secbuf; 391 u_int maxebr = DOS_MAXEBR, nextebr; 392 int i; 393 394 again: 395 if (!maxebr--) { 396 if (verbose) 397 fprintf(stderr, "Traversed more than %d Extended Boot " 398 "Records (EBRs)\n", DOS_MAXEBR); 399 return ((u_int)-1); 400 } 401 402 if (verbose) 403 fprintf(stderr, "%s boot record (%cBR) at sector %u\n", 404 (mbroff == DOSBBSECTOR) ? "master" : "extended", 405 (mbroff == DOSBBSECTOR) ? 'M' : 'E', mbroff); 406 407 if ((secbuf = malloc(dl->d_secsize)) == NULL) 408 err(1, NULL); 409 if (pread(devfd, secbuf, dl->d_secsize, (off_t)mbroff * dl->d_secsize) 410 < (ssize_t)sizeof(mbr)) 411 err(4, "can't pread boot record"); 412 bcopy(secbuf, &mbr, sizeof(mbr)); 413 free(secbuf); 414 415 if (mbr.dmbr_sign != DOSMBR_SIGNATURE) 416 errx(1, "invalid boot record signature (0x%04X) @ sector %u", 417 mbr.dmbr_sign, mbroff); 418 419 nextebr = 0; 420 for (i = 0; i < NDOSPART; i++) { 421 dp = &mbr.dmbr_parts[i]; 422 if (!dp->dp_size) 423 continue; 424 425 if (verbose) 426 fprintf(stderr, 427 "\tpartition %d: type 0x%02X offset %u size %u\n", 428 i, dp->dp_typ, dp->dp_start, dp->dp_size); 429 430 if (dp->dp_typ == DOSPTYP_OPENBSD) { 431 if (dp->dp_start > (dp->dp_start + mbroff)) 432 continue; 433 return (dp->dp_start + mbroff); 434 } 435 436 if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND || 437 dp->dp_typ == DOSPTYP_EXTENDL)) { 438 nextebr = dp->dp_start + mbr_eoff; 439 if (nextebr < dp->dp_start) 440 nextebr = (u_int)-1; 441 if (mbr_eoff == DOSBBSECTOR) 442 mbr_eoff = dp->dp_start; 443 } 444 } 445 446 if (nextebr && nextebr != (u_int)-1) { 447 mbroff = nextebr; 448 goto again; 449 } 450 451 return ((u_int)-1); 452 } 453 454 /* 455 * Returns 0 if the MBR with the provided partition array is a GPT protective 456 * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only 457 * one MBR partition, an EFI partition that either covers the whole disk or as 458 * much of it as is possible with a 32bit size field. 459 * 460 * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!** 461 */ 462 static int 463 gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) 464 { 465 struct dos_partition *dp2; 466 int efi, found, i; 467 u_int32_t psize; 468 469 found = efi = 0; 470 for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) { 471 if (dp2->dp_typ == DOSPTYP_UNUSED) 472 continue; 473 found++; 474 if (dp2->dp_typ != DOSPTYP_EFI) 475 continue; 476 psize = letoh32(dp2->dp_size); 477 if (psize == (dsize - 1) || 478 psize == UINT32_MAX) { 479 if (letoh32(dp2->dp_start) == 1) 480 efi++; 481 } 482 } 483 if (found == 1 && efi == 1) 484 return (0); 485 486 return (1); 487 } 488 489 int 490 findgptefisys(int devfd, struct disklabel *dl) 491 { 492 struct gpt_partition gp[NGPTPARTITIONS]; 493 struct gpt_header gh; 494 struct dos_partition dp[NDOSPART]; 495 struct uuid efisys_uuid; 496 const char efisys_uuid_code[] = GPT_UUID_EFI_SYSTEM; 497 off_t off; 498 ssize_t len; 499 u_int64_t start; 500 int i; 501 uint32_t orig_csum, new_csum; 502 uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec; 503 u_int8_t *secbuf; 504 505 /* Prepare EFI System UUID */ 506 uuid_dec_be(efisys_uuid_code, &efisys_uuid); 507 508 if ((secbuf = malloc(dl->d_secsize)) == NULL) 509 err(1, NULL); 510 511 /* Check that there is a protective MBR. */ 512 len = pread(devfd, secbuf, dl->d_secsize, 0); 513 if (len != dl->d_secsize) 514 err(4, "can't read mbr"); 515 memcpy(dp, &secbuf[DOSPARTOFF], sizeof(dp)); 516 if (gpt_chk_mbr(dp, DL_GETDSIZE(dl))) { 517 free(secbuf); 518 return (-1); 519 } 520 521 /* Check GPT Header. */ 522 off = dl->d_secsize; /* Read header from sector 1. */ 523 len = pread(devfd, secbuf, dl->d_secsize, off); 524 if (len != dl->d_secsize) 525 err(4, "can't pread gpt header"); 526 527 memcpy(&gh, secbuf, sizeof(gh)); 528 free(secbuf); 529 530 /* Check signature */ 531 if (letoh64(gh.gh_sig) != GPTSIGNATURE) 532 return (-1); 533 534 if (letoh32(gh.gh_rev) != GPTREVISION) 535 return (-1); 536 537 ghsize = letoh32(gh.gh_size); 538 if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) 539 return (-1); 540 541 /* Check checksum */ 542 orig_csum = gh.gh_csum; 543 gh.gh_csum = 0; 544 new_csum = crc32((unsigned char *)&gh, ghsize); 545 gh.gh_csum = orig_csum; 546 if (letoh32(orig_csum) != new_csum) 547 return (-1); 548 549 off = letoh64(gh.gh_part_lba) * dl->d_secsize; 550 ghpartsize = letoh32(gh.gh_part_size); 551 ghpartspersec = dl->d_secsize / ghpartsize; 552 ghpartnum = letoh32(gh.gh_part_num); 553 if ((secbuf = malloc(dl->d_secsize)) == NULL) 554 err(1, NULL); 555 for (i = 0; i < (ghpartnum + ghpartspersec - 1) / ghpartspersec; i++) { 556 len = pread(devfd, secbuf, dl->d_secsize, off); 557 if (len != dl->d_secsize) { 558 free(secbuf); 559 return (-1); 560 } 561 memcpy(gp + i * ghpartspersec, secbuf, 562 ghpartspersec * sizeof(struct gpt_partition)); 563 off += dl->d_secsize; 564 } 565 free(secbuf); 566 new_csum = crc32((unsigned char *)&gp, ghpartnum * ghpartsize); 567 if (new_csum != letoh32(gh.gh_part_csum)) 568 return (-1); 569 570 start = 0; 571 for (i = 0; i < ghpartnum && start == 0; i++) { 572 if (memcmp(&gp[i].gp_type, &efisys_uuid, 573 sizeof(struct uuid)) == 0) 574 start = letoh64(gp[i].gp_lba_start); 575 } 576 577 if (start) { 578 for (i = 0; i < MAXPARTITIONS; i++) { 579 if (DL_GETPSIZE(&dl->d_partitions[i]) > 0 && 580 DL_GETPOFFSET(&dl->d_partitions[i]) == start) 581 return ('a' + i); 582 } 583 } 584 585 return (-1); 586 } 587 588 /* 589 * Load the prototype boot sector (biosboot) into memory. 590 */ 591 static char * 592 loadproto(char *fname, long *size) 593 { 594 int fd; 595 size_t tdsize; /* text+data size */ 596 char *bp; 597 Elf_Ehdr eh; 598 Elf_Word phsize; 599 Elf_Phdr *ph; 600 601 if ((fd = open(fname, O_RDONLY)) == -1) 602 err(1, "%s", fname); 603 604 if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) 605 errx(1, "%s: read failed", fname); 606 607 if (!IS_ELF(eh)) 608 errx(1, "%s: bad magic: 0x%02x%02x%02x%02x", fname, 609 eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1], 610 eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]); 611 612 /* 613 * We have to include the exec header in the beginning of 614 * the buffer, and leave extra space at the end in case 615 * the actual write to disk wants to skip the header. 616 */ 617 618 /* Program load header. */ 619 if (eh.e_phnum != 1) 620 errx(1, "%s: %u ELF load sections (only support 1)", 621 fname, eh.e_phnum); 622 623 ph = reallocarray(NULL, eh.e_phnum, sizeof(Elf_Phdr)); 624 if (ph == NULL) 625 err(1, NULL); 626 phsize = eh.e_phnum * sizeof(Elf_Phdr); 627 628 if (pread(fd, ph, phsize, eh.e_phoff) != phsize) 629 errx(1, "%s: can't pread header", fname); 630 631 tdsize = ph->p_filesz; 632 633 /* 634 * Allocate extra space here because the caller may copy 635 * the boot block starting at the end of the exec header. 636 * This prevents reading beyond the end of the buffer. 637 */ 638 if ((bp = calloc(tdsize, 1)) == NULL) 639 err(1, NULL); 640 641 /* Read the rest of the file. */ 642 if (pread(fd, bp, tdsize, ph->p_offset) != (ssize_t)tdsize) 643 errx(1, "%s: pread failed", fname); 644 645 *size = tdsize; /* not aligned to DEV_BSIZE */ 646 647 close(fd); 648 return bp; 649 } 650 651 static void 652 devread(int fd, void *buf, daddr_t blk, size_t size, char *msg) 653 { 654 if (pread(fd, buf, size, dbtob((off_t)blk)) != (ssize_t)size) 655 err(1, "%s: devread: pread", msg); 656 } 657 658 /* 659 * Read information about /boot's inode, then put this and filesystem 660 * parameters from the superblock into pbr_symbols. 661 */ 662 static int 663 getbootparams(char *boot, int devfd, struct disklabel *dl) 664 { 665 int fd; 666 struct stat dsb, fsb; 667 struct statfs fssb; 668 struct partition *pp; 669 struct fs *fs; 670 char *sblock, *buf; 671 u_int blk, *ap; 672 int ndb; 673 int mib[3]; 674 size_t size; 675 dev_t dev; 676 int incr; 677 678 /* 679 * Open 2nd-level boot program and record enough details about 680 * where it is on the filesystem represented by `devfd' 681 * (inode block, offset within that block, and various filesystem 682 * parameters essentially taken from the superblock) for biosboot 683 * to be able to load it later. 684 */ 685 686 /* Make sure the (probably new) boot file is on disk. */ 687 sync(); sleep(1); 688 689 if ((fd = open(boot, O_RDONLY)) == -1) 690 err(1, "open: %s", boot); 691 692 if (fstatfs(fd, &fssb) == -1) 693 err(1, "statfs: %s", boot); 694 695 if (strncmp(fssb.f_fstypename, "ffs", MFSNAMELEN) && 696 strncmp(fssb.f_fstypename, "ufs", MFSNAMELEN) ) 697 errx(1, "%s: not on an FFS filesystem", boot); 698 699 #if 0 700 if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) 701 errx(1, "read: %s", boot); 702 703 if (!IS_ELF(eh)) { 704 errx(1, "%s: bad magic: 0x%02x%02x%02x%02x", 705 boot, 706 eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1], 707 eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]); 708 } 709 #endif 710 711 if (fsync(fd) != 0) 712 err(1, "fsync: %s", boot); 713 714 if (fstat(fd, &fsb) != 0) 715 err(1, "fstat: %s", boot); 716 717 if (fstat(devfd, &dsb) != 0) 718 err(1, "fstat: %d", devfd); 719 720 /* Check devices. */ 721 mib[0] = CTL_MACHDEP; 722 mib[1] = CPU_CHR2BLK; 723 mib[2] = dsb.st_rdev; 724 size = sizeof(dev); 725 if (sysctl(mib, 3, &dev, &size, NULL, 0) >= 0) { 726 if (fsb.st_dev / MAXPARTITIONS != dev / MAXPARTITIONS) 727 errx(1, "cross-device install"); 728 } 729 730 pp = &dl->d_partitions[DISKPART(fsb.st_dev)]; 731 close(fd); 732 733 if ((sblock = malloc(SBSIZE)) == NULL) 734 err(1, NULL); 735 736 sbread(devfd, DL_SECTOBLK(dl, pp->p_offset), &fs, sblock); 737 738 /* Read inode. */ 739 if ((buf = malloc(fs->fs_bsize)) == NULL) 740 err(1, NULL); 741 742 blk = fsbtodb(fs, ino_to_fsba(fs, fsb.st_ino)); 743 744 /* 745 * Have the inode. Figure out how many filesystem blocks (not disk 746 * sectors) there are for biosboot to load. 747 */ 748 devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset) + blk, 749 fs->fs_bsize, "inode"); 750 if (fs->fs_magic == FS_UFS2_MAGIC) { 751 struct ufs2_dinode *ip2 = (struct ufs2_dinode *)(buf) + 752 ino_to_fsbo(fs, fsb.st_ino); 753 ndb = howmany(ip2->di_size, fs->fs_bsize); 754 ap = (u_int *)ip2->di_db; 755 incr = sizeof(u_int32_t); 756 } else { 757 struct ufs1_dinode *ip1 = (struct ufs1_dinode *)(buf) + 758 ino_to_fsbo(fs, fsb.st_ino); 759 ndb = howmany(ip1->di_size, fs->fs_bsize); 760 ap = (u_int *)ip1->di_db; 761 incr = 0; 762 } 763 764 if (ndb <= 0) 765 errx(1, "No blocks to load"); 766 767 /* 768 * Now set the values that will need to go into biosboot 769 * (the partition boot record, a.k.a. the PBR). 770 */ 771 sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16)); 772 sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / 773 dl->d_secsize)); 774 775 /* 776 * fs_fsbtodb is the shift to convert fs_fsize to DEV_BSIZE. The 777 * ino_to_fsba() return value is the number of fs_fsize units. 778 * Calculate the shift to convert fs_fsize into physical sectors, 779 * which are added to p_offset to get the sector address BIOS 780 * will use. 781 * 782 * N.B.: ASSUMES fs_fsize is a power of 2 of d_secsize. 783 */ 784 sym_set_value(pbr_symbols, "_fsbtodb", 785 ffs(fs->fs_fsize / dl->d_secsize) - 1); 786 787 sym_set_value(pbr_symbols, "_p_offset", pp->p_offset); 788 sym_set_value(pbr_symbols, "_inodeblk", 789 ino_to_fsba(fs, fsb.st_ino)); 790 sym_set_value(pbr_symbols, "_inodedbl", 791 ((((char *)ap) - buf) + INODEOFF)); 792 sym_set_value(pbr_symbols, "_nblocks", ndb); 793 sym_set_value(pbr_symbols, "_blkincr", incr); 794 795 if (verbose) { 796 fprintf(stderr, "%s is %d blocks x %d bytes\n", 797 boot, ndb, fs->fs_bsize); 798 fprintf(stderr, "fs block shift %u; part offset %u; " 799 "inode block %lld, offset %u\n", 800 ffs(fs->fs_fsize / dl->d_secsize) - 1, 801 pp->p_offset, 802 ino_to_fsba(fs, fsb.st_ino), 803 (unsigned int)((((char *)ap) - buf) + INODEOFF)); 804 fprintf(stderr, "expecting %d-bit fs blocks (incr %d)\n", 805 incr ? 64 : 32, incr); 806 } 807 808 free (sblock); 809 free (buf); 810 811 return 0; 812 } 813 814 void 815 sym_set_value(struct sym_data *sym_list, char *sym, u_int32_t value) 816 { 817 struct sym_data *p; 818 819 for (p = sym_list; p->sym_name != NULL; p++) { 820 if (strcmp(p->sym_name, sym) == 0) 821 break; 822 } 823 824 if (p->sym_name == NULL) 825 errx(1, "%s: no such symbol", sym); 826 827 p->sym_value = value; 828 p->sym_set = 1; 829 } 830 831 /* 832 * Write the parameters stored in sym_list into the in-memory copy of 833 * the prototype biosboot (proto), ready for it to be written to disk. 834 */ 835 void 836 pbr_set_symbols(char *fname, char *proto, struct sym_data *sym_list) 837 { 838 struct sym_data *sym; 839 struct nlist *nl; 840 char *vp; 841 u_int32_t *lp; 842 u_int16_t *wp; 843 u_int8_t *bp; 844 845 for (sym = sym_list; sym->sym_name != NULL; sym++) { 846 if (!sym->sym_set) 847 errx(1, "%s not set", sym->sym_name); 848 849 /* Allocate space for 2; second is null-terminator for list. */ 850 nl = calloc(2, sizeof(struct nlist)); 851 if (nl == NULL) 852 err(1, NULL); 853 854 nl->n_name = sym->sym_name; 855 856 if (nlist_elf32(fname, nl) != 0) 857 errx(1, "%s: symbol %s not found", 858 fname, sym->sym_name); 859 860 if (nl->n_type != (N_TEXT)) 861 errx(1, "%s: %s: wrong type (%x)", 862 fname, sym->sym_name, nl->n_type); 863 864 /* Get a pointer to where the symbol's value needs to go. */ 865 vp = proto + nl->n_value; 866 867 switch (sym->sym_size) { 868 case 4: /* u_int32_t */ 869 lp = (u_int32_t *) vp; 870 *lp = sym->sym_value; 871 break; 872 case 2: /* u_int16_t */ 873 if (sym->sym_value >= 0x10000) /* out of range */ 874 errx(1, "%s: symbol out of range (%u)", 875 sym->sym_name, sym->sym_value); 876 wp = (u_int16_t *) vp; 877 *wp = (u_int16_t) sym->sym_value; 878 break; 879 case 1: /* u_int16_t */ 880 if (sym->sym_value >= 0x100) /* out of range */ 881 errx(1, "%s: symbol out of range (%u)", 882 sym->sym_name, sym->sym_value); 883 bp = (u_int8_t *) vp; 884 *bp = (u_int8_t) sym->sym_value; 885 break; 886 default: 887 errx(1, "%s: bad symbol size %d", 888 sym->sym_name, sym->sym_size); 889 /* NOTREACHED */ 890 } 891 892 free(nl); 893 } 894 } 895 896 static int 897 sbchk(struct fs *fs, daddr_t sbloc) 898 { 899 if (verbose) 900 fprintf(stderr, "looking for superblock at %lld\n", sbloc); 901 902 if (fs->fs_magic != FS_UFS2_MAGIC && fs->fs_magic != FS_UFS1_MAGIC) { 903 if (verbose) 904 fprintf(stderr, "bad superblock magic 0x%x\n", 905 fs->fs_magic); 906 return (0); 907 } 908 909 /* 910 * Looking for an FFS1 file system at SBLOCK_UFS2 will find the 911 * wrong superblock for file systems with 64k block size. 912 */ 913 if (fs->fs_magic == FS_UFS1_MAGIC && sbloc == SBLOCK_UFS2) { 914 if (verbose) 915 fprintf(stderr, "skipping ffs1 superblock at %lld\n", 916 sbloc); 917 return (0); 918 } 919 920 if (fs->fs_bsize <= 0 || fs->fs_bsize < sizeof(struct fs) || 921 fs->fs_bsize > MAXBSIZE) { 922 if (verbose) 923 fprintf(stderr, "invalid superblock block size %d\n", 924 fs->fs_bsize); 925 return (0); 926 } 927 928 if (fs->fs_sbsize <= 0 || fs->fs_sbsize > SBSIZE) { 929 if (verbose) 930 fprintf(stderr, "invalid superblock size %d\n", 931 fs->fs_sbsize); 932 return (0); 933 } 934 935 if (fs->fs_inopb <= 0) { 936 if (verbose) 937 fprintf(stderr, "invalid superblock inodes/block %d\n", 938 fs->fs_inopb); 939 return (0); 940 } 941 942 if (verbose) 943 fprintf(stderr, "found valid %s superblock\n", 944 fs->fs_magic == FS_UFS2_MAGIC ? "ffs2" : "ffs1"); 945 946 return (1); 947 } 948 949 static void 950 sbread(int fd, daddr_t poffset, struct fs **fs, char *sblock) 951 { 952 int i; 953 daddr_t sboff; 954 955 for (i = 0; sbtry[i] != -1; i++) { 956 sboff = sbtry[i] / DEV_BSIZE; 957 devread(fd, sblock, poffset + sboff, SBSIZE, "superblock"); 958 *fs = (struct fs *)sblock; 959 if (sbchk(*fs, sbtry[i])) 960 break; 961 } 962 963 if (sbtry[i] == -1) 964 errx(1, "couldn't find ffs superblock"); 965 } 966