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