xref: /freebsd/stand/i386/zfsboot/zfsboot.c (revision b197d4b893974c9eb4d7b38704c6d5c486235d6f)
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 __FBSDID("$FreeBSD$");
18 
19 #include <stand.h>
20 
21 #include <sys/param.h>
22 #include <sys/errno.h>
23 #include <sys/diskmbr.h>
24 #ifdef GPT
25 #include <sys/gpt.h>
26 #endif
27 #include <sys/reboot.h>
28 #include <sys/queue.h>
29 #ifdef LOADER_ZFS_SUPPORT
30 #include <sys/zfs_bootenv.h>
31 #endif
32 
33 #include <machine/bootinfo.h>
34 #include <machine/elf.h>
35 #include <machine/pc/bios.h>
36 
37 #include <stdarg.h>
38 #include <stddef.h>
39 
40 #include <a.out.h>
41 #include "bootstrap.h"
42 #include "libi386.h"
43 #include <btxv86.h>
44 
45 #include "lib.h"
46 #include "rbx.h"
47 #include "cons.h"
48 #include "bootargs.h"
49 #include "disk.h"
50 #include "part.h"
51 #include "paths.h"
52 
53 #include "libzfs.h"
54 
55 #define	ARGS			0x900
56 #define	NOPT			14
57 #define	NDEV			3
58 
59 #define	BIOS_NUMDRIVES		0x475
60 #define	DRV_HARD		0x80
61 #define	DRV_MASK		0x7f
62 
63 #define	TYPE_AD			0
64 #define	TYPE_DA			1
65 #define	TYPE_MAXHARD		TYPE_DA
66 #define	TYPE_FD			2
67 
68 extern uint32_t _end;
69 
70 static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
71 static const unsigned char flags[NOPT] = {
72     RBX_DUAL,
73     RBX_SERIAL,
74     RBX_ASKNAME,
75     RBX_CDROM,
76     RBX_CONFIG,
77     RBX_KDB,
78     RBX_GDB,
79     RBX_MUTE,
80     RBX_NOINTR,
81     RBX_PAUSE,
82     RBX_QUIET,
83     RBX_DFLTROOT,
84     RBX_SINGLE,
85     RBX_VERBOSE
86 };
87 uint32_t opts;
88 
89 /*
90  * Paths to try loading before falling back to the boot2 prompt.
91  *
92  * /boot/zfsloader must be tried before /boot/loader in order to remain
93  * backward compatible with ZFS boot environments where /boot/loader exists
94  * but does not have ZFS support, which was the case before FreeBSD 12.
95  *
96  * If no loader is found, try to load a kernel directly instead.
97  */
98 static const struct string {
99 	const char *p;
100 	size_t len;
101 } loadpath[] = {
102 	{ PATH_LOADER_ZFS, sizeof(PATH_LOADER_ZFS) },
103 	{ PATH_LOADER, sizeof(PATH_LOADER) },
104 	{ PATH_KERNEL, sizeof(PATH_KERNEL) },
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 #ifdef LOADER_GELI_SUPPORT
118 static struct geli_boot_args geliargs;
119 #endif
120 
121 extern vm_offset_t high_heap_base;
122 extern uint32_t	bios_basemem, bios_extmem, high_heap_size;
123 
124 static char *heap_top;
125 static char *heap_bottom;
126 
127 void exit(int);
128 static void i386_zfs_probe(void);
129 static void load(void);
130 static int parse_cmd(void);
131 
132 #ifdef LOADER_GELI_SUPPORT
133 #include "geliboot.h"
134 static char gelipw[GELI_PW_MAXLEN];
135 #endif
136 
137 struct arch_switch archsw;	/* MI/MD interface boundary */
138 static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */
139 
140 struct devsw *devsw[] = {
141 	&bioshd,
142 #if defined(LOADER_ZFS_SUPPORT)
143 	&zfs_dev,
144 #endif
145 	NULL
146 };
147 
148 struct fs_ops *file_system[] = {
149 #if defined(LOADER_ZFS_SUPPORT)
150 	&zfs_fsops,
151 #endif
152 #if defined(LOADER_UFS_SUPPORT)
153 	&ufs_fsops,
154 #endif
155 	NULL
156 };
157 
158 caddr_t
159 ptov(uintptr_t x)
160 {
161 	return (PTOV(x));
162 }
163 
164 int main(void);
165 
166 int
167 main(void)
168 {
169 	unsigned i;
170 	int auto_boot, fd, nextboot = 0;
171 	struct disk_devdesc devdesc;
172 
173 	bios_getmem();
174 
175 	if (high_heap_size > 0) {
176 		heap_top = PTOV(high_heap_base + high_heap_size);
177 		heap_bottom = PTOV(high_heap_base);
178 	} else {
179 		heap_bottom = (char *)
180 		    (roundup2(__base + (int32_t)&_end, 0x10000) - __base);
181 		heap_top = (char *)PTOV(bios_basemem);
182 	}
183 	setheap(heap_bottom, heap_top);
184 
185 	/*
186 	 * Initialise the block cache. Set the upper limit.
187 	 */
188 	bcache_init(32768, 512);
189 
190 	archsw.arch_autoload = NULL;
191 	archsw.arch_getdev = i386_getdev;
192 	archsw.arch_copyin = NULL;
193 	archsw.arch_copyout = NULL;
194 	archsw.arch_readin = NULL;
195 	archsw.arch_isainb = NULL;
196 	archsw.arch_isaoutb = NULL;
197 	archsw.arch_zfs_probe = i386_zfs_probe;
198 
199 	bootinfo.bi_version = BOOTINFO_VERSION;
200 	bootinfo.bi_size = sizeof(bootinfo);
201 	bootinfo.bi_basemem = bios_basemem / 1024;
202 	bootinfo.bi_extmem = bios_extmem / 1024;
203 	bootinfo.bi_memsizes_valid++;
204 	bootinfo.bi_bios_dev = *(uint8_t *)PTOV(ARGS);
205 
206 	/* Set up fall back device name. */
207 	snprintf(boot_devname, sizeof (boot_devname), "disk%d:",
208 	    bd_bios2unit(bootinfo.bi_bios_dev));
209 
210 	/* Set up currdev variable to have hooks in place. */
211 	env_setenv("currdev", EV_VOLATILE, "", i386_setcurrdev,
212 	    env_nounset);
213 
214 	for (i = 0; devsw[i] != NULL; i++)
215 		if (devsw[i]->dv_init != NULL)
216 			(devsw[i]->dv_init)();
217 
218 	disk_parsedev(&devdesc, boot_devname + 4, NULL);
219 
220 	bootdev = MAKEBOOTDEV(dev_maj[DEVT_DISK], devdesc.d_slice + 1,
221 	    devdesc.dd.d_unit,
222 	    devdesc.d_partition >= 0 ? devdesc.d_partition : 0xff);
223 
224 	/*
225 	 * devformat() can be called only after dv_init
226 	 */
227 	if (bdev != NULL && bdev->dd.d_dev->dv_type == DEVT_ZFS) {
228 		/* set up proper device name string for ZFS */
229 		strncpy(boot_devname, devformat(&bdev->dd), sizeof (boot_devname));
230 		if (zfs_get_bootonce(bdev, OS_BOOTONCE, cmd,
231 		    sizeof(cmd)) == 0) {
232 			nvlist_t *benv;
233 
234 			nextboot = 1;
235 			memcpy(cmddup, cmd, sizeof(cmd));
236 			if (parse_cmd()) {
237 				if (!OPT_CHECK(RBX_QUIET))
238 					printf("failed to parse bootonce "
239 					    "command\n");
240 				exit(0);
241 			}
242 			if (!OPT_CHECK(RBX_QUIET))
243 				printf("zfs bootonce: %s\n", cmddup);
244 
245 			if (zfs_get_bootenv(bdev, &benv) == 0) {
246 				nvlist_add_string(benv, OS_BOOTONCE_USED,
247 				    cmddup);
248 				zfs_set_bootenv(bdev, benv);
249 			}
250 			/* Do not process this command twice */
251 			*cmd = 0;
252 		}
253 	}
254 
255 	/* now make sure we have bdev on all cases */
256 	free(bdev);
257 	i386_getdev((void **)&bdev, boot_devname, NULL);
258 
259 	env_setenv("currdev", EV_VOLATILE, boot_devname, i386_setcurrdev,
260 	    env_nounset);
261 
262 	/* Process configuration file */
263 	auto_boot = 1;
264 
265 	fd = open(PATH_CONFIG, O_RDONLY);
266 	if (fd == -1)
267 		fd = open(PATH_DOTCONFIG, O_RDONLY);
268 
269 	if (fd != -1) {
270 		ssize_t cmdlen;
271 
272 		if ((cmdlen = read(fd, cmd, sizeof(cmd))) > 0)
273 			cmd[cmdlen] = '\0';
274 		else
275 			*cmd = '\0';
276 		close(fd);
277 	}
278 
279 	if (*cmd) {
280 		/*
281 		 * Note that parse_cmd() is destructive to cmd[] and we also
282 		 * want to honor RBX_QUIET option that could be present in
283 		 * cmd[].
284 		 */
285 		memcpy(cmddup, cmd, sizeof(cmd));
286 		if (parse_cmd())
287 			auto_boot = 0;
288 		if (!OPT_CHECK(RBX_QUIET))
289 			printf("%s: %s\n", PATH_CONFIG, cmddup);
290 		/* Do not process this command twice */
291 		*cmd = 0;
292 	}
293 
294 	/* Do not risk waiting at the prompt forever. */
295 	if (nextboot && !auto_boot)
296 		exit(0);
297 
298 	if (auto_boot && !*kname) {
299 		/*
300 		 * Iterate through the list of loader and kernel paths,
301 		 * trying to load. If interrupted by a keypress, or in case of
302 		 * failure, drop the user to the boot2 prompt.
303 		 */
304 		for (i = 0; i < nitems(loadpath); i++) {
305 			memcpy(kname, loadpath[i].p, loadpath[i].len);
306 			if (keyhit(3))
307 				break;
308 			load();
309 		}
310 	}
311 
312 	/* Present the user with the boot2 prompt. */
313 
314 	for (;;) {
315 		if (!auto_boot || !OPT_CHECK(RBX_QUIET)) {
316 			printf("\nFreeBSD/x86 boot\n");
317 			printf("Default: %s%s\nboot: ", boot_devname, kname);
318 		}
319 		if (ioctrl & IO_SERIAL)
320 			sio_flush();
321 		if (!auto_boot || keyhit(5))
322 			getstr(cmd, sizeof(cmd));
323 		else if (!auto_boot || !OPT_CHECK(RBX_QUIET))
324 			putchar('\n');
325 		auto_boot = 0;
326 		if (parse_cmd())
327 			putchar('\a');
328 		else
329 			load();
330 	}
331 }
332 
333 /* XXX - Needed for btxld to link the boot2 binary; do not remove. */
334 void
335 exit(int x)
336 {
337 	__exit(x);
338 }
339 
340 static void
341 load(void)
342 {
343 	union {
344 		struct exec ex;
345 		Elf32_Ehdr eh;
346 	} hdr;
347 	static Elf32_Phdr ep[2];
348 	static Elf32_Shdr es[2];
349 	caddr_t p;
350 	uint32_t addr, x;
351 	int fd, fmt, i, j;
352 	ssize_t size;
353 
354 	if ((fd = open(kname, O_RDONLY)) == -1) {
355 		printf("\nCan't find %s\n", kname);
356 		return;
357 	}
358 
359 	size = sizeof(hdr);
360 	if (read(fd, &hdr, sizeof (hdr)) != size) {
361 		close(fd);
362 		return;
363 	}
364 	if (N_GETMAGIC(hdr.ex) == ZMAGIC) {
365 		fmt = 0;
366 	} else if (IS_ELF(hdr.eh)) {
367 		fmt = 1;
368 	} else {
369 		printf("Invalid %s\n", "format");
370 		close(fd);
371 		return;
372 	}
373 	if (fmt == 0) {
374 		addr = hdr.ex.a_entry & 0xffffff;
375 		p = PTOV(addr);
376 		lseek(fd, PAGE_SIZE, SEEK_SET);
377 		size = hdr.ex.a_text;
378 		if (read(fd, p, hdr.ex.a_text) != size) {
379 			close(fd);
380 			return;
381 		}
382 		p += roundup2(hdr.ex.a_text, PAGE_SIZE);
383 		size = hdr.ex.a_data;
384 		if (read(fd, p, hdr.ex.a_data) != size) {
385 			close(fd);
386 			return;
387 		}
388 		p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
389 		bootinfo.bi_symtab = VTOP(p);
390 		memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
391 		p += sizeof(hdr.ex.a_syms);
392 		if (hdr.ex.a_syms) {
393 			size = hdr.ex.a_syms;
394 			if (read(fd, p, hdr.ex.a_syms) != size) {
395 				close(fd);
396 				return;
397 			}
398 			p += hdr.ex.a_syms;
399 			size = sizeof (int);
400 			if (read(fd, p, sizeof (int)) != size) {
401 				close(fd);
402 				return;
403 			}
404 			x = *(uint32_t *)p;
405 			p += sizeof(int);
406 			x -= sizeof(int);
407 			size = x;
408 			if (read(fd, p, x) != size) {
409 				close(fd);
410 				return;
411 			}
412 			p += x;
413 		}
414 	} else {
415 		lseek(fd, hdr.eh.e_phoff, SEEK_SET);
416 		for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) {
417 			size = sizeof (ep[0]);
418 			if (read(fd, ep + j, sizeof (ep[0])) != size) {
419 				close(fd);
420 				return;
421 			}
422 			if (ep[j].p_type == PT_LOAD)
423 				j++;
424 		}
425 		for (i = 0; i < 2; i++) {
426 			p = PTOV(ep[i].p_paddr & 0xffffff);
427 			lseek(fd, ep[i].p_offset, SEEK_SET);
428 			size = ep[i].p_filesz;
429 			if (read(fd, p, ep[i].p_filesz) != size) {
430 				close(fd);
431 				return;
432 			}
433 		}
434 		p += roundup2(ep[1].p_memsz, PAGE_SIZE);
435 		bootinfo.bi_symtab = VTOP(p);
436 		if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
437 			lseek(fd, hdr.eh.e_shoff +
438 			    sizeof (es[0]) * (hdr.eh.e_shstrndx + 1),
439 			    SEEK_SET);
440 			size = sizeof(es);
441 			if (read(fd, &es, sizeof (es)) != size) {
442 				close(fd);
443 				return;
444 			}
445 			for (i = 0; i < 2; i++) {
446 				memcpy(p, &es[i].sh_size,
447 				    sizeof(es[i].sh_size));
448 				p += sizeof(es[i].sh_size);
449 				lseek(fd, es[i].sh_offset, SEEK_SET);
450 				size = es[i].sh_size;
451 				if (read(fd, p, es[i].sh_size) != size) {
452 					close(fd);
453 					return;
454 				}
455 				p += es[i].sh_size;
456 			}
457 		}
458 		addr = hdr.eh.e_entry & 0xffffff;
459 	}
460 	close(fd);
461 
462 	bootinfo.bi_esymtab = VTOP(p);
463 	bootinfo.bi_kernelname = VTOP(kname);
464 #ifdef LOADER_GELI_SUPPORT
465 	explicit_bzero(gelipw, sizeof(gelipw));
466 #endif
467 
468 	if (bdev->dd.d_dev->dv_type == DEVT_ZFS) {
469 		zfsargs.size = sizeof(zfsargs);
470 		zfsargs.pool = bdev->zfs.pool_guid;
471 		zfsargs.root = bdev->zfs.root_guid;
472 #ifdef LOADER_GELI_SUPPORT
473 		export_geli_boot_data(&zfsargs.gelidata);
474 #endif
475 		/*
476 		 * Note that the zfsargs struct is passed by value, not by
477 		 * pointer. Code in btxldr.S copies the values from the entry
478 		 * stack to a fixed location within loader(8) at startup due
479 		 * to the presence of KARGS_FLAGS_EXTARG.
480 		 */
481 		__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
482 		    bootdev,
483 		    KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG,
484 		    (uint32_t)bdev->zfs.pool_guid,
485 		    (uint32_t)(bdev->zfs.pool_guid >> 32),
486 		    VTOP(&bootinfo),
487 		    zfsargs);
488 	} else {
489 #ifdef LOADER_GELI_SUPPORT
490 		geliargs.size = sizeof(geliargs);
491 		export_geli_boot_data(&geliargs.gelidata);
492 #endif
493 
494 		/*
495 		 * Note that the geliargs struct is passed by value, not by
496 		 * pointer. Code in btxldr.S copies the values from the entry
497 		 * stack to a fixed location within loader(8) at startup due
498 		 * to the presence of the KARGS_FLAGS_EXTARG flag.
499 		 */
500 		__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
501 		    bootdev,
502 #ifdef LOADER_GELI_SUPPORT
503 		    KARGS_FLAGS_GELI | KARGS_FLAGS_EXTARG, 0, 0,
504 		    VTOP(&bootinfo), geliargs
505 #else
506 		    0, 0, 0, VTOP(&bootinfo)
507 #endif
508 		    );
509 	}
510 }
511 
512 static int
513 mount_root(char *arg)
514 {
515 	char *root;
516 	struct i386_devdesc *ddesc;
517 	uint8_t part;
518 
519 	if (asprintf(&root, "%s:", arg) < 0)
520 		return (1);
521 
522 	if (i386_getdev((void **)&ddesc, root, NULL)) {
523 		free(root);
524 		return (1);
525 	}
526 
527 	/* we should have new device descriptor, free old and replace it. */
528 	free(bdev);
529 	bdev = ddesc;
530 	if (bdev->dd.d_dev->dv_type == DEVT_DISK) {
531 		if (bdev->disk.d_partition == -1)
532 			part = 0xff;
533 		else
534 			part = bdev->disk.d_partition;
535 		bootdev = MAKEBOOTDEV(dev_maj[bdev->dd.d_dev->dv_type],
536 		    bdev->disk.d_slice + 1, bdev->dd.d_unit, part);
537 		bootinfo.bi_bios_dev = bd_unit2bios(bdev);
538 	}
539 	strncpy(boot_devname, root, sizeof (boot_devname));
540 	setenv("currdev", root, 1);
541 	free(root);
542 	return (0);
543 }
544 
545 static void
546 fs_list(char *arg)
547 {
548 	int fd;
549 	struct dirent *d;
550 	char line[80];
551 
552 	fd = open(arg, O_RDONLY);
553 	if (fd < 0)
554 		return;
555 	pager_open();
556 	while ((d = readdirfd(fd)) != NULL) {
557 		sprintf(line, "%s\n", d->d_name);
558 		if (pager_output(line))
559 			break;
560 	}
561 	pager_close();
562 	close(fd);
563 }
564 
565 static int
566 parse_cmd(void)
567 {
568 	char *arg = cmd;
569 	char *ep, *p, *q;
570 	const char *cp;
571 	char line[80];
572 	int c, i, j;
573 
574 	while ((c = *arg++)) {
575 		if (c == ' ' || c == '\t' || c == '\n')
576 			continue;
577 		for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++)
578 			;
579 		ep = p;
580 		if (*p)
581 			*p++ = 0;
582 		if (c == '-') {
583 			while ((c = *arg++)) {
584 				if (c == 'P') {
585 					if (*(uint8_t *)PTOV(0x496) & 0x10) {
586 						cp = "yes";
587 					} else {
588 						opts |= OPT_SET(RBX_DUAL);
589 						opts |= OPT_SET(RBX_SERIAL);
590 						cp = "no";
591 					}
592 					printf("Keyboard: %s\n", cp);
593 					continue;
594 				} else if (c == 'S') {
595 					j = 0;
596 					while ((unsigned int)
597 					    (i = *arg++ - '0') <= 9)
598 						j = j * 10 + i;
599 					if (j > 0 && i == -'0') {
600 						comspeed = j;
601 						break;
602 					}
603 					/*
604 					 * Fall through to error below
605 					 * ('S' not in optstr[]).
606 					 */
607 				}
608 				for (i = 0; c != optstr[i]; i++)
609 					if (i == NOPT - 1)
610 						return (-1);
611 				opts ^= OPT_SET(flags[i]);
612 			}
613 			ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
614 			    OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
615 			if (ioctrl & IO_SERIAL) {
616 				if (sio_init(115200 / comspeed) != 0)
617 					ioctrl &= ~IO_SERIAL;
618 			}
619 		} if (c == '?') {
620 			printf("\n");
621 			if (*arg == '\0')
622 				arg = (char *)"/";
623 			fs_list(arg);
624 			zfs_list(arg);
625 			return (-1);
626 		} else {
627 			char *ptr;
628 			printf("\n");
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 						snprintf(line, sizeof(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 "zfs:" prefix simply ignore it.
655 			 */
656 			ptr = arg;
657 			if (strncmp(ptr, "zfs:", 4) == 0)
658 				ptr += 4;
659 
660 			/*
661 			 * If there is a colon, switch pools.
662 			 */
663 			q = strchr(ptr, ':');
664 			if (q) {
665 				*q++ = '\0';
666 				if (mount_root(arg) != 0) {
667 					return (-1);
668 				}
669 				arg = q;
670 			}
671 			if ((i = ep - arg)) {
672 				if ((size_t)i >= sizeof(kname))
673 					return (-1);
674 				memcpy(kname, arg, i + 1);
675 			}
676 		}
677 		arg = p;
678 	}
679 	return (0);
680 }
681 
682 /*
683  * Probe all disks to discover ZFS pools. The idea is to walk all possible
684  * disk devices, however, we also need to identify possible boot pool.
685  * For boot pool detection we have boot disk passed us from BIOS, recorded
686  * in bootinfo.bi_bios_dev.
687  */
688 static void
689 i386_zfs_probe(void)
690 {
691 	char devname[32];
692 	int boot_unit;
693 	struct i386_devdesc dev;
694 	uint64_t pool_guid = 0;
695 
696 	dev.dd.d_dev = &bioshd;
697 	/* Translate bios dev to our unit number. */
698 	boot_unit = bd_bios2unit(bootinfo.bi_bios_dev);
699 
700 	/*
701 	 * Open all the disks we can find and see if we can reconstruct
702 	 * ZFS pools from them.
703 	 */
704 	for (dev.dd.d_unit = 0; bd_unit2bios(&dev) >= 0; dev.dd.d_unit++) {
705 		snprintf(devname, sizeof (devname), "%s%d:", bioshd.dv_name,
706 		    dev.dd.d_unit);
707 		/* If this is not boot disk, use generic probe. */
708 		if (dev.dd.d_unit != boot_unit)
709 			zfs_probe_dev(devname, NULL);
710 		else
711 			zfs_probe_dev(devname, &pool_guid);
712 
713 		if (pool_guid != 0 && bdev == NULL) {
714 			bdev = malloc(sizeof (struct i386_devdesc));
715 			bzero(bdev, sizeof (struct i386_devdesc));
716 			bdev->zfs.dd.d_dev = &zfs_dev;
717 			bdev->zfs.pool_guid = pool_guid;
718 		}
719 	}
720 }
721