xref: /illumos-gate/usr/src/boot/sys/boot/efi/loader/main.c (revision b713c91e)
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
efi_zfs_is_preferred(EFI_HANDLE * h)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
has_keyboard(void)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
set_currdev(const char * devname)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
set_currdev_devdesc(struct devdesc * currdev)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
set_currdev_devsw(struct devsw * dev,int unit)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
set_currdev_pdinfo(pdinfo_t * dp)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
sanity_check_currdev(void)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
probe_zfs_currdev(uint64_t guid)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
try_as_currdev(pdinfo_t * pp)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
find_currdev(EFI_LOADED_IMAGE * img)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
interactive_interrupt(const char * msg)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 EFI_STATUS
main(int argc,CHAR16 * argv[])493 main(int argc, CHAR16 *argv[])
494 {
495 	char var[128];
496 	int i, j, howto;
497 	bool vargood;
498 	void *ptr;
499 	bool has_kbd;
500 	char *s;
501 	EFI_DEVICE_PATH *imgpath;
502 	CHAR16 *text;
503 	EFI_STATUS status;
504 	UINT16 boot_current;
505 	size_t sz;
506 	UINT16 boot_order[100];
507 
508 	archsw.arch_autoload = efi_autoload;
509 	archsw.arch_getdev = efi_getdev;
510 	archsw.arch_copyin = efi_copyin;
511 	archsw.arch_copyout = efi_copyout;
512 	archsw.arch_readin = efi_readin;
513 	archsw.arch_loadaddr = efi_loadaddr;
514 	archsw.arch_free_loadaddr = efi_free_loadaddr;
515 	/* Note this needs to be set before ZFS init. */
516 	archsw.arch_zfs_probe = efi_zfs_probe;
517 
518 	/* Get our loaded image protocol interface structure. */
519 	(void) OpenProtocolByHandle(IH, &imgid, (void **)&img);
520 
521 	/* Init the time source */
522 	efi_time_init();
523 
524 	has_kbd = has_keyboard();
525 
526 	/*
527 	 * XXX Chicken-and-egg problem; we want to have console output
528 	 * early, but some console attributes may depend on reading from
529 	 * eg. the boot device, which we can't do yet.  We can use
530 	 * printf() etc. once this is done.
531 	 */
532 	cons_probe();
533 	efi_getsmap();
534 
535 	/*
536 	 * Initialise the block cache. Set the upper limit.
537 	 */
538 	bcache_init(32768, 512);
539 
540 	/*
541 	 * Parse the args to set the console settings, etc
542 	 * iPXE may be setup to pass these in. Or the optional argument in the
543 	 * boot environment was used to pass these arguments in (in which case
544 	 * neither /boot.config nor /boot/config are consulted).
545 	 *
546 	 * Loop through the args, and for each one that contains an '=' that is
547 	 * not the first character, add it to the environment.  This allows
548 	 * loader and kernel env vars to be passed on the command line.  Convert
549 	 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though
550 	 * this method is flawed for non-ASCII characters).
551 	 */
552 	howto = 0;
553 	for (i = 1; i < argc; i++) {
554 		if (argv[i][0] == '-') {
555 			for (j = 1; argv[i][j] != 0; j++) {
556 				int ch;
557 
558 				ch = argv[i][j];
559 				switch (ch) {
560 				case 'a':
561 					howto |= RB_ASKNAME;
562 					break;
563 				case 'd':
564 					howto |= RB_KDB;
565 					break;
566 				case 'D':
567 					howto |= RB_MULTIPLE;
568 					break;
569 				case 'h':
570 					howto |= RB_SERIAL;
571 					break;
572 				case 'm':
573 					howto |= RB_MUTE;
574 					break;
575 				case 'p':
576 					howto |= RB_PAUSE;
577 					break;
578 				case 'P':
579 					if (!has_kbd) {
580 						howto |= RB_SERIAL;
581 						howto |= RB_MULTIPLE;
582 					}
583 					break;
584 				case 'r':
585 					howto |= RB_DFLTROOT;
586 					break;
587 				case 's':
588 					howto |= RB_SINGLE;
589 					break;
590 				case 'S':
591 					if (argv[i][j + 1] == 0) {
592 						if (i + 1 == argc) {
593 							strncpy(var, "115200",
594 							    sizeof (var));
595 						} else {
596 							CHAR16 *ptr;
597 							ptr = &argv[i + 1][0];
598 							cpy16to8(ptr, var,
599 							    sizeof (var));
600 						}
601 						i++;
602 					} else {
603 						cpy16to8(&argv[i][j + 1], var,
604 						    sizeof (var));
605 					}
606 					strncat(var, ",8,n,1,-", sizeof (var));
607 					setenv("ttya-mode", var, 1);
608 					break;
609 				case 'v':
610 					howto |= RB_VERBOSE;
611 					break;
612 				}
613 			}
614 		} else {
615 			vargood = false;
616 			for (j = 0; argv[i][j] != 0; j++) {
617 				if (j == sizeof (var)) {
618 					vargood = false;
619 					break;
620 				}
621 				if (j > 0 && argv[i][j] == '=')
622 					vargood = true;
623 				var[j] = (char)argv[i][j];
624 			}
625 			if (vargood) {
626 				var[j] = 0;
627 				putenv(var);
628 			}
629 		}
630 	}
631 	for (i = 0; howto_names[i].ev != NULL; i++)
632 		if (howto & howto_names[i].mask)
633 			setenv(howto_names[i].ev, "YES", 1);
634 
635 	/*
636 	 * XXX we need fallback to this stuff after looking at the ConIn,
637 	 * ConOut and ConErr variables.
638 	 */
639 	if (howto & RB_MULTIPLE) {
640 		if (howto & RB_SERIAL)
641 			setenv("console", "ttya text", 1);
642 		else
643 			setenv("console", "text ttya", 1);
644 	} else if (howto & RB_SERIAL) {
645 		setenv("console", "ttya", 1);
646 	} else
647 		setenv("console", "text", 1);
648 
649 	if ((s = getenv("fail_timeout")) != NULL)
650 		fail_timeout = strtol(s, NULL, 10);
651 
652 	/*
653 	 * Scan the BLOCK IO MEDIA handles then
654 	 * march through the device switch probing for things.
655 	 */
656 	if ((i = efipart_inithandles()) == 0) {
657 		for (i = 0; devsw[i] != NULL; i++)
658 			if (devsw[i]->dv_init != NULL)
659 				(devsw[i]->dv_init)();
660 	} else
661 		printf("efipart_inithandles failed %d, expect failures", i);
662 
663 	printf("Command line arguments:");
664 	for (i = 0; i < argc; i++) {
665 		printf(" %S", argv[i]);
666 	}
667 	printf("\n");
668 
669 	printf("Image base: 0x%lx\n", (unsigned long)img->ImageBase);
670 	printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
671 	    ST->Hdr.Revision & 0xffff);
672 	printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor,
673 	    ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
674 
675 	printf("\n%s", bootprog_info);
676 
677 	/* Determine the devpath of our image so we can prefer it. */
678 	text = efi_devpath_name(img->FilePath);
679 	if (text != NULL) {
680 		printf("   Load Path: %S\n", text);
681 		efi_setenv_illumos_wcs("LoaderPath", text);
682 		efi_free_devpath_name(text);
683 	}
684 
685 	status = OpenProtocolByHandle(img->DeviceHandle, &devid,
686 	    (void **)&imgpath);
687 	if (status == EFI_SUCCESS) {
688 		text = efi_devpath_name(imgpath);
689 		if (text != NULL) {
690 			printf("   Load Device: %S\n", text);
691 			efi_setenv_illumos_wcs("LoaderDev", text);
692 			efi_free_devpath_name(text);
693 		}
694 	}
695 
696 	boot_current = 0;
697 	sz = sizeof (boot_current);
698 	efi_global_getenv("BootCurrent", &boot_current, &sz);
699 	printf("   BootCurrent: %04x\n", boot_current);
700 
701 	sz = sizeof (boot_order);
702 	efi_global_getenv("BootOrder", &boot_order, &sz);
703 	printf("   BootOrder:");
704 	for (i = 0; i < sz / sizeof (boot_order[0]); i++)
705 		printf(" %04x%s", boot_order[i],
706 		    boot_order[i] == boot_current ? "[*]" : "");
707 	printf("\n");
708 
709 	/*
710 	 * Disable the watchdog timer. By default the boot manager sets
711 	 * the timer to 5 minutes before invoking a boot option. If we
712 	 * want to return to the boot manager, we have to disable the
713 	 * watchdog timer and since we're an interactive program, we don't
714 	 * want to wait until the user types "quit". The timer may have
715 	 * fired by then. We don't care if this fails. It does not prevent
716 	 * normal functioning in any way...
717 	 */
718 	BS->SetWatchdogTimer(0, 0, 0, NULL);
719 
720 	/*
721 	 * Try and find a good currdev based on the image that was booted.
722 	 * It might be desirable here to have a short pause to allow falling
723 	 * through to the boot loader instead of returning instantly to follow
724 	 * the boot protocol and also allow an escape hatch for users wishing
725 	 * to try something different.
726 	 */
727 	if (!find_currdev(img))
728 		if (!interactive_interrupt("Failed to find bootable partition"))
729 			return (EFI_NOT_FOUND);
730 
731 	autoload_font(false);		/* Set up the font list for console. */
732 	efi_init_environment();
733 	setenv("ISADIR", "amd64", 1);	/* we only build 64bit */
734 	bi_isadir();			/* set ISADIR */
735 	acpi_detect();
736 
737 	if ((ptr = efi_get_table(&smbios3)) == NULL)
738 		ptr = efi_get_table(&smbios);
739 	smbios_detect(ptr);
740 
741 	interact(NULL);			/* doesn't return */
742 
743 	return (EFI_SUCCESS);		/* keep compiler happy */
744 }
745 
746 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
747 
748 static int
command_reboot(int argc __unused,char * argv[]__unused)749 command_reboot(int argc __unused, char *argv[] __unused)
750 {
751 	int i;
752 
753 	for (i = 0; devsw[i] != NULL; ++i)
754 		if (devsw[i]->dv_cleanup != NULL)
755 			(devsw[i]->dv_cleanup)();
756 
757 	RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
758 
759 	/* NOTREACHED */
760 	return (CMD_ERROR);
761 }
762 
763 COMMAND_SET(poweroff, "poweroff", "power off the system", command_poweroff);
764 
765 static int
command_poweroff(int argc __unused,char * argv[]__unused)766 command_poweroff(int argc __unused, char *argv[] __unused)
767 {
768 	int i;
769 
770 	for (i = 0; devsw[i] != NULL; ++i)
771 		if (devsw[i]->dv_cleanup != NULL)
772 			(devsw[i]->dv_cleanup)();
773 
774 	RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
775 
776 	/* NOTREACHED */
777 	return (CMD_ERROR);
778 }
779 
780 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
781 
782 static int
command_memmap(int argc __unused,char * argv[]__unused)783 command_memmap(int argc __unused, char *argv[] __unused)
784 {
785 	UINTN sz;
786 	EFI_MEMORY_DESCRIPTOR *map, *p;
787 	UINTN key, dsz;
788 	UINT32 dver;
789 	EFI_STATUS status;
790 	int i, ndesc;
791 	int rv = 0;
792 	char line[80];
793 
794 	sz = 0;
795 	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
796 	if (status != EFI_BUFFER_TOO_SMALL) {
797 		printf("Can't determine memory map size\n");
798 		return (CMD_ERROR);
799 	}
800 	map = malloc(sz);
801 	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
802 	if (EFI_ERROR(status)) {
803 		printf("Can't read memory map\n");
804 		return (CMD_ERROR);
805 	}
806 
807 	ndesc = sz / dsz;
808 	snprintf(line, 80, "%23s %12s %12s %8s %4s\n",
809 	    "Type", "Physical", "Virtual", "#Pages", "Attr");
810 	pager_open();
811 	rv = pager_output(line);
812 	if (rv) {
813 		pager_close();
814 		return (CMD_OK);
815 	}
816 
817 	for (i = 0, p = map; i < ndesc;
818 	    i++, p = NextMemoryDescriptor(p, dsz)) {
819 		snprintf(line, 80, "%23s %012jx %012jx %08jx ",
820 		    efi_memory_type(p->Type), p->PhysicalStart,
821 		    p->VirtualStart, p->NumberOfPages);
822 		rv = pager_output(line);
823 		if (rv)
824 			break;
825 
826 		if (p->Attribute & EFI_MEMORY_UC)
827 			printf("UC ");
828 		if (p->Attribute & EFI_MEMORY_WC)
829 			printf("WC ");
830 		if (p->Attribute & EFI_MEMORY_WT)
831 			printf("WT ");
832 		if (p->Attribute & EFI_MEMORY_WB)
833 			printf("WB ");
834 		if (p->Attribute & EFI_MEMORY_UCE)
835 			printf("UCE ");
836 		if (p->Attribute & EFI_MEMORY_WP)
837 			printf("WP ");
838 		if (p->Attribute & EFI_MEMORY_RP)
839 			printf("RP ");
840 		if (p->Attribute & EFI_MEMORY_XP)
841 			printf("XP ");
842 		if (p->Attribute & EFI_MEMORY_NV)
843 			printf("NV ");
844 		if (p->Attribute & EFI_MEMORY_MORE_RELIABLE)
845 			printf("MR ");
846 		if (p->Attribute & EFI_MEMORY_RO)
847 			printf("RO ");
848 		rv = pager_output("\n");
849 		if (rv)
850 			break;
851 	}
852 
853 	pager_close();
854 	return (CMD_OK);
855 }
856 
857 COMMAND_SET(configuration, "configuration", "print configuration tables",
858     command_configuration);
859 
860 static int
command_configuration(int argc __unused,char * argv[]__unused)861 command_configuration(int argc __unused, char *argv[] __unused)
862 {
863 	UINTN i;
864 	char *name;
865 
866 	printf("NumberOfTableEntries=%lu\n",
867 	    (unsigned long)ST->NumberOfTableEntries);
868 	for (i = 0; i < ST->NumberOfTableEntries; i++) {
869 		EFI_GUID *guid;
870 
871 		printf("  ");
872 		guid = &ST->ConfigurationTable[i].VendorGuid;
873 
874 		if (efi_guid_to_name(guid, &name) == true) {
875 			printf(name);
876 			free(name);
877 		} else {
878 			printf("Error while translating UUID to name");
879 		}
880 		printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
881 	}
882 
883 	return (CMD_OK);
884 }
885 
886 
887 COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode);
888 
889 static int
command_mode(int argc,char * argv[])890 command_mode(int argc, char *argv[])
891 {
892 	UINTN cols, rows;
893 	unsigned int mode;
894 	int i;
895 	char *cp;
896 	EFI_STATUS status;
897 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
898 	EFI_CONSOLE_CONTROL_SCREEN_MODE sm;
899 
900 	if (plat_stdout_is_framebuffer())
901 		sm = EfiConsoleControlScreenGraphics;
902 	else
903 		sm = EfiConsoleControlScreenText;
904 
905 	conout = ST->ConOut;
906 
907 	if (argc > 1) {
908 		mode = strtol(argv[1], &cp, 0);
909 		if (cp[0] != '\0') {
910 			printf("Invalid mode\n");
911 			return (CMD_ERROR);
912 		}
913 		status = conout->QueryMode(conout, mode, &cols, &rows);
914 		if (EFI_ERROR(status)) {
915 			printf("invalid mode %d\n", mode);
916 			return (CMD_ERROR);
917 		}
918 		status = conout->SetMode(conout, mode);
919 		if (EFI_ERROR(status)) {
920 			printf("couldn't set mode %d\n", mode);
921 			return (CMD_ERROR);
922 		}
923 		plat_cons_update_mode(sm);
924 		return (CMD_OK);
925 	}
926 
927 	printf("Current mode: %d\n", conout->Mode->Mode);
928 	for (i = 0; i <= conout->Mode->MaxMode; i++) {
929 		status = conout->QueryMode(conout, i, &cols, &rows);
930 		if (EFI_ERROR(status))
931 			continue;
932 		printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols,
933 		    (unsigned)rows);
934 	}
935 
936 	if (i != 0)
937 		printf("Select a mode with the command \"mode <number>\"\n");
938 
939 	return (CMD_OK);
940 }
941 
942 COMMAND_SET(lsefi, "lsefi", "list EFI handles", command_lsefi);
943 
944 static int
command_lsefi(int argc __unused,char * argv[]__unused)945 command_lsefi(int argc __unused, char *argv[] __unused)
946 {
947 	char *name;
948 	EFI_HANDLE *buffer = NULL;
949 	EFI_HANDLE handle;
950 	UINTN bufsz = 0, i, j;
951 	EFI_STATUS status;
952 	int ret = 0;
953 
954 	status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
955 	if (status != EFI_BUFFER_TOO_SMALL) {
956 		snprintf(command_errbuf, sizeof (command_errbuf),
957 		    "unexpected error: %lld", (long long)status);
958 		return (CMD_ERROR);
959 	}
960 	if ((buffer = malloc(bufsz)) == NULL) {
961 		sprintf(command_errbuf, "out of memory");
962 		return (CMD_ERROR);
963 	}
964 
965 	status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
966 	if (EFI_ERROR(status)) {
967 		free(buffer);
968 		snprintf(command_errbuf, sizeof (command_errbuf),
969 		    "LocateHandle() error: %lld", (long long)status);
970 		return (CMD_ERROR);
971 	}
972 
973 	pager_open();
974 	for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) {
975 		UINTN nproto = 0;
976 		EFI_GUID **protocols = NULL;
977 
978 		handle = buffer[i];
979 		printf("Handle %p", handle);
980 		if (pager_output("\n"))
981 			break;
982 		/* device path */
983 
984 		status = BS->ProtocolsPerHandle(handle, &protocols, &nproto);
985 		if (EFI_ERROR(status)) {
986 			snprintf(command_errbuf, sizeof (command_errbuf),
987 			    "ProtocolsPerHandle() error: %lld",
988 			    (long long)status);
989 			continue;
990 		}
991 
992 		for (j = 0; j < nproto; j++) {
993 			if (efi_guid_to_name(protocols[j], &name) == true) {
994 				printf("  %s", name);
995 				free(name);
996 			} else {
997 				printf("Error while translating UUID to name");
998 			}
999 			if ((ret = pager_output("\n")) != 0)
1000 				break;
1001 		}
1002 		BS->FreePool(protocols);
1003 		if (ret != 0)
1004 			break;
1005 	}
1006 	pager_close();
1007 	free(buffer);
1008 	return (CMD_OK);
1009 }
1010 
1011 COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset",
1012     command_lszfs);
1013 
1014 static int
command_lszfs(int argc,char * argv[])1015 command_lszfs(int argc, char *argv[])
1016 {
1017 	int err;
1018 
1019 	if (argc != 2) {
1020 		command_errmsg = "wrong number of arguments";
1021 		return (CMD_ERROR);
1022 	}
1023 
1024 	err = zfs_list(argv[1]);
1025 	if (err != 0) {
1026 		command_errmsg = strerror(err);
1027 		return (CMD_ERROR);
1028 	}
1029 	return (CMD_OK);
1030 }
1031 
1032 #ifdef LOADER_FDT_SUPPORT
1033 extern int command_fdt_internal(int argc, char *argv[]);
1034 
1035 /*
1036  * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
1037  * and declaring it as extern is in contradiction with COMMAND_SET() macro
1038  * (which uses static pointer), we're defining wrapper function, which
1039  * calls the proper fdt handling routine.
1040  */
1041 static int
command_fdt(int argc,char * argv[])1042 command_fdt(int argc, char *argv[])
1043 {
1044 	return (command_fdt_internal(argc, argv));
1045 }
1046 
1047 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
1048 #endif
1049 
1050 /*
1051  * Chain load another efi loader.
1052  */
1053 static int
command_chain(int argc,char * argv[])1054 command_chain(int argc, char *argv[])
1055 {
1056 	EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
1057 	EFI_HANDLE loaderhandle;
1058 	EFI_LOADED_IMAGE *loaded_image;
1059 	EFI_STATUS status;
1060 	struct stat st;
1061 	struct devdesc *dev;
1062 	char *name, *path;
1063 	void *buf;
1064 	int fd;
1065 
1066 	if (argc < 2) {
1067 		command_errmsg = "wrong number of arguments";
1068 		return (CMD_ERROR);
1069 	}
1070 
1071 	name = argv[1];
1072 
1073 	if ((fd = open(name, O_RDONLY)) < 0) {
1074 		command_errmsg = "no such file";
1075 		return (CMD_ERROR);
1076 	}
1077 
1078 	if (fstat(fd, &st) < -1) {
1079 		command_errmsg = "stat failed";
1080 		close(fd);
1081 		return (CMD_ERROR);
1082 	}
1083 
1084 	status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf);
1085 	if (status != EFI_SUCCESS) {
1086 		command_errmsg = "failed to allocate buffer";
1087 		close(fd);
1088 		return (CMD_ERROR);
1089 	}
1090 	if (read(fd, buf, st.st_size) != st.st_size) {
1091 		command_errmsg = "error while reading the file";
1092 		(void) BS->FreePool(buf);
1093 		close(fd);
1094 		return (CMD_ERROR);
1095 	}
1096 	close(fd);
1097 	status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle);
1098 	(void) BS->FreePool(buf);
1099 	if (status != EFI_SUCCESS) {
1100 		command_errmsg = "LoadImage failed";
1101 		return (CMD_ERROR);
1102 	}
1103 	status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID,
1104 	    (void **)&loaded_image);
1105 
1106 	if (argc > 2) {
1107 		int i, len = 0;
1108 		CHAR16 *argp;
1109 
1110 		for (i = 2; i < argc; i++)
1111 			len += strlen(argv[i]) + 1;
1112 
1113 		len *= sizeof (*argp);
1114 		loaded_image->LoadOptions = argp = malloc(len);
1115 		if (loaded_image->LoadOptions == NULL) {
1116 			(void) BS->UnloadImage(loaded_image);
1117 			return (CMD_ERROR);
1118 		}
1119 		loaded_image->LoadOptionsSize = len;
1120 		for (i = 2; i < argc; i++) {
1121 			char *ptr = argv[i];
1122 			while (*ptr)
1123 				*(argp++) = *(ptr++);
1124 			*(argp++) = ' ';
1125 		}
1126 		*(--argv) = 0;
1127 	}
1128 
1129 	if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) {
1130 		struct zfs_devdesc *z_dev;
1131 		struct disk_devdesc *d_dev;
1132 		pdinfo_t *hd, *pd;
1133 
1134 		switch (dev->d_dev->dv_type) {
1135 		case DEVT_ZFS:
1136 			z_dev = (struct zfs_devdesc *)dev;
1137 			loaded_image->DeviceHandle =
1138 			    efizfs_get_handle_by_guid(z_dev->pool_guid);
1139 			break;
1140 		case DEVT_NET:
1141 			loaded_image->DeviceHandle =
1142 			    efi_find_handle(dev->d_dev, dev->d_unit);
1143 			break;
1144 		default:
1145 			hd = efiblk_get_pdinfo(dev);
1146 			if (STAILQ_EMPTY(&hd->pd_part)) {
1147 				loaded_image->DeviceHandle = hd->pd_handle;
1148 				break;
1149 			}
1150 			d_dev = (struct disk_devdesc *)dev;
1151 			STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
1152 				/*
1153 				 * d_partition should be 255
1154 				 */
1155 				if (pd->pd_unit == d_dev->d_slice) {
1156 					loaded_image->DeviceHandle =
1157 					    pd->pd_handle;
1158 					break;
1159 				}
1160 			}
1161 			break;
1162 		}
1163 	}
1164 
1165 	dev_cleanup();
1166 	status = BS->StartImage(loaderhandle, NULL, NULL);
1167 	if (status != EFI_SUCCESS) {
1168 		command_errmsg = "StartImage failed";
1169 		free(loaded_image->LoadOptions);
1170 		loaded_image->LoadOptions = NULL;
1171 		status = BS->UnloadImage(loaded_image);
1172 		return (CMD_ERROR);
1173 	}
1174 
1175 	return (CMD_ERROR);	/* not reached */
1176 }
1177 
1178 COMMAND_SET(chain, "chain", "chain load file", command_chain);
1179