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