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