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
ptov(uintptr_t x)146 ptov(uintptr_t x)
147 {
148 return (PTOV(x));
149 }
150
151 int
main(void)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
exit(int x)361 exit(int x)
362 {
363 __exit(x);
364 }
365
366 static void
load(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
mount_root(char * arg)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
fs_list(char * arg)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
parse_cmd(void)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
parttblread(void * arg,void * buf,size_t blocks,uint64_t offset)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
probe_partition(void * arg,const char * partname,const struct ptable_entry * part)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
probe_disk(char * devname)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
i386_zfs_probe(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