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