xref: /illumos-gate/usr/src/boot/efi/loader/main.c (revision 2a690de65126520928618d79f73d5c0e4e573351)
1 /*
2  * Copyright (c) 2008-2010 Rui Paulo
3  * Copyright (c) 2006 Marcel Moolenaar
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 
30 #include <sys/disk.h>
31 #include <sys/param.h>
32 #include <sys/reboot.h>
33 #include <sys/boot.h>
34 #include <sys/consplat.h>
35 #include <sys/zfs_bootenv.h>
36 #include <stand.h>
37 #include <inttypes.h>
38 #include <string.h>
39 #include <setjmp.h>
40 #include <disk.h>
41 
42 #include <efi.h>
43 #include <efilib.h>
44 #include <efigpt.h>
45 
46 #include <uuid.h>
47 
48 #include <bootstrap.h>
49 #include <gfx_fb.h>
50 #include <smbios.h>
51 
52 #include <libzfs.h>
53 #include <efizfs.h>
54 
55 #include "loader_efi.h"
56 
57 struct arch_switch archsw;	/* MI/MD interface boundary */
58 
59 EFI_GUID devid = DEVICE_PATH_PROTOCOL;
60 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
61 EFI_GUID smbios = SMBIOS_TABLE_GUID;
62 EFI_GUID smbios3 = SMBIOS3_TABLE_GUID;
63 EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL;
64 EFI_GUID serialio = SERIAL_IO_PROTOCOL;
65 
66 extern void acpi_detect(void);
67 extern void efi_getsmap(void);
68 
69 static EFI_LOADED_IMAGE *img;
70 
71 /*
72  * Number of seconds to wait for a keystroke before exiting with failure
73  * in the event no currdev is found. -2 means always break, -1 means
74  * never break, 0 means poll once and then reboot, > 0 means wait for
75  * that many seconds. "fail_timeout" can be set in the environment as
76  * well.
77  */
78 static int fail_timeout = 5;
79 
80 bool
81 efi_zfs_is_preferred(EFI_HANDLE *h)
82 {
83 	EFI_DEVICE_PATH *devpath, *dp, *node;
84 	HARDDRIVE_DEVICE_PATH *hd;
85 	bool ret;
86 	extern UINT64 start_sector;	/* from mb_header.S */
87 
88 	/* This check is true for chainloader case. */
89 	if (h == img->DeviceHandle)
90 		return (true);
91 
92 	/*
93 	 * Make sure the image was loaded from the hard disk.
94 	 */
95 	devpath = efi_lookup_devpath(img->DeviceHandle);
96 	if (devpath == NULL)
97 		return (false);
98 	node = efi_devpath_last_node(devpath);
99 	if (node == NULL)
100 		return (false);
101 	if (DevicePathType(node) != MEDIA_DEVICE_PATH ||
102 	    (DevicePathSubType(node) != MEDIA_FILEPATH_DP &&
103 	    DevicePathSubType(node) != MEDIA_HARDDRIVE_DP)) {
104 		return (false);
105 	}
106 
107 	/*
108 	 * XXX We ignore the MEDIA_FILEPATH_DP here for now as it is
109 	 * used on arm and we do not support arm.
110 	 */
111 	ret = false;
112 	dp = efi_devpath_trim(devpath);
113 	devpath = NULL;
114 	if (dp == NULL)
115 		goto done;
116 
117 	devpath = efi_lookup_devpath(h);
118 	if (devpath == NULL)
119 		goto done;
120 	hd = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(devpath);
121 	if (hd == NULL) {
122 		devpath = NULL;
123 		goto done;
124 	}
125 	devpath = efi_devpath_trim(devpath);
126 	if (devpath == NULL)
127 		goto done;
128 
129 	if (!efi_devpath_match(dp, devpath))
130 		goto done;
131 
132 	/* It is the same disk, do we have partition start? */
133 	if (start_sector == 0)
134 		ret = true;
135 	else if (start_sector == hd->PartitionStart)
136 		ret = true;
137 
138 done:
139 	free(dp);
140 	free(devpath);
141 	return (ret);
142 }
143 
144 static bool
145 has_keyboard(void)
146 {
147 	EFI_STATUS status;
148 	EFI_DEVICE_PATH *path;
149 	EFI_HANDLE *hin, *hin_end, *walker;
150 	UINTN sz;
151 	bool retval = false;
152 
153 	/*
154 	 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
155 	 * do the typical dance to get the right sized buffer.
156 	 */
157 	sz = 0;
158 	hin = NULL;
159 	status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0);
160 	if (status == EFI_BUFFER_TOO_SMALL) {
161 		hin = (EFI_HANDLE *)malloc(sz);
162 		status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz,
163 		    hin);
164 		if (EFI_ERROR(status))
165 			free(hin);
166 	}
167 	if (EFI_ERROR(status))
168 		return (retval);
169 
170 	/*
171 	 * Look at each of the handles. If it supports the device path protocol,
172 	 * use it to get the device path for this handle. Then see if that
173 	 * device path matches either the USB device path for keyboards or the
174 	 * legacy device path for keyboards.
175 	 */
176 	hin_end = &hin[sz / sizeof (*hin)];
177 	for (walker = hin; walker < hin_end; walker++) {
178 		status = OpenProtocolByHandle(*walker, &devid, (void **)&path);
179 		if (EFI_ERROR(status))
180 			continue;
181 
182 		while (!IsDevicePathEnd(path)) {
183 			/*
184 			 * Check for the ACPI keyboard node. All PNP3xx nodes
185 			 * are keyboards of different flavors. Note: It is
186 			 * unclear of there's always a keyboard node when
187 			 * there's a keyboard controller, or if there's only one
188 			 * when a keyboard is detected at boot.
189 			 */
190 			if (DevicePathType(path) == ACPI_DEVICE_PATH &&
191 			    (DevicePathSubType(path) == ACPI_DP ||
192 			    DevicePathSubType(path) == ACPI_EXTENDED_DP)) {
193 				ACPI_HID_DEVICE_PATH  *acpi;
194 
195 				acpi = (ACPI_HID_DEVICE_PATH *)(void *)path;
196 				if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) ==
197 				    0x300 &&
198 				    (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) {
199 					retval = true;
200 					goto out;
201 				}
202 			/*
203 			 * Check for USB keyboard node, if present. Unlike a
204 			 * PS/2 keyboard, these definitely only appear when
205 			 * connected to the system.
206 			 */
207 			} else if (DevicePathType(path) ==
208 			    MESSAGING_DEVICE_PATH &&
209 			    DevicePathSubType(path) == MSG_USB_CLASS_DP) {
210 				USB_CLASS_DEVICE_PATH *usb;
211 
212 				/*
213 				 * Check for:
214 				 * DeviceClass: HID
215 				 * DeviceSubClass: Boot devices
216 				 * DeviceProtocol: Boot keyboards
217 				 */
218 				usb = (USB_CLASS_DEVICE_PATH *)(void *)path;
219 				if (usb->DeviceClass == 3 &&
220 				    usb->DeviceSubClass == 1 &&
221 				    usb->DeviceProtocol == 1) {
222 					retval = true;
223 					goto out;
224 				}
225 			}
226 			path = NextDevicePathNode(path);
227 		}
228 	}
229 out:
230 	free(hin);
231 	return (retval);
232 }
233 
234 static void
235 set_currdev(const char *devname)
236 {
237 
238 	/*
239 	 * Don't execute hooks here; we may need to try setting these more than
240 	 * once here if we're probing for the ZFS pool we're supposed to boot.
241 	 * The currdev hook is intended to just validate user input anyways,
242 	 * while the loaddev hook makes it immutable once we've determined what
243 	 * the proper currdev is.
244 	 */
245 	env_setenv("currdev", EV_VOLATILE | EV_NOHOOK, devname, efi_setcurrdev,
246 	    env_nounset);
247 	env_setenv("loaddev", EV_VOLATILE | EV_NOHOOK, devname, env_noset,
248 	    env_nounset);
249 }
250 
251 static void
252 set_currdev_devdesc(struct devdesc *currdev)
253 {
254 	char *devname;
255 
256 	devname = efi_fmtdev(currdev);
257 
258 	printf("Setting currdev to %s\n", devname);
259 	set_currdev(devname);
260 }
261 
262 static void
263 set_currdev_devsw(struct devsw *dev, int unit)
264 {
265 	struct devdesc currdev;
266 
267 	currdev.d_dev = dev;
268 	currdev.d_unit = unit;
269 
270 	set_currdev_devdesc(&currdev);
271 }
272 
273 static void
274 set_currdev_pdinfo(pdinfo_t *dp)
275 {
276 
277 	/*
278 	 * Disks are special: they have partitions. if the parent
279 	 * pointer is non-null, we're a partition not a full disk
280 	 * and we need to adjust currdev appropriately.
281 	 */
282 	if (dp->pd_devsw->dv_type == DEVT_DISK) {
283 		struct disk_devdesc currdev;
284 
285 		currdev.dd.d_dev = dp->pd_devsw;
286 		if (dp->pd_parent == NULL) {
287 			currdev.dd.d_unit = dp->pd_unit;
288 			currdev.d_slice = D_SLICENONE;
289 			currdev.d_partition = D_PARTNONE;
290 		} else {
291 			currdev.dd.d_unit = dp->pd_parent->pd_unit;
292 			currdev.d_slice = dp->pd_unit;
293 			currdev.d_partition = D_PARTISGPT; /* Assumes GPT */
294 		}
295 		set_currdev_devdesc((struct devdesc *)&currdev);
296 	} else {
297 		set_currdev_devsw(dp->pd_devsw, dp->pd_unit);
298 	}
299 }
300 
301 static bool
302 sanity_check_currdev(void)
303 {
304 	struct stat st;
305 
306 	return (stat("/boot/defaults/loader.conf", &st) == 0);
307 }
308 
309 static bool
310 probe_zfs_currdev(uint64_t guid)
311 {
312 	struct zfs_devdesc currdev;
313 	char *bootonce;
314 	bool rv;
315 
316 	currdev.dd.d_dev = &zfs_dev;
317 	currdev.dd.d_unit = 0;
318 	currdev.pool_guid = guid;
319 	currdev.root_guid = 0;
320 	set_currdev_devdesc((struct devdesc *)&currdev);
321 
322 	rv = sanity_check_currdev();
323 	if (rv) {
324 		bootonce = malloc(VDEV_PAD_SIZE);
325 		if (bootonce != NULL) {
326 			if (zfs_get_bootonce(&currdev, OS_BOOTONCE, bootonce,
327 			    VDEV_PAD_SIZE) == 0) {
328 				printf("zfs bootonce: %s\n", bootonce);
329 				set_currdev(bootonce);
330 				setenv("zfs-bootonce", bootonce, 1);
331 			}
332 			free(bootonce);
333 			(void) zfs_attach_nvstore(&currdev);
334 		} else {
335 			printf("Failed to process bootonce data: %s\n",
336 			    strerror(errno));
337 		}
338 	}
339 	return (rv);
340 }
341 
342 static bool
343 try_as_currdev(pdinfo_t *pp)
344 {
345 	uint64_t guid;
346 
347 	/*
348 	 * If there's a zpool on this device, try it as a ZFS
349 	 * filesystem, which has somewhat different setup than all
350 	 * other types of fs due to imperfect loader integration.
351 	 * This all stems from ZFS being both a device (zpool) and
352 	 * a filesystem, plus the boot env feature.
353 	 */
354 	if (efizfs_get_guid_by_handle(pp->pd_handle, &guid))
355 		return (probe_zfs_currdev(guid));
356 
357 	/*
358 	 * All other filesystems just need the pdinfo
359 	 * initialized in the standard way.
360 	 */
361 	set_currdev_pdinfo(pp);
362 	return (sanity_check_currdev());
363 }
364 
365 static bool
366 find_currdev(EFI_LOADED_IMAGE *img)
367 {
368 	pdinfo_t *dp, *pp;
369 	EFI_DEVICE_PATH *devpath, *copy;
370 	EFI_HANDLE h;
371 	CHAR16 *text;
372 	struct devsw *dev;
373 	int unit;
374 	uint64_t extra;
375 
376 	/*
377 	 * Did efi_zfs_probe() detect the boot pool? If so, use the zpool
378 	 * it found, if it's sane. ZFS is the only thing that looks for
379 	 * disks and pools to boot.
380 	 */
381 	if (pool_guid != 0) {
382 		printf("Trying ZFS pool\n");
383 		if (probe_zfs_currdev(pool_guid))
384 			return (true);
385 	}
386 
387 	/*
388 	 * Try to find the block device by its handle based on the
389 	 * image we're booting. If we can't find a sane partition,
390 	 * search all the other partitions of the disk. We do not
391 	 * search other disks because it's a violation of the UEFI
392 	 * boot protocol to do so. We fail and let UEFI go on to
393 	 * the next candidate.
394 	 */
395 	dp = efiblk_get_pdinfo_by_handle(img->DeviceHandle);
396 	if (dp != NULL) {
397 		text = efi_devpath_name(dp->pd_devpath);
398 		if (text != NULL) {
399 			printf("Trying ESP: %S\n", text);
400 			efi_free_devpath_name(text);
401 		}
402 		set_currdev_pdinfo(dp);
403 		if (sanity_check_currdev())
404 			return (true);
405 		if (dp->pd_parent != NULL) {
406 			dp = dp->pd_parent;
407 			STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
408 				text = efi_devpath_name(pp->pd_devpath);
409 				if (text != NULL) {
410 					printf("And now the part: %S\n", text);
411 					efi_free_devpath_name(text);
412 				}
413 				/*
414 				 * Roll up the ZFS special case
415 				 * for those partitions that have
416 				 * zpools on them
417 				 */
418 				if (try_as_currdev(pp))
419 					return (true);
420 			}
421 		}
422 	} else {
423 		printf("Can't find device by handle\n");
424 	}
425 
426 	/*
427 	 * Try the device handle from our loaded image first.  If that
428 	 * fails, use the device path from the loaded image and see if
429 	 * any of the nodes in that path match one of the enumerated
430 	 * handles. Currently, this handle list is only for netboot.
431 	 */
432 	if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) {
433 		set_currdev_devsw(dev, unit);
434 		if (sanity_check_currdev())
435 			return (true);
436 	}
437 
438 	copy = NULL;
439 	devpath = efi_lookup_image_devpath(IH);
440 	while (devpath != NULL) {
441 		h = efi_devpath_handle(devpath);
442 		if (h == NULL)
443 			break;
444 
445 		free(copy);
446 		copy = NULL;
447 
448 		if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) {
449 			set_currdev_devsw(dev, unit);
450 			if (sanity_check_currdev())
451 				return (true);
452 		}
453 
454 		devpath = efi_lookup_devpath(h);
455 		if (devpath != NULL) {
456 			copy = efi_devpath_trim(devpath);
457 			devpath = copy;
458 		}
459 	}
460 	free(copy);
461 
462 	return (false);
463 }
464 
465 static bool
466 interactive_interrupt(const char *msg)
467 {
468 	time_t now, then, last;
469 
470 	last = 0;
471 	now = then = getsecs();
472 	printf("%s\n", msg);
473 	if (fail_timeout == -2)			/* Always break to OK */
474 		return (true);
475 	if (fail_timeout == -1)			/* Never break to OK */
476 		return (false);
477 	do {
478 		if (last != now) {
479 			printf("press any key to interrupt reboot "
480 			    "in %d seconds\r",
481 			    fail_timeout - (int)(now - then));
482 			last = now;
483 		}
484 
485 		/* XXX no pause or timeout wait for char */
486 		if (ischar())
487 			return (true);
488 		now = getsecs();
489 	} while (now - then < fail_timeout);
490 	return (false);
491 }
492 
493 static void
494 setenv_int(const char *key, int val)
495 {
496 	char buf[20];
497 
498 	(void) snprintf(buf, sizeof (buf), "%d", val);
499 	(void) setenv(key, buf, 1);
500 }
501 
502 /*
503  * Parse ConOut (the list of consoles active) and see if we can find a
504  * serial port and/or a video port. It would be nice to also walk the
505  * ACPI name space to map the UID for the serial port to a port. The
506  * latter is especially hard.
507  */
508 static int
509 parse_uefi_con_out(void)
510 {
511 	int how, rv;
512 	int vid_seen = 0, com_seen = 0, seen = 0;
513 	size_t sz;
514 	char buf[4096], *ep;
515 	EFI_DEVICE_PATH *node;
516 	ACPI_HID_DEVICE_PATH *acpi;
517 	UART_DEVICE_PATH *uart;
518 	bool pci_pending = false;
519 
520 	how = 0;
521 	sz = sizeof (buf);
522 	rv = efi_global_getenv("ConOut", buf, &sz);
523 	if (rv != EFI_SUCCESS)
524 		rv = efi_global_getenv("ConOutDev", buf, &sz);
525 	if (rv != EFI_SUCCESS) {
526 		/*
527 		 * If we don't have any ConOut default to video.
528 		 * non-server systems may not have serial.
529 		 */
530 		goto out;
531 	}
532 	ep = buf + sz;
533 	node = (EFI_DEVICE_PATH *)buf;
534 	while ((char *)node < ep) {
535 		if (IsDevicePathEndType(node)) {
536 			if (pci_pending && vid_seen == 0)
537 				vid_seen = ++seen;
538 		}
539 		pci_pending = false;
540 		if (DevicePathType(node) == ACPI_DEVICE_PATH &&
541 		    (DevicePathSubType(node) == ACPI_DP ||
542 		    DevicePathSubType(node) == ACPI_EXTENDED_DP)) {
543 			/* Check for Serial node */
544 			acpi = (void *)node;
545 			if (EISA_ID_TO_NUM(acpi->HID) == 0x501) {
546 				setenv_int("efi_8250_uid", acpi->UID);
547 				com_seen = ++seen;
548 			}
549 		} else if (DevicePathType(node) == MESSAGING_DEVICE_PATH &&
550 		    DevicePathSubType(node) == MSG_UART_DP) {
551 			com_seen = ++seen;
552 			uart = (void *)node;
553 			setenv_int("efi_com_speed", uart->BaudRate);
554 		} else if (DevicePathType(node) == ACPI_DEVICE_PATH &&
555 		    DevicePathSubType(node) == ACPI_ADR_DP) {
556 			/* Check for AcpiAdr() Node for video */
557 			vid_seen = ++seen;
558 		} else if (DevicePathType(node) == HARDWARE_DEVICE_PATH &&
559 		    DevicePathSubType(node) == HW_PCI_DP) {
560 			/*
561 			 * Note, vmware fusion has a funky console device
562 			 *	PciRoot(0x0)/Pci(0xf,0x0)
563 			 * which we can only detect at the end since we also
564 			 * have to cope with:
565 			 *	PciRoot(0x0)/Pci(0x1f,0x0)/Serial(0x1)
566 			 * so only match it if it's last.
567 			 */
568 			pci_pending = true;
569 		}
570 		node = NextDevicePathNode(node); /* Skip the end node */
571 	}
572 
573 	/*
574 	 * Truth table for RB_MULTIPLE | RB_SERIAL
575 	 * Value		Result
576 	 * 0			Use only video console
577 	 * RB_SERIAL		Use only serial console
578 	 * RB_MULTIPLE		Use both video and serial console
579 	 *			(but video is primary so gets rc messages)
580 	 * both			Use both video and serial console
581 	 *			(but serial is primary so gets rc messages)
582 	 *
583 	 * Try to honor this as best we can. If only one of serial / video
584 	 * found, then use that. Otherwise, use the first one we found.
585 	 * This also implies if we found nothing, default to video.
586 	 */
587 	how = 0;
588 	if (vid_seen && com_seen) {
589 		how |= RB_MULTIPLE;
590 		if (com_seen < vid_seen)
591 			how |= RB_SERIAL;
592 	} else if (com_seen)
593 		how |= RB_SERIAL;
594 out:
595 	return (how);
596 }
597 
598 caddr_t
599 ptov(uintptr_t x)
600 {
601 	return ((caddr_t)x);
602 }
603 
604 static int
605 efi_serial_get_uid(EFI_DEVICE_PATH *devpath)
606 {
607 	ACPI_HID_DEVICE_PATH  *acpi;
608 
609 	while (!IsDevicePathEnd(devpath)) {
610 		if (DevicePathType(devpath) == ACPI_DEVICE_PATH &&
611 		    (DevicePathSubType(devpath) == ACPI_DP ||
612 		    DevicePathSubType(devpath) == ACPI_EXTENDED_DP)) {
613 			acpi = (ACPI_HID_DEVICE_PATH *)devpath;
614 			if (EISA_ID_TO_NUM(acpi->HID) == 0x501) {
615 				return (acpi->UID);
616 			}
617 		}
618 
619 		devpath = NextDevicePathNode(devpath);
620 	}
621 	return (-1);
622 }
623 
624 /*
625  * Walk serialio protocol handle array and find index for serial console
626  * device. The problem is, we check for acpi UID value, but we can not be sure,
627  * if it will start from 0 or 1.
628  */
629 static const char *
630 uefi_serial_console(void)
631 {
632 	UINTN bufsz;
633 	EFI_STATUS status;
634 	EFI_HANDLE *handles;
635 	int i, nhandles;
636 	unsigned long uid, lowest;
637 	char *env, *ep;
638 	extern struct console ttya;
639 	extern struct console ttyb;
640 	extern struct console ttyc;
641 	extern struct console ttyd;
642 
643 	env = getenv("efi_8250_uid");
644 	if (env == NULL)
645 		return (NULL);
646 	(void) unsetenv("efi_8250_uid");
647 	errno = 0;
648 	uid = strtoul(env, &ep, 10);
649 	if (errno != 0 || *ep != '\0')
650 		return (NULL);
651 
652 	/* if uid is 0, this is first serial port */
653 	if (uid == 0)
654 		return (ttya.c_name);
655 
656 	/*
657 	 * get buffer size
658 	 */
659 	bufsz = 0;
660 	handles = NULL;
661 	status = BS->LocateHandle(ByProtocol, &serialio, NULL, &bufsz, handles);
662 	if (status != EFI_BUFFER_TOO_SMALL)
663 		return (NULL);
664 	if ((handles = malloc(bufsz)) == NULL)
665 		return (NULL);
666 
667 	/*
668 	 * get handle array
669 	 */
670 	status = BS->LocateHandle(ByProtocol, &serialio, NULL, &bufsz, handles);
671 	if (EFI_ERROR(status)) {
672 		free(handles);
673 		return (NULL);
674 	}
675 	nhandles = (int)(bufsz / sizeof (EFI_HANDLE));
676 
677 	lowest = 255;	/* high enough value */
678 	for (i = 0; i < nhandles; i++) {
679 		EFI_DEVICE_PATH *devpath;
680 		unsigned long _uid;
681 
682 		devpath = efi_lookup_devpath(handles[i]);
683 		_uid = efi_serial_get_uid(devpath);
684 		if (_uid < lowest)
685 			lowest = _uid;
686 	}
687 	free(handles);
688 	switch (uid - lowest) {
689 	case 0:
690 		return (ttya.c_name);
691 	case 1:
692 		return (ttyb.c_name);
693 	case 2:
694 		return (ttyc.c_name);
695 	case 3:
696 		return (ttyd.c_name);
697 	}
698 	return (NULL);
699 }
700 
701 EFI_STATUS
702 main(int argc, CHAR16 *argv[])
703 {
704 	char var[128];
705 	int i, j, howto;
706 	bool vargood;
707 	void *ptr;
708 	bool has_kbd;
709 	char *s;
710 	const char *serial;
711 	EFI_DEVICE_PATH *imgpath;
712 	CHAR16 *text;
713 	EFI_STATUS status;
714 	UINT16 boot_current;
715 	size_t sz;
716 	UINT16 boot_order[100];
717 
718 	archsw.arch_autoload = efi_autoload;
719 	archsw.arch_getdev = efi_getdev;
720 	archsw.arch_copyin = efi_copyin;
721 	archsw.arch_copyout = efi_copyout;
722 	archsw.arch_readin = efi_readin;
723 	archsw.arch_loadaddr = efi_loadaddr;
724 	archsw.arch_free_loadaddr = efi_free_loadaddr;
725 #if defined(__amd64) || defined(__i386)
726 	archsw.arch_hypervisor = x86_hypervisor;
727 #endif
728 	/* Note this needs to be set before ZFS init. */
729 	archsw.arch_zfs_probe = efi_zfs_probe;
730 
731 	/* Get our loaded image protocol interface structure. */
732 	(void) OpenProtocolByHandle(IH, &imgid, (void **)&img);
733 
734 	/*
735 	 * XXX Chicken-and-egg problem; we want to have console output
736 	 * early, but some console attributes may depend on reading from
737 	 * eg. the boot device, which we can't do yet.  We can use
738 	 * printf() etc. once this is done.
739 	 */
740 	setenv("console", "text", 1);
741 	howto = parse_uefi_con_out();
742 	serial = uefi_serial_console();
743 	cons_probe();
744 	efi_getsmap();
745 
746 	if ((s = getenv("efi_com_speed")) != NULL) {
747 		char *name;
748 
749 		(void) snprintf(var, sizeof (var), "%s,8,n,1,-", s);
750 		if (asprintf(&name, "%s-mode", serial) > 0) {
751 			(void) setenv (name, var, 1);
752 			free(name);
753 		}
754 		if (asprintf(&name, "%s-spcr-mode", serial) > 0) {
755 			(void) setenv (name, var, 1);
756 			free(name);
757 		}
758 		(void) unsetenv("efi_com_speed");
759 	}
760 
761 	/* Init the time source */
762 	efi_time_init();
763 
764 	/*
765 	 * Initialise the block cache. Set the upper limit.
766 	 */
767 	bcache_init(32768, 512);
768 
769 	has_kbd = has_keyboard();
770 
771 	/*
772 	 * Parse the args to set the console settings, etc
773 	 * iPXE may be setup to pass these in. Or the optional argument in the
774 	 * boot environment was used to pass these arguments in (in which case
775 	 * neither /boot.config nor /boot/config are consulted).
776 	 *
777 	 * Loop through the args, and for each one that contains an '=' that is
778 	 * not the first character, add it to the environment.  This allows
779 	 * loader and kernel env vars to be passed on the command line.  Convert
780 	 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though
781 	 * this method is flawed for non-ASCII characters).
782 	 */
783 	for (i = 1; i < argc; i++) {
784 		if (argv[i][0] == '-') {
785 			for (j = 1; argv[i][j] != 0; j++) {
786 				int ch;
787 
788 				ch = argv[i][j];
789 				switch (ch) {
790 				case 'a':
791 					howto |= RB_ASKNAME;
792 					break;
793 				case 'd':
794 					howto |= RB_KDB;
795 					break;
796 				case 'D':
797 					howto |= RB_MULTIPLE;
798 					break;
799 				case 'h':
800 					howto |= RB_SERIAL;
801 					break;
802 				case 'm':
803 					howto |= RB_MUTE;
804 					break;
805 				case 'p':
806 					howto |= RB_PAUSE;
807 					break;
808 				case 'P':
809 					if (!has_kbd) {
810 						howto |= RB_SERIAL;
811 						howto |= RB_MULTIPLE;
812 					}
813 					break;
814 				case 'r':
815 					howto |= RB_DFLTROOT;
816 					break;
817 				case 's':
818 					howto |= RB_SINGLE;
819 					break;
820 				case 'S':
821 					if (argv[i][j + 1] == 0) {
822 						if (i + 1 == argc) {
823 							strncpy(var, "115200",
824 							    sizeof (var));
825 						} else {
826 							CHAR16 *ptr;
827 							ptr = &argv[i + 1][0];
828 							cpy16to8(ptr, var,
829 							    sizeof (var));
830 						}
831 						i++;
832 					} else {
833 						cpy16to8(&argv[i][j + 1], var,
834 						    sizeof (var));
835 					}
836 					strncat(var, ",8,n,1,-", sizeof (var));
837 					setenv("ttya-mode", var, 1);
838 					break;
839 				case 'v':
840 					howto |= RB_VERBOSE;
841 					break;
842 				}
843 			}
844 		} else {
845 			vargood = false;
846 			for (j = 0; argv[i][j] != 0; j++) {
847 				if (j == sizeof (var)) {
848 					vargood = false;
849 					break;
850 				}
851 				if (j > 0 && argv[i][j] == '=')
852 					vargood = true;
853 				var[j] = (char)argv[i][j];
854 			}
855 			if (vargood) {
856 				var[j] = 0;
857 				putenv(var);
858 			}
859 		}
860 	}
861 	for (i = 0; howto_names[i].ev != NULL; i++)
862 		if (howto & howto_names[i].mask)
863 			setenv(howto_names[i].ev, "YES", 1);
864 
865 	/*
866 	 * XXX we need fallback to this stuff after looking at the ConIn,
867 	 * ConOut and ConErr variables.
868 	 */
869 	if (howto & RB_MULTIPLE) {
870 		if (howto & RB_SERIAL)
871 			(void) snprintf(var, sizeof (var), "%s text", serial);
872 		else
873 			(void) snprintf(var, sizeof (var), "text %s", serial);
874 	} else if (howto & RB_SERIAL) {
875 		(void) snprintf(var, sizeof (var), "%s", serial);
876 	} else {
877 		(void) snprintf(var, sizeof (var), "text");
878 	}
879 	(void) setenv("console", var, 1);
880 
881 	if ((s = getenv("fail_timeout")) != NULL)
882 		fail_timeout = strtol(s, NULL, 10);
883 
884 	/*
885 	 * Scan the BLOCK IO MEDIA handles then
886 	 * march through the device switch probing for things.
887 	 */
888 	if ((i = efipart_inithandles()) == 0) {
889 		for (i = 0; devsw[i] != NULL; i++)
890 			if (devsw[i]->dv_init != NULL)
891 				(devsw[i]->dv_init)();
892 	} else
893 		printf("efipart_inithandles failed %d, expect failures", i);
894 
895 	printf("Command line arguments:");
896 	for (i = 0; i < argc; i++) {
897 		printf(" %S", argv[i]);
898 	}
899 	printf("\n");
900 
901 	printf("Image base: 0x%lx\n", (unsigned long)img->ImageBase);
902 	printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
903 	    ST->Hdr.Revision & 0xffff);
904 	printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor,
905 	    ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
906 
907 	printf("\n%s", bootprog_info);
908 
909 	/* Determine the devpath of our image so we can prefer it. */
910 	text = efi_devpath_name(img->FilePath);
911 	if (text != NULL) {
912 		printf("   Load Path: %S\n", text);
913 		efi_setenv_illumos_wcs("LoaderPath", text);
914 		efi_free_devpath_name(text);
915 	}
916 
917 	status = OpenProtocolByHandle(img->DeviceHandle, &devid,
918 	    (void **)&imgpath);
919 	if (status == EFI_SUCCESS) {
920 		text = efi_devpath_name(imgpath);
921 		if (text != NULL) {
922 			printf("   Load Device: %S\n", text);
923 			efi_setenv_illumos_wcs("LoaderDev", text);
924 			efi_free_devpath_name(text);
925 		}
926 	}
927 
928 	boot_current = 0;
929 	sz = sizeof (boot_current);
930 	efi_global_getenv("BootCurrent", &boot_current, &sz);
931 	printf("   BootCurrent: %04x\n", boot_current);
932 
933 	sz = sizeof (boot_order);
934 	efi_global_getenv("BootOrder", &boot_order, &sz);
935 	printf("   BootOrder:");
936 	for (i = 0; i < sz / sizeof (boot_order[0]); i++)
937 		printf(" %04x%s", boot_order[i],
938 		    boot_order[i] == boot_current ? "[*]" : "");
939 	printf("\n");
940 
941 	/*
942 	 * Disable the watchdog timer. By default the boot manager sets
943 	 * the timer to 5 minutes before invoking a boot option. If we
944 	 * want to return to the boot manager, we have to disable the
945 	 * watchdog timer and since we're an interactive program, we don't
946 	 * want to wait until the user types "quit". The timer may have
947 	 * fired by then. We don't care if this fails. It does not prevent
948 	 * normal functioning in any way...
949 	 */
950 	BS->SetWatchdogTimer(0, 0, 0, NULL);
951 
952 	/*
953 	 * Try and find a good currdev based on the image that was booted.
954 	 * It might be desirable here to have a short pause to allow falling
955 	 * through to the boot loader instead of returning instantly to follow
956 	 * the boot protocol and also allow an escape hatch for users wishing
957 	 * to try something different.
958 	 */
959 	if (!find_currdev(img))
960 		if (!interactive_interrupt("Failed to find bootable partition"))
961 			return (EFI_NOT_FOUND);
962 
963 	autoload_font(false);		/* Set up the font list for console. */
964 	efi_init_environment();
965 	setenv("ISADIR", "amd64", 1);	/* we only build 64bit */
966 	bi_isadir();			/* set ISADIR */
967 	acpi_detect();
968 
969 	if ((ptr = efi_get_table(&smbios3)) == NULL)
970 		ptr = efi_get_table(&smbios);
971 	smbios_detect(ptr);
972 
973 	interact(NULL);			/* doesn't return */
974 
975 	return (EFI_SUCCESS);		/* keep compiler happy */
976 }
977 
978 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
979 
980 static int
981 command_reboot(int argc __unused, char *argv[] __unused)
982 {
983 	int i;
984 
985 	for (i = 0; devsw[i] != NULL; ++i)
986 		if (devsw[i]->dv_cleanup != NULL)
987 			(devsw[i]->dv_cleanup)();
988 
989 	RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
990 
991 	/* NOTREACHED */
992 	return (CMD_ERROR);
993 }
994 
995 COMMAND_SET(poweroff, "poweroff", "power off the system", command_poweroff);
996 
997 static int
998 command_poweroff(int argc __unused, char *argv[] __unused)
999 {
1000 	int i;
1001 
1002 	for (i = 0; devsw[i] != NULL; ++i)
1003 		if (devsw[i]->dv_cleanup != NULL)
1004 			(devsw[i]->dv_cleanup)();
1005 
1006 	RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
1007 
1008 	/* NOTREACHED */
1009 	return (CMD_ERROR);
1010 }
1011 
1012 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
1013 
1014 static int
1015 command_memmap(int argc __unused, char *argv[] __unused)
1016 {
1017 	UINTN sz;
1018 	EFI_MEMORY_DESCRIPTOR *map, *p;
1019 	UINTN key, dsz;
1020 	UINT32 dver;
1021 	EFI_STATUS status;
1022 	int i, ndesc;
1023 	int rv = 0;
1024 	char line[80];
1025 
1026 	sz = 0;
1027 	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
1028 	if (status != EFI_BUFFER_TOO_SMALL) {
1029 		printf("Can't determine memory map size\n");
1030 		return (CMD_ERROR);
1031 	}
1032 	map = malloc(sz);
1033 	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
1034 	if (EFI_ERROR(status)) {
1035 		printf("Can't read memory map\n");
1036 		return (CMD_ERROR);
1037 	}
1038 
1039 	ndesc = sz / dsz;
1040 	snprintf(line, 80, "%23s %12s %12s %8s %4s\n",
1041 	    "Type", "Physical", "Virtual", "#Pages", "Attr");
1042 	pager_open();
1043 	rv = pager_output(line);
1044 	if (rv) {
1045 		pager_close();
1046 		return (CMD_OK);
1047 	}
1048 
1049 	for (i = 0, p = map; i < ndesc;
1050 	    i++, p = NextMemoryDescriptor(p, dsz)) {
1051 		snprintf(line, 80, "%23s %012jx %012jx %08jx ",
1052 		    efi_memory_type(p->Type), p->PhysicalStart,
1053 		    p->VirtualStart, p->NumberOfPages);
1054 		rv = pager_output(line);
1055 		if (rv)
1056 			break;
1057 
1058 		if (p->Attribute & EFI_MEMORY_UC)
1059 			printf("UC ");
1060 		if (p->Attribute & EFI_MEMORY_WC)
1061 			printf("WC ");
1062 		if (p->Attribute & EFI_MEMORY_WT)
1063 			printf("WT ");
1064 		if (p->Attribute & EFI_MEMORY_WB)
1065 			printf("WB ");
1066 		if (p->Attribute & EFI_MEMORY_UCE)
1067 			printf("UCE ");
1068 		if (p->Attribute & EFI_MEMORY_WP)
1069 			printf("WP ");
1070 		if (p->Attribute & EFI_MEMORY_RP)
1071 			printf("RP ");
1072 		if (p->Attribute & EFI_MEMORY_XP)
1073 			printf("XP ");
1074 		if (p->Attribute & EFI_MEMORY_NV)
1075 			printf("NV ");
1076 		if (p->Attribute & EFI_MEMORY_MORE_RELIABLE)
1077 			printf("MR ");
1078 		if (p->Attribute & EFI_MEMORY_RO)
1079 			printf("RO ");
1080 		rv = pager_output("\n");
1081 		if (rv)
1082 			break;
1083 	}
1084 
1085 	pager_close();
1086 	return (CMD_OK);
1087 }
1088 
1089 COMMAND_SET(configuration, "configuration", "print configuration tables",
1090     command_configuration);
1091 
1092 static int
1093 command_configuration(int argc __unused, char *argv[] __unused)
1094 {
1095 	UINTN i;
1096 	char *name;
1097 
1098 	printf("NumberOfTableEntries=%lu\n",
1099 	    (unsigned long)ST->NumberOfTableEntries);
1100 	for (i = 0; i < ST->NumberOfTableEntries; i++) {
1101 		EFI_GUID *guid;
1102 
1103 		printf("  ");
1104 		guid = &ST->ConfigurationTable[i].VendorGuid;
1105 
1106 		if (efi_guid_to_name(guid, &name) == true) {
1107 			printf(name);
1108 			free(name);
1109 		} else {
1110 			printf("Error while translating UUID to name");
1111 		}
1112 		printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
1113 	}
1114 
1115 	return (CMD_OK);
1116 }
1117 
1118 
1119 COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode);
1120 
1121 static int
1122 command_mode(int argc, char *argv[])
1123 {
1124 	UINTN cols, rows;
1125 	unsigned int mode;
1126 	int i;
1127 	char *cp;
1128 	EFI_STATUS status;
1129 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
1130 	EFI_CONSOLE_CONTROL_SCREEN_MODE sm;
1131 
1132 	if (plat_stdout_is_framebuffer())
1133 		sm = EfiConsoleControlScreenGraphics;
1134 	else
1135 		sm = EfiConsoleControlScreenText;
1136 
1137 	conout = ST->ConOut;
1138 
1139 	if (argc > 1) {
1140 		mode = strtol(argv[1], &cp, 0);
1141 		if (cp[0] != '\0') {
1142 			printf("Invalid mode\n");
1143 			return (CMD_ERROR);
1144 		}
1145 		status = conout->QueryMode(conout, mode, &cols, &rows);
1146 		if (EFI_ERROR(status)) {
1147 			printf("invalid mode %d\n", mode);
1148 			return (CMD_ERROR);
1149 		}
1150 		status = conout->SetMode(conout, mode);
1151 		if (EFI_ERROR(status)) {
1152 			printf("couldn't set mode %d\n", mode);
1153 			return (CMD_ERROR);
1154 		}
1155 		plat_cons_update_mode(sm);
1156 		return (CMD_OK);
1157 	}
1158 
1159 	printf("Current mode: %d\n", conout->Mode->Mode);
1160 	for (i = 0; i <= conout->Mode->MaxMode; i++) {
1161 		status = conout->QueryMode(conout, i, &cols, &rows);
1162 		if (EFI_ERROR(status))
1163 			continue;
1164 		printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols,
1165 		    (unsigned)rows);
1166 	}
1167 
1168 	if (i != 0)
1169 		printf("Select a mode with the command \"mode <number>\"\n");
1170 
1171 	return (CMD_OK);
1172 }
1173 
1174 COMMAND_SET(lsefi, "lsefi", "list EFI handles", command_lsefi);
1175 
1176 static int
1177 command_lsefi(int argc __unused, char *argv[] __unused)
1178 {
1179 	char *name;
1180 	EFI_HANDLE *buffer = NULL;
1181 	EFI_HANDLE handle;
1182 	UINTN bufsz = 0, i, j;
1183 	EFI_STATUS status;
1184 	int ret = 0;
1185 
1186 	status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
1187 	if (status != EFI_BUFFER_TOO_SMALL) {
1188 		snprintf(command_errbuf, sizeof (command_errbuf),
1189 		    "unexpected error: %lld", (long long)status);
1190 		return (CMD_ERROR);
1191 	}
1192 	if ((buffer = malloc(bufsz)) == NULL) {
1193 		sprintf(command_errbuf, "out of memory");
1194 		return (CMD_ERROR);
1195 	}
1196 
1197 	status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
1198 	if (EFI_ERROR(status)) {
1199 		free(buffer);
1200 		snprintf(command_errbuf, sizeof (command_errbuf),
1201 		    "LocateHandle() error: %lld", (long long)status);
1202 		return (CMD_ERROR);
1203 	}
1204 
1205 	pager_open();
1206 	for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) {
1207 		UINTN nproto = 0;
1208 		EFI_GUID **protocols = NULL;
1209 
1210 		handle = buffer[i];
1211 		printf("Handle %p", handle);
1212 		if (pager_output("\n"))
1213 			break;
1214 		/* device path */
1215 
1216 		status = BS->ProtocolsPerHandle(handle, &protocols, &nproto);
1217 		if (EFI_ERROR(status)) {
1218 			snprintf(command_errbuf, sizeof (command_errbuf),
1219 			    "ProtocolsPerHandle() error: %lld",
1220 			    (long long)status);
1221 			continue;
1222 		}
1223 
1224 		for (j = 0; j < nproto; j++) {
1225 			if (efi_guid_to_name(protocols[j], &name) == true) {
1226 				printf("  %s", name);
1227 				free(name);
1228 			} else {
1229 				printf("Error while translating UUID to name");
1230 			}
1231 			if ((ret = pager_output("\n")) != 0)
1232 				break;
1233 		}
1234 		BS->FreePool(protocols);
1235 		if (ret != 0)
1236 			break;
1237 	}
1238 	pager_close();
1239 	free(buffer);
1240 	return (CMD_OK);
1241 }
1242 
1243 COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset",
1244     command_lszfs);
1245 
1246 static int
1247 command_lszfs(int argc, char *argv[])
1248 {
1249 	int err;
1250 
1251 	if (argc != 2) {
1252 		command_errmsg = "wrong number of arguments";
1253 		return (CMD_ERROR);
1254 	}
1255 
1256 	err = zfs_list(argv[1]);
1257 	if (err != 0) {
1258 		command_errmsg = strerror(err);
1259 		return (CMD_ERROR);
1260 	}
1261 	return (CMD_OK);
1262 }
1263 
1264 #ifdef LOADER_FDT_SUPPORT
1265 extern int command_fdt_internal(int argc, char *argv[]);
1266 
1267 /*
1268  * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
1269  * and declaring it as extern is in contradiction with COMMAND_SET() macro
1270  * (which uses static pointer), we're defining wrapper function, which
1271  * calls the proper fdt handling routine.
1272  */
1273 static int
1274 command_fdt(int argc, char *argv[])
1275 {
1276 	return (command_fdt_internal(argc, argv));
1277 }
1278 
1279 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
1280 #endif
1281 
1282 /*
1283  * Chain load another efi loader.
1284  */
1285 static int
1286 command_chain(int argc, char *argv[])
1287 {
1288 	EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
1289 	EFI_HANDLE loaderhandle;
1290 	EFI_LOADED_IMAGE *loaded_image;
1291 	EFI_STATUS status;
1292 	struct stat st;
1293 	struct devdesc *dev;
1294 	char *name, *path;
1295 	void *buf;
1296 	int fd;
1297 
1298 	if (argc < 2) {
1299 		command_errmsg = "wrong number of arguments";
1300 		return (CMD_ERROR);
1301 	}
1302 
1303 	name = argv[1];
1304 
1305 	if ((fd = open(name, O_RDONLY)) < 0) {
1306 		command_errmsg = "no such file";
1307 		return (CMD_ERROR);
1308 	}
1309 
1310 	if (fstat(fd, &st) < -1) {
1311 		command_errmsg = "stat failed";
1312 		close(fd);
1313 		return (CMD_ERROR);
1314 	}
1315 
1316 	status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf);
1317 	if (status != EFI_SUCCESS) {
1318 		command_errmsg = "failed to allocate buffer";
1319 		close(fd);
1320 		return (CMD_ERROR);
1321 	}
1322 	if (read(fd, buf, st.st_size) != st.st_size) {
1323 		command_errmsg = "error while reading the file";
1324 		(void) BS->FreePool(buf);
1325 		close(fd);
1326 		return (CMD_ERROR);
1327 	}
1328 	close(fd);
1329 	status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle);
1330 	(void) BS->FreePool(buf);
1331 	if (status != EFI_SUCCESS) {
1332 		command_errmsg = "LoadImage failed";
1333 		return (CMD_ERROR);
1334 	}
1335 	status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID,
1336 	    (void **)&loaded_image);
1337 
1338 	if (argc > 2) {
1339 		int i, len = 0;
1340 		CHAR16 *argp;
1341 
1342 		for (i = 2; i < argc; i++)
1343 			len += strlen(argv[i]) + 1;
1344 
1345 		len *= sizeof (*argp);
1346 		loaded_image->LoadOptions = argp = malloc(len);
1347 		if (loaded_image->LoadOptions == NULL) {
1348 			(void) BS->UnloadImage(loaded_image);
1349 			return (CMD_ERROR);
1350 		}
1351 		loaded_image->LoadOptionsSize = len;
1352 		for (i = 2; i < argc; i++) {
1353 			char *ptr = argv[i];
1354 			while (*ptr)
1355 				*(argp++) = *(ptr++);
1356 			*(argp++) = ' ';
1357 		}
1358 		*(--argv) = 0;
1359 	}
1360 
1361 	if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) {
1362 		struct zfs_devdesc *z_dev;
1363 		struct disk_devdesc *d_dev;
1364 		pdinfo_t *hd, *pd;
1365 
1366 		switch (dev->d_dev->dv_type) {
1367 		case DEVT_ZFS:
1368 			z_dev = (struct zfs_devdesc *)dev;
1369 			loaded_image->DeviceHandle =
1370 			    efizfs_get_handle_by_guid(z_dev->pool_guid);
1371 			break;
1372 		case DEVT_NET:
1373 			loaded_image->DeviceHandle =
1374 			    efi_find_handle(dev->d_dev, dev->d_unit);
1375 			break;
1376 		default:
1377 			hd = efiblk_get_pdinfo(dev);
1378 			if (STAILQ_EMPTY(&hd->pd_part)) {
1379 				loaded_image->DeviceHandle = hd->pd_handle;
1380 				break;
1381 			}
1382 			d_dev = (struct disk_devdesc *)dev;
1383 			STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
1384 				/*
1385 				 * d_partition should be 255
1386 				 */
1387 				if (pd->pd_unit == d_dev->d_slice) {
1388 					loaded_image->DeviceHandle =
1389 					    pd->pd_handle;
1390 					break;
1391 				}
1392 			}
1393 			break;
1394 		}
1395 	}
1396 
1397 	dev_cleanup();
1398 	status = BS->StartImage(loaderhandle, NULL, NULL);
1399 	if (status != EFI_SUCCESS) {
1400 		command_errmsg = "StartImage failed";
1401 		free(loaded_image->LoadOptions);
1402 		loaded_image->LoadOptions = NULL;
1403 		status = BS->UnloadImage(loaded_image);
1404 		return (CMD_ERROR);
1405 	}
1406 
1407 	return (CMD_ERROR);	/* not reached */
1408 }
1409 
1410 COMMAND_SET(chain, "chain", "chain load file", command_chain);
1411