1 /* 2 * Copyright (c) 1998 Robert Nordier 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are freely 6 * permitted provided that the above copyright notice and this 7 * paragraph and the following disclaimer are duplicated in all 8 * such forms. 9 * 10 * This software is provided "AS IS" and without any express or 11 * implied warranties, including, without limitation, the implied 12 * warranties of merchantability and fitness for a particular 13 * purpose. 14 */ 15 16 #include <sys/cdefs.h> 17 #include <stand.h> 18 19 #include <sys/param.h> 20 #include <sys/errno.h> 21 #include <sys/diskmbr.h> 22 #include <sys/vtoc.h> 23 #include <sys/disk.h> 24 #include <sys/reboot.h> 25 #include <sys/queue.h> 26 #include <sys/multiboot.h> 27 #include <sys/zfs_bootenv.h> 28 29 #include <machine/bootinfo.h> 30 #include <machine/elf.h> 31 #include <machine/pc/bios.h> 32 33 #include <stdarg.h> 34 #include <stdbool.h> 35 #include <stddef.h> 36 37 #include <a.out.h> 38 #include "bootstrap.h" 39 #include "libi386.h" 40 #include <btxv86.h> 41 42 #include "lib.h" 43 #include "rbx.h" 44 #include "cons.h" 45 #include "bootargs.h" 46 #include "disk.h" 47 #include "part.h" 48 #include "paths.h" 49 50 #include "libzfs.h" 51 52 #define ARGS 0x900 53 #define NOPT 15 54 #define NDEV 3 55 56 #define BIOS_NUMDRIVES 0x475 57 #define DRV_HARD 0x80 58 #define DRV_MASK 0x7f 59 60 #define TYPE_AD 0 61 #define TYPE_DA 1 62 #define TYPE_MAXHARD TYPE_DA 63 #define TYPE_FD 2 64 65 extern uint32_t _end; 66 67 /* 68 * Fake multiboot header to provide versioning and to pass 69 * partition start LBA. Partition is either GPT partition or 70 * VTOC slice. 71 */ 72 extern const struct multiboot_header mb_header; 73 extern uint64_t start_sector; 74 75 static const char optstr[NOPT] = "DhaCcdgmnpqrstv"; /* Also 'P', 'S' */ 76 static const unsigned char flags[NOPT] = { 77 RBX_DUAL, 78 RBX_SERIAL, 79 RBX_ASKNAME, 80 RBX_CDROM, 81 RBX_CONFIG, 82 RBX_KDB, 83 RBX_GDB, 84 RBX_MUTE, 85 RBX_NOINTR, 86 RBX_PAUSE, 87 RBX_QUIET, 88 RBX_DFLTROOT, 89 RBX_SINGLE, 90 RBX_TEXT_MODE, 91 RBX_VERBOSE 92 }; 93 uint32_t opts; 94 95 /* 96 * Paths to try loading before falling back to the boot2 prompt. 97 */ 98 #define PATH_ZFSLOADER "/boot/zfsloader" 99 static const struct string { 100 const char *p; 101 size_t len; 102 } loadpath[] = { 103 { PATH_LOADER, sizeof (PATH_LOADER) }, 104 { PATH_ZFSLOADER, sizeof (PATH_ZFSLOADER) } 105 }; 106 107 static const unsigned char dev_maj[NDEV] = {30, 4, 2}; 108 109 static struct i386_devdesc *bdev; 110 static char cmd[512]; 111 static char cmddup[512]; 112 static char kname[1024]; 113 static int comspeed = SIOSPD; 114 static struct bootinfo bootinfo; 115 static uint32_t bootdev; 116 static struct zfs_boot_args zfsargs; 117 118 extern vm_offset_t high_heap_base; 119 extern uint32_t bios_basemem, bios_extmem, high_heap_size; 120 121 static char *heap_top; 122 static char *heap_bottom; 123 124 static void i386_zfs_probe(void); 125 static void load(void); 126 static int parse_cmd(void); 127 128 struct arch_switch archsw; /* MI/MD interface boundary */ 129 static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */ 130 131 struct devsw *devsw[] = { 132 &bioshd, 133 &zfs_dev, 134 NULL 135 }; 136 137 struct fs_ops *file_system[] = { 138 &zfs_fsops, 139 &ufs_fsops, 140 &dosfs_fsops, 141 NULL 142 }; 143 144 caddr_t 145 ptov(uintptr_t x) 146 { 147 return (PTOV(x)); 148 } 149 150 int 151 main(void) 152 { 153 unsigned i; 154 int fd; 155 bool auto_boot; 156 bool nextboot = false; 157 struct disk_devdesc devdesc; 158 159 bios_getmem(); 160 161 if (high_heap_size > 0) { 162 heap_top = PTOV(high_heap_base + high_heap_size); 163 heap_bottom = PTOV(high_heap_base); 164 } else { 165 heap_bottom = (char *) 166 (roundup2(__base + (int32_t)&_end, 0x10000) - __base); 167 heap_top = (char *)PTOV(bios_basemem); 168 } 169 setheap(heap_bottom, heap_top); 170 171 /* 172 * Initialise the block cache. Set the upper limit. 173 */ 174 bcache_init(32768, 512); 175 176 archsw.arch_autoload = NULL; 177 archsw.arch_getdev = i386_getdev; 178 archsw.arch_copyin = NULL; 179 archsw.arch_copyout = NULL; 180 archsw.arch_readin = NULL; 181 archsw.arch_isainb = NULL; 182 archsw.arch_isaoutb = NULL; 183 archsw.arch_zfs_probe = i386_zfs_probe; 184 185 bootinfo.bi_version = BOOTINFO_VERSION; 186 bootinfo.bi_size = sizeof (bootinfo); 187 bootinfo.bi_basemem = bios_basemem / 1024; 188 bootinfo.bi_extmem = bios_extmem / 1024; 189 bootinfo.bi_memsizes_valid++; 190 bootinfo.bi_bios_dev = *(uint8_t *)PTOV(ARGS); 191 192 /* 193 * Set up fall back device name. bd_bios2unit() is not available yet. 194 */ 195 if (bootinfo.bi_bios_dev < 0x80) 196 snprintf(boot_devname, sizeof (boot_devname), "disk%d:", 197 bootinfo.bi_bios_dev); 198 else 199 snprintf(boot_devname, sizeof (boot_devname), "disk%d:", 200 bootinfo.bi_bios_dev - 0x80); 201 202 for (i = 0; devsw[i] != NULL; i++) 203 if (devsw[i]->dv_init != NULL) 204 (devsw[i]->dv_init)(); 205 206 disk_parsedev(&devdesc, boot_devname + 4, NULL); 207 208 bootdev = MAKEBOOTDEV(dev_maj[DEVT_DISK], devdesc.d_slice + 1, 209 devdesc.dd.d_unit, 210 devdesc.d_partition >= 0 ? devdesc.d_partition : 0xff); 211 212 /* 213 * zfs_fmtdev() can be called only after dv_init 214 */ 215 if (bdev != NULL && bdev->dd.d_dev->dv_type == DEVT_ZFS) { 216 /* set up proper device name string for ZFS */ 217 strncpy(boot_devname, zfs_fmtdev(bdev), sizeof (boot_devname)); 218 if (zfs_get_bootonce(bdev, OS_BOOTONCE, cmd, 219 sizeof (cmd)) == 0) { 220 nvlist_t *benv; 221 222 nextboot = true; 223 memcpy(cmddup, cmd, sizeof (cmd)); 224 if (parse_cmd()) { 225 printf("failed to parse bootonce command\n"); 226 exit(0); 227 } 228 if (!OPT_CHECK(RBX_QUIET)) 229 printf("zfs bootonce: %s\n", cmddup); 230 231 if (zfs_get_bootenv(bdev, &benv) == 0) { 232 nvlist_add_string(benv, OS_BOOTONCE_USED, 233 cmddup); 234 zfs_set_bootenv(bdev, benv); 235 } 236 /* Do not process this command twice */ 237 *cmd = 0; 238 } 239 } 240 241 /* now make sure we have bdev on all cases */ 242 free(bdev); 243 i386_getdev((void **)&bdev, boot_devname, NULL); 244 245 env_setenv("currdev", EV_VOLATILE, boot_devname, i386_setcurrdev, 246 env_nounset); 247 248 /* Process configuration file */ 249 setenv("screen-#rows", "24", 1); 250 auto_boot = true; 251 252 fd = open(PATH_CONFIG, O_RDONLY); 253 if (fd == -1) 254 fd = open(PATH_DOTCONFIG, O_RDONLY); 255 256 if (fd != -1) { 257 ssize_t cmdlen; 258 259 if ((cmdlen = read(fd, cmd, sizeof (cmd))) > 0) 260 cmd[cmdlen] = '\0'; 261 else 262 *cmd = '\0'; 263 close(fd); 264 } 265 266 if (*cmd) { 267 /* 268 * Note that parse_cmd() is destructive to cmd[] and we also 269 * want to honor RBX_QUIET option that could be present in 270 * cmd[]. 271 */ 272 memcpy(cmddup, cmd, sizeof (cmd)); 273 if (parse_cmd()) 274 auto_boot = false; 275 if (!OPT_CHECK(RBX_QUIET)) 276 printf("%s: %s\n", PATH_CONFIG, cmddup); 277 /* Do not process this command twice */ 278 *cmd = 0; 279 } 280 281 /* Do not risk waiting at the prompt forever. */ 282 if (nextboot && !auto_boot) 283 exit(0); 284 285 if (auto_boot && !*kname) { 286 /* 287 * Try to exec stage 3 boot loader. If interrupted by a 288 * keypress, or in case of failure, drop the user to the 289 * boot2 prompt.. 290 */ 291 auto_boot = false; 292 for (i = 0; i < nitems(loadpath); i++) { 293 memcpy(kname, loadpath[i].p, loadpath[i].len); 294 if (keyhit(3)) 295 break; 296 load(); 297 } 298 } 299 /* Reset to default */ 300 memcpy(kname, loadpath[0].p, loadpath[0].len); 301 302 /* Present the user with the boot2 prompt. */ 303 304 for (;;) { 305 if (!auto_boot || !OPT_CHECK(RBX_QUIET)) { 306 printf("\nillumos/x86 boot\n"); 307 printf("Default: %s%s\nboot: ", boot_devname, kname); 308 } 309 if (ioctrl & IO_SERIAL) 310 sio_flush(); 311 if (!auto_boot || keyhit(5)) 312 getstr(cmd, sizeof (cmd)); 313 else if (!auto_boot || !OPT_CHECK(RBX_QUIET)) 314 putchar('\n'); 315 auto_boot = false; 316 if (parse_cmd()) 317 putchar('\a'); 318 else 319 load(); 320 } 321 } 322 323 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 324 void 325 exit(int x) 326 { 327 __exit(x); 328 } 329 330 static void 331 load(void) 332 { 333 union { 334 struct exec ex; 335 Elf32_Ehdr eh; 336 } hdr; 337 static Elf32_Phdr ep[2]; 338 static Elf32_Shdr es[2]; 339 caddr_t p; 340 uint32_t addr, x; 341 int fd, fmt, i, j; 342 343 if ((fd = open(kname, O_RDONLY)) == -1) { 344 printf("\nCan't find %s\n", kname); 345 return; 346 } 347 if (read(fd, &hdr, sizeof (hdr)) != sizeof (hdr)) { 348 close(fd); 349 return; 350 } 351 if (N_GETMAGIC(hdr.ex) == ZMAGIC) { 352 fmt = 0; 353 } else if (IS_ELF(hdr.eh)) { 354 fmt = 1; 355 } else { 356 printf("Invalid %s\n", "format"); 357 close(fd); 358 return; 359 } 360 if (fmt == 0) { 361 addr = hdr.ex.a_entry & 0xffffff; 362 p = PTOV(addr); 363 lseek(fd, PAGE_SIZE, SEEK_SET); 364 if (read(fd, p, hdr.ex.a_text) != hdr.ex.a_text) { 365 close(fd); 366 return; 367 } 368 p += roundup2(hdr.ex.a_text, PAGE_SIZE); 369 if (read(fd, p, hdr.ex.a_data) != hdr.ex.a_data) { 370 close(fd); 371 return; 372 } 373 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 374 bootinfo.bi_symtab = VTOP(p); 375 memcpy(p, &hdr.ex.a_syms, sizeof (hdr.ex.a_syms)); 376 p += sizeof (hdr.ex.a_syms); 377 if (hdr.ex.a_syms) { 378 if (read(fd, p, hdr.ex.a_syms) != hdr.ex.a_syms) { 379 close(fd); 380 return; 381 } 382 p += hdr.ex.a_syms; 383 if (read(fd, p, sizeof (int)) != sizeof (int)) { 384 close(fd); 385 return; 386 } 387 x = *(uint32_t *)p; 388 p += sizeof (int); 389 x -= sizeof (int); 390 if (read(fd, p, x) != x) { 391 close(fd); 392 return; 393 } 394 p += x; 395 } 396 } else { 397 lseek(fd, hdr.eh.e_phoff, SEEK_SET); 398 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 399 if (read(fd, ep + j, sizeof (ep[0])) != 400 sizeof (ep[0])) { 401 close(fd); 402 return; 403 } 404 if (ep[j].p_type == PT_LOAD) 405 j++; 406 } 407 for (i = 0; i < 2; i++) { 408 p = PTOV(ep[i].p_paddr & 0xffffff); 409 lseek(fd, ep[i].p_offset, SEEK_SET); 410 if (read(fd, p, ep[i].p_filesz) != ep[i].p_filesz) { 411 close(fd); 412 return; 413 } 414 } 415 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 416 bootinfo.bi_symtab = VTOP(p); 417 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 418 lseek(fd, hdr.eh.e_shoff + 419 sizeof (es[0]) * (hdr.eh.e_shstrndx + 1), 420 SEEK_SET); 421 if (read(fd, &es, sizeof (es)) != sizeof (es)) { 422 close(fd); 423 return; 424 } 425 for (i = 0; i < 2; i++) { 426 memcpy(p, &es[i].sh_size, 427 sizeof (es[i].sh_size)); 428 p += sizeof (es[i].sh_size); 429 lseek(fd, es[i].sh_offset, SEEK_SET); 430 if (read(fd, p, es[i].sh_size) != 431 es[i].sh_size) { 432 close(fd); 433 return; 434 } 435 p += es[i].sh_size; 436 } 437 } 438 addr = hdr.eh.e_entry & 0xffffff; 439 } 440 close(fd); 441 442 bootinfo.bi_esymtab = VTOP(p); 443 bootinfo.bi_kernelname = VTOP(kname); 444 445 if (bdev->dd.d_dev->dv_type == DEVT_ZFS) { 446 zfsargs.size = sizeof (zfsargs); 447 zfsargs.pool = bdev->d_kind.zfs.pool_guid; 448 zfsargs.root = bdev->d_kind.zfs.root_guid; 449 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 450 bootdev, 451 KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG, 452 (uint32_t)bdev->d_kind.zfs.pool_guid, 453 (uint32_t)(bdev->d_kind.zfs.pool_guid >> 32), 454 VTOP(&bootinfo), 455 zfsargs); 456 } else { 457 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 458 bootdev, 0, 0, 0, VTOP(&bootinfo)); 459 } 460 } 461 462 static int 463 mount_root(char *arg) 464 { 465 char *root; 466 struct i386_devdesc *ddesc; 467 uint8_t part; 468 469 if (asprintf(&root, "%s:", arg) < 0) 470 return (1); 471 472 if (i386_getdev((void **)&ddesc, root, NULL)) { 473 free(root); 474 return (1); 475 } 476 477 /* we should have new device descriptor, free old and replace it. */ 478 free(bdev); 479 bdev = ddesc; 480 if (bdev->dd.d_dev->dv_type == DEVT_DISK) { 481 if (bdev->d_kind.biosdisk.partition == -1) 482 part = 0xff; 483 else 484 part = bdev->d_kind.biosdisk.partition; 485 bootdev = MAKEBOOTDEV(dev_maj[bdev->dd.d_dev->dv_type], 486 bdev->d_kind.biosdisk.slice + 1, 487 bdev->dd.d_unit, part); 488 bootinfo.bi_bios_dev = bd_unit2bios(bdev); 489 } 490 strncpy(boot_devname, root, sizeof (boot_devname)); 491 setenv("currdev", root, 1); 492 free(root); 493 return (0); 494 } 495 496 static void 497 fs_list(char *arg) 498 { 499 int fd; 500 struct dirent *d; 501 char line[80]; 502 503 fd = open(arg, O_RDONLY); 504 if (fd < 0) 505 return; 506 pager_open(); 507 while ((d = readdirfd(fd)) != NULL) { 508 sprintf(line, "%s\n", d->d_name); 509 if (pager_output(line)) 510 break; 511 } 512 pager_close(); 513 close(fd); 514 } 515 516 static int 517 parse_cmd(void) 518 { 519 char *arg = cmd; 520 char *ep, *p, *q; 521 const char *cp; 522 char line[80]; 523 int c, i; 524 525 while ((c = *arg++)) { 526 if (isspace(c)) 527 continue; 528 529 for (p = arg; *p != '\0' && !isspace(*p); p++) 530 ; 531 ep = p; 532 if (*p != '\0') 533 *p++ = '\0'; 534 if (c == '-') { 535 while ((c = *arg++)) { 536 if (isspace(c)) 537 break; 538 539 if (c == 'P') { 540 if (*(uint8_t *)PTOV(0x496) & 0x10) { 541 cp = "yes"; 542 } else { 543 opts |= OPT_SET(RBX_DUAL); 544 opts |= OPT_SET(RBX_SERIAL); 545 cp = "no"; 546 } 547 printf("Keyboard: %s\n", cp); 548 continue; 549 } else if (c == 'S') { 550 char *end; 551 552 errno = 0; 553 i = strtol(arg, &end, 10); 554 if (errno == 0 && 555 *arg != '\0' && 556 *end == '\0' && 557 i > 0 && 558 i <= 115200) { 559 comspeed = i; 560 break; 561 } else { 562 printf("warning: bad value for " 563 "speed: %s\n", arg); 564 } 565 arg = end; 566 /* 567 * Fall through to error below 568 * ('S' not in optstr[]). 569 */ 570 } 571 for (i = 0; c != optstr[i]; i++) 572 if (i == NOPT - 1) 573 return (-1); 574 opts ^= OPT_SET(flags[i]); 575 } 576 if (OPT_CHECK(RBX_DUAL)) 577 ioctrl = IO_SERIAL | IO_KEYBOARD; 578 else if (OPT_CHECK(RBX_SERIAL)) 579 ioctrl = IO_SERIAL; 580 else 581 ioctrl = IO_KEYBOARD; 582 583 if (ioctrl & IO_SERIAL) { 584 if (sio_init(115200 / comspeed) != 0) 585 ioctrl &= ~IO_SERIAL; 586 } 587 } else if (c == '?') { 588 printf("\n"); 589 fs_list(arg); 590 zfs_list(arg); 591 return (-1); 592 } else { 593 arg--; 594 595 /* 596 * Report pool status if the comment is 'status'. Lets 597 * hope no-one wants to load /status as a kernel. 598 */ 599 if (strcmp(arg, "status") == 0) { 600 pager_open(); 601 for (i = 0; devsw[i] != NULL; i++) { 602 if (devsw[i]->dv_print != NULL) { 603 if (devsw[i]->dv_print(1)) 604 break; 605 } else { 606 sprintf(line, 607 "%s: (unknown)\n", 608 devsw[i]->dv_name); 609 if (pager_output(line)) 610 break; 611 } 612 } 613 pager_close(); 614 return (-1); 615 } 616 617 /* 618 * If there is a colon, switch pools. 619 */ 620 if (strncmp(arg, "zfs:", 4) == 0) 621 q = strrchr(arg + 4, ':'); 622 else 623 q = strrchr(arg, ':'); 624 625 if (q != NULL) { 626 *q++ = '\0'; 627 if (mount_root(arg) != 0) 628 return (-1); 629 arg = q; 630 } 631 if ((i = ep - arg)) { 632 if ((size_t)i >= sizeof (kname)) 633 return (-1); 634 memcpy(kname, arg, i + 1); 635 } 636 } 637 arg = p; 638 } 639 return (0); 640 } 641 642 /* 643 * probe arguments for partition iterator (see below) 644 */ 645 struct probe_args { 646 int fd; 647 char *devname; 648 uint_t secsz; 649 uint64_t offset; 650 }; 651 652 /* 653 * simple wrapper around read() to avoid using device specific 654 * strategy() directly. 655 */ 656 static int 657 parttblread(void *arg, void *buf, size_t blocks, uint64_t offset) 658 { 659 struct probe_args *ppa = arg; 660 size_t size = ppa->secsz * blocks; 661 662 lseek(ppa->fd, offset * ppa->secsz, SEEK_SET); 663 if (read(ppa->fd, buf, size) == size) 664 return (0); 665 return (EIO); 666 } 667 668 /* 669 * scan partition entries to find boot partition starting at start_sector. 670 * in case of MBR partition type PART_SOLARIS2, read VTOC and recurse. 671 */ 672 static int 673 probe_partition(void *arg, const char *partname, 674 const struct ptable_entry *part) 675 { 676 struct probe_args pa, *ppa = arg; 677 struct ptable *table; 678 uint64_t *pool_guid_ptr = NULL; 679 uint64_t pool_guid = 0; 680 char devname[32]; 681 int len, ret = 0; 682 683 len = strlen(ppa->devname); 684 if (len > sizeof (devname)) 685 len = sizeof (devname); 686 687 strncpy(devname, ppa->devname, len - 1); 688 devname[len - 1] = '\0'; 689 snprintf(devname, sizeof (devname), "%s%s:", devname, partname); 690 691 /* filter out partitions *not* used by zfs */ 692 switch (part->type) { 693 case PART_RESERVED: /* efi reserverd */ 694 case PART_VTOC_BOOT: /* vtoc boot area */ 695 case PART_VTOC_SWAP: 696 return (ret); 697 default: 698 break; 699 } 700 701 if (part->type == PART_SOLARIS2) { 702 pa.offset = part->start; 703 pa.fd = open(devname, O_RDONLY); 704 if (pa.fd == -1) 705 return (ret); 706 pa.devname = devname; 707 pa.secsz = ppa->secsz; 708 table = ptable_open(&pa, part->end - part->start + 1, 709 ppa->secsz, parttblread); 710 if (table != NULL) { 711 enum ptable_type pt = ptable_gettype(table); 712 713 if (pt == PTABLE_VTOC8 || pt == PTABLE_VTOC) { 714 ret = ptable_iterate(table, &pa, 715 probe_partition); 716 ptable_close(table); 717 close(pa.fd); 718 return (ret); 719 } 720 ptable_close(table); 721 } 722 close(pa.fd); 723 } 724 725 if (ppa->offset + part->start == start_sector) { 726 /* Ask zfs_probe_dev to provide guid. */ 727 pool_guid_ptr = &pool_guid; 728 /* Set up boot device name for non-zfs case. */ 729 strncpy(boot_devname, devname, sizeof (boot_devname)); 730 } 731 732 ret = zfs_probe_dev(devname, pool_guid_ptr); 733 if (pool_guid != 0 && bdev == NULL) { 734 bdev = malloc(sizeof (struct i386_devdesc)); 735 bzero(bdev, sizeof (struct i386_devdesc)); 736 bdev->dd.d_dev = &zfs_dev; 737 bdev->d_kind.zfs.pool_guid = pool_guid; 738 739 /* 740 * We can not set up zfs boot device name yet, as the 741 * zfs dv_init() is not completed. We will set boot_devname 742 * in main, after devsw setup. 743 */ 744 } 745 746 return (0); 747 } 748 749 /* 750 * open partition table on disk and scan partition entries to find 751 * boot partition starting at start_sector (recorded by installboot). 752 */ 753 static int 754 probe_disk(char *devname) 755 { 756 struct ptable *table; 757 struct probe_args pa; 758 uint64_t mediasz; 759 int ret; 760 761 pa.offset = 0; 762 pa.devname = devname; 763 pa.fd = open(devname, O_RDONLY); 764 if (pa.fd == -1) { 765 return (ENXIO); 766 } 767 768 ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); 769 if (ret == 0) 770 ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz); 771 if (ret == 0) { 772 table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz, 773 parttblread); 774 if (table != NULL) { 775 ret = ptable_iterate(table, &pa, probe_partition); 776 ptable_close(table); 777 } 778 } 779 close(pa.fd); 780 return (ret); 781 } 782 783 /* 784 * Probe all disks to discover ZFS pools. The idea is to walk all possible 785 * disk devices, however, we also need to identify possible boot pool. 786 * For boot pool detection we have boot disk passed us from BIOS, recorded 787 * in bootinfo.bi_bios_dev, and start_sector LBA recorded by installboot. 788 * 789 * To detect boot pool, we can not use generic zfs_probe_dev() on boot disk, 790 * but we need to walk partitions, as we have no way to pass start_sector 791 * to zfs_probe_dev(). Note we do need to detect the partition correcponding 792 * to non-zfs case, so here we can set boot_devname for both cases. 793 */ 794 static void 795 i386_zfs_probe(void) 796 { 797 char devname[32]; 798 int boot_unit; 799 struct i386_devdesc dev; 800 801 dev.dd.d_dev = &bioshd; 802 /* Translate bios dev to our unit number. */ 803 boot_unit = bd_bios2unit(bootinfo.bi_bios_dev); 804 805 /* 806 * Open all the disks we can find and see if we can reconstruct 807 * ZFS pools from them. 808 */ 809 for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) { 810 snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name, 811 dev.dd.d_unit); 812 /* If this is not boot disk, use generic probe. */ 813 if (dev.dd.d_unit != boot_unit) 814 zfs_probe_dev(devname, NULL); 815 else 816 probe_disk(devname); 817 } 818 } 819