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