xref: /freebsd/stand/efi/loader/main.c (revision 8a16b7a18f5d0b031f09832fd7752fba717e2a97)
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 __FBSDID("$FreeBSD$");
30 
31 #include <sys/disk.h>
32 #include <sys/param.h>
33 #include <sys/reboot.h>
34 #include <sys/boot.h>
35 #include <inttypes.h>
36 #include <stand.h>
37 #include <string.h>
38 #include <setjmp.h>
39 #include <disk.h>
40 
41 #include <efi.h>
42 #include <efilib.h>
43 
44 #include <uuid.h>
45 
46 #include <bootstrap.h>
47 #include <smbios.h>
48 
49 #ifdef EFI_ZFS_BOOT
50 #include <libzfs.h>
51 
52 #include "efizfs.h"
53 #endif
54 
55 #include "loader_efi.h"
56 
57 extern char bootprog_info[];
58 
59 struct arch_switch archsw;	/* MI/MD interface boundary */
60 
61 EFI_GUID acpi = ACPI_TABLE_GUID;
62 EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
63 EFI_GUID devid = DEVICE_PATH_PROTOCOL;
64 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
65 EFI_GUID mps = MPS_TABLE_GUID;
66 EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
67 EFI_GUID smbios = SMBIOS_TABLE_GUID;
68 EFI_GUID dxe = DXE_SERVICES_TABLE_GUID;
69 EFI_GUID hoblist = HOB_LIST_TABLE_GUID;
70 EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID;
71 EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID;
72 EFI_GUID fdtdtb = FDT_TABLE_GUID;
73 EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL;
74 
75 static EFI_LOADED_IMAGE *img;
76 
77 #ifdef	EFI_ZFS_BOOT
78 bool
79 efi_zfs_is_preferred(EFI_HANDLE *h)
80 {
81         return (h == img->DeviceHandle);
82 }
83 #endif
84 
85 static int
86 has_keyboard(void)
87 {
88 	EFI_STATUS status;
89 	EFI_DEVICE_PATH *path;
90 	EFI_HANDLE *hin, *hin_end, *walker;
91 	UINTN sz;
92 	int retval = 0;
93 
94 	/*
95 	 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
96 	 * do the typical dance to get the right sized buffer.
97 	 */
98 	sz = 0;
99 	hin = NULL;
100 	status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0);
101 	if (status == EFI_BUFFER_TOO_SMALL) {
102 		hin = (EFI_HANDLE *)malloc(sz);
103 		status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz,
104 		    hin);
105 		if (EFI_ERROR(status))
106 			free(hin);
107 	}
108 	if (EFI_ERROR(status))
109 		return retval;
110 
111 	/*
112 	 * Look at each of the handles. If it supports the device path protocol,
113 	 * use it to get the device path for this handle. Then see if that
114 	 * device path matches either the USB device path for keyboards or the
115 	 * legacy device path for keyboards.
116 	 */
117 	hin_end = &hin[sz / sizeof(*hin)];
118 	for (walker = hin; walker < hin_end; walker++) {
119 		status = BS->HandleProtocol(*walker, &devid, (VOID **)&path);
120 		if (EFI_ERROR(status))
121 			continue;
122 
123 		while (!IsDevicePathEnd(path)) {
124 			/*
125 			 * Check for the ACPI keyboard node. All PNP3xx nodes
126 			 * are keyboards of different flavors. Note: It is
127 			 * unclear of there's always a keyboard node when
128 			 * there's a keyboard controller, or if there's only one
129 			 * when a keyboard is detected at boot.
130 			 */
131 			if (DevicePathType(path) == ACPI_DEVICE_PATH &&
132 			    (DevicePathSubType(path) == ACPI_DP ||
133 				DevicePathSubType(path) == ACPI_EXTENDED_DP)) {
134 				ACPI_HID_DEVICE_PATH  *acpi;
135 
136 				acpi = (ACPI_HID_DEVICE_PATH *)(void *)path;
137 				if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 &&
138 				    (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) {
139 					retval = 1;
140 					goto out;
141 				}
142 			/*
143 			 * Check for USB keyboard node, if present. Unlike a
144 			 * PS/2 keyboard, these definitely only appear when
145 			 * connected to the system.
146 			 */
147 			} else if (DevicePathType(path) == MESSAGING_DEVICE_PATH &&
148 			    DevicePathSubType(path) == MSG_USB_CLASS_DP) {
149 				USB_CLASS_DEVICE_PATH *usb;
150 
151 				usb = (USB_CLASS_DEVICE_PATH *)(void *)path;
152 				if (usb->DeviceClass == 3 && /* HID */
153 				    usb->DeviceSubClass == 1 && /* Boot devices */
154 				    usb->DeviceProtocol == 1) { /* Boot keyboards */
155 					retval = 1;
156 					goto out;
157 				}
158 			}
159 			path = NextDevicePathNode(path);
160 		}
161 	}
162 out:
163 	free(hin);
164 	return retval;
165 }
166 
167 static void
168 set_devdesc_currdev(struct devsw *dev, int unit)
169 {
170 	struct devdesc currdev;
171 	char *devname;
172 
173 	currdev.d_dev = dev;
174 	currdev.d_type = currdev.d_dev->dv_type;
175 	currdev.d_unit = unit;
176 	currdev.d_opendata = NULL;
177 	devname = efi_fmtdev(&currdev);
178 
179 	env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
180 	    env_nounset);
181 	env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset);
182 }
183 
184 static int
185 find_currdev(EFI_LOADED_IMAGE *img)
186 {
187 	pdinfo_list_t *pdi_list;
188 	pdinfo_t *dp, *pp;
189 	EFI_DEVICE_PATH *devpath, *copy;
190 	EFI_HANDLE h;
191 	char *devname;
192 	struct devsw *dev;
193 	int unit;
194 	uint64_t extra;
195 
196 #ifdef EFI_ZFS_BOOT
197 	/* Did efi_zfs_probe() detect the boot pool? */
198 	if (pool_guid != 0) {
199 		struct zfs_devdesc currdev;
200 
201 		currdev.d_dev = &zfs_dev;
202 		currdev.d_unit = 0;
203 		currdev.d_type = currdev.d_dev->dv_type;
204 		currdev.d_opendata = NULL;
205 		currdev.pool_guid = pool_guid;
206 		currdev.root_guid = 0;
207 		devname = efi_fmtdev(&currdev);
208 
209 		env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev,
210 		    env_nounset);
211 		env_setenv("loaddev", EV_VOLATILE, devname, env_noset,
212 		    env_nounset);
213 		init_zfs_bootenv(devname);
214 		return (0);
215 	}
216 #endif /* EFI_ZFS_BOOT */
217 
218 	/* We have device lists for hd, cd, fd, walk them all. */
219 	pdi_list = efiblk_get_pdinfo_list(&efipart_hddev);
220 	STAILQ_FOREACH(dp, pdi_list, pd_link) {
221 		struct disk_devdesc currdev;
222 
223 		currdev.d_dev = &efipart_hddev;
224 		currdev.d_type = currdev.d_dev->dv_type;
225 		currdev.d_unit = dp->pd_unit;
226 		currdev.d_opendata = NULL;
227 		currdev.d_slice = -1;
228 		currdev.d_partition = -1;
229 
230 		if (dp->pd_handle == img->DeviceHandle) {
231 			devname = efi_fmtdev(&currdev);
232 
233 			env_setenv("currdev", EV_VOLATILE, devname,
234 			    efi_setcurrdev, env_nounset);
235 			env_setenv("loaddev", EV_VOLATILE, devname,
236 			    env_noset, env_nounset);
237 			return (0);
238 		}
239 		/* Assuming GPT partitioning. */
240 		STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
241 			if (pp->pd_handle == img->DeviceHandle) {
242 				currdev.d_slice = pp->pd_unit;
243 				currdev.d_partition = 255;
244 				devname = efi_fmtdev(&currdev);
245 
246 				env_setenv("currdev", EV_VOLATILE, devname,
247 				    efi_setcurrdev, env_nounset);
248 				env_setenv("loaddev", EV_VOLATILE, devname,
249 				    env_noset, env_nounset);
250 				return (0);
251 			}
252 		}
253 	}
254 
255 	pdi_list = efiblk_get_pdinfo_list(&efipart_cddev);
256 	STAILQ_FOREACH(dp, pdi_list, pd_link) {
257 		if (dp->pd_handle == img->DeviceHandle ||
258 		    dp->pd_alias == img->DeviceHandle) {
259 			set_devdesc_currdev(&efipart_cddev, dp->pd_unit);
260 			return (0);
261 		}
262 	}
263 
264 	pdi_list = efiblk_get_pdinfo_list(&efipart_fddev);
265 	STAILQ_FOREACH(dp, pdi_list, pd_link) {
266 		if (dp->pd_handle == img->DeviceHandle) {
267 			set_devdesc_currdev(&efipart_fddev, dp->pd_unit);
268 			return (0);
269 		}
270 	}
271 
272 	/*
273 	 * Try the device handle from our loaded image first.  If that
274 	 * fails, use the device path from the loaded image and see if
275 	 * any of the nodes in that path match one of the enumerated
276 	 * handles.
277 	 */
278 	if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) {
279 		set_devdesc_currdev(dev, unit);
280 		return (0);
281 	}
282 
283 	copy = NULL;
284 	devpath = efi_lookup_image_devpath(IH);
285 	while (devpath != NULL) {
286 		h = efi_devpath_handle(devpath);
287 		if (h == NULL)
288 			break;
289 
290 		free(copy);
291 		copy = NULL;
292 
293 		if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) {
294 			set_devdesc_currdev(dev, unit);
295 			return (0);
296 		}
297 
298 		devpath = efi_lookup_devpath(h);
299 		if (devpath != NULL) {
300 			copy = efi_devpath_trim(devpath);
301 			devpath = copy;
302 		}
303 	}
304 	free(copy);
305 
306 	return (ENOENT);
307 }
308 
309 EFI_STATUS
310 main(int argc, CHAR16 *argv[])
311 {
312 	char var[128];
313 	EFI_GUID *guid;
314 	int i, j, vargood, howto;
315 	UINTN k;
316 	int has_kbd;
317 #if !defined(__arm__)
318 	char buf[40];
319 #endif
320 
321 	archsw.arch_autoload = efi_autoload;
322 	archsw.arch_getdev = efi_getdev;
323 	archsw.arch_copyin = efi_copyin;
324 	archsw.arch_copyout = efi_copyout;
325 	archsw.arch_readin = efi_readin;
326 #ifdef EFI_ZFS_BOOT
327 	/* Note this needs to be set before ZFS init. */
328 	archsw.arch_zfs_probe = efi_zfs_probe;
329 #endif
330 
331         /* Get our loaded image protocol interface structure. */
332 	BS->HandleProtocol(IH, &imgid, (VOID**)&img);
333 
334 	/* Init the time source */
335 	efi_time_init();
336 
337 	has_kbd = has_keyboard();
338 
339 	/*
340 	 * XXX Chicken-and-egg problem; we want to have console output
341 	 * early, but some console attributes may depend on reading from
342 	 * eg. the boot device, which we can't do yet.  We can use
343 	 * printf() etc. once this is done.
344 	 */
345 	cons_probe();
346 
347 	/*
348 	 * Initialise the block cache. Set the upper limit.
349 	 */
350 	bcache_init(32768, 512);
351 
352 	/*
353 	 * Parse the args to set the console settings, etc
354 	 * boot1.efi passes these in, if it can read /boot.config or /boot/config
355 	 * or iPXE may be setup to pass these in.
356 	 *
357 	 * Loop through the args, and for each one that contains an '=' that is
358 	 * not the first character, add it to the environment.  This allows
359 	 * loader and kernel env vars to be passed on the command line.  Convert
360 	 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied.
361 	 */
362 	howto = 0;
363 	for (i = 1; i < argc; i++) {
364 		if (argv[i][0] == '-') {
365 			for (j = 1; argv[i][j] != 0; j++) {
366 				int ch;
367 
368 				ch = argv[i][j];
369 				switch (ch) {
370 				case 'a':
371 					howto |= RB_ASKNAME;
372 					break;
373 				case 'd':
374 					howto |= RB_KDB;
375 					break;
376 				case 'D':
377 					howto |= RB_MULTIPLE;
378 					break;
379 				case 'h':
380 					howto |= RB_SERIAL;
381 					break;
382 				case 'm':
383 					howto |= RB_MUTE;
384 					break;
385 				case 'p':
386 					howto |= RB_PAUSE;
387 					break;
388 				case 'P':
389 					if (!has_kbd)
390 						howto |= RB_SERIAL | RB_MULTIPLE;
391 					break;
392 				case 'r':
393 					howto |= RB_DFLTROOT;
394 					break;
395 				case 's':
396 					howto |= RB_SINGLE;
397 					break;
398 				case 'S':
399 					if (argv[i][j + 1] == 0) {
400 						if (i + 1 == argc) {
401 							setenv("comconsole_speed", "115200", 1);
402 						} else {
403 							cpy16to8(&argv[i + 1][0], var,
404 							    sizeof(var));
405 							setenv("comconsole_speed", var, 1);
406 						}
407 						i++;
408 						break;
409 					} else {
410 						cpy16to8(&argv[i][j + 1], var,
411 						    sizeof(var));
412 						setenv("comconsole_speed", var, 1);
413 						break;
414 					}
415 				case 'v':
416 					howto |= RB_VERBOSE;
417 					break;
418 				}
419 			}
420 		} else {
421 			vargood = 0;
422 			for (j = 0; argv[i][j] != 0; j++) {
423 				if (j == sizeof(var)) {
424 					vargood = 0;
425 					break;
426 				}
427 				if (j > 0 && argv[i][j] == '=')
428 					vargood = 1;
429 				var[j] = (char)argv[i][j];
430 			}
431 			if (vargood) {
432 				var[j] = 0;
433 				putenv(var);
434 			}
435 		}
436 	}
437 	for (i = 0; howto_names[i].ev != NULL; i++)
438 		if (howto & howto_names[i].mask)
439 			setenv(howto_names[i].ev, "YES", 1);
440 	if (howto & RB_MULTIPLE) {
441 		if (howto & RB_SERIAL)
442 			setenv("console", "comconsole efi" , 1);
443 		else
444 			setenv("console", "efi comconsole" , 1);
445 	} else if (howto & RB_SERIAL) {
446 		setenv("console", "comconsole" , 1);
447 	}
448 
449 	if (efi_copy_init()) {
450 		printf("failed to allocate staging area\n");
451 		return (EFI_BUFFER_TOO_SMALL);
452 	}
453 
454 	/*
455 	 * March through the device switch probing for things.
456 	 */
457 	for (i = 0; devsw[i] != NULL; i++)
458 		if (devsw[i]->dv_init != NULL)
459 			(devsw[i]->dv_init)();
460 
461 	printf("Command line arguments:");
462 	for (i = 0; i < argc; i++)
463 		printf(" %S", argv[i]);
464 	printf("\n");
465 
466 	printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
467 	printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
468 	    ST->Hdr.Revision & 0xffff);
469 	printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor,
470 	    ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
471 
472 	printf("\n%s", bootprog_info);
473 
474 	/*
475 	 * Disable the watchdog timer. By default the boot manager sets
476 	 * the timer to 5 minutes before invoking a boot option. If we
477 	 * want to return to the boot manager, we have to disable the
478 	 * watchdog timer and since we're an interactive program, we don't
479 	 * want to wait until the user types "quit". The timer may have
480 	 * fired by then. We don't care if this fails. It does not prevent
481 	 * normal functioning in any way...
482 	 */
483 	BS->SetWatchdogTimer(0, 0, 0, NULL);
484 
485 	if (find_currdev(img) != 0)
486 		return (EFI_NOT_FOUND);
487 
488 	efi_init_environment();
489 	setenv("LINES", "24", 1);	/* optional */
490 
491 	for (k = 0; k < ST->NumberOfTableEntries; k++) {
492 		guid = &ST->ConfigurationTable[k].VendorGuid;
493 #if !defined(__arm__)
494 		if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) {
495 			snprintf(buf, sizeof(buf), "%p",
496 			    ST->ConfigurationTable[k].VendorTable);
497 			setenv("hint.smbios.0.mem", buf, 1);
498 			smbios_detect(ST->ConfigurationTable[k].VendorTable);
499 			break;
500 		}
501 #endif
502 	}
503 
504 	interact(NULL);			/* doesn't return */
505 
506 	return (EFI_SUCCESS);		/* keep compiler happy */
507 }
508 
509 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
510 
511 static int
512 command_reboot(int argc, char *argv[])
513 {
514 	int i;
515 
516 	for (i = 0; devsw[i] != NULL; ++i)
517 		if (devsw[i]->dv_cleanup != NULL)
518 			(devsw[i]->dv_cleanup)();
519 
520 	RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
521 
522 	/* NOTREACHED */
523 	return (CMD_ERROR);
524 }
525 
526 COMMAND_SET(quit, "quit", "exit the loader", command_quit);
527 
528 static int
529 command_quit(int argc, char *argv[])
530 {
531 	exit(0);
532 	return (CMD_OK);
533 }
534 
535 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
536 
537 static int
538 command_memmap(int argc, char *argv[])
539 {
540 	UINTN sz;
541 	EFI_MEMORY_DESCRIPTOR *map, *p;
542 	UINTN key, dsz;
543 	UINT32 dver;
544 	EFI_STATUS status;
545 	int i, ndesc;
546 	char line[80];
547 	static char *types[] = {
548 	    "Reserved",
549 	    "LoaderCode",
550 	    "LoaderData",
551 	    "BootServicesCode",
552 	    "BootServicesData",
553 	    "RuntimeServicesCode",
554 	    "RuntimeServicesData",
555 	    "ConventionalMemory",
556 	    "UnusableMemory",
557 	    "ACPIReclaimMemory",
558 	    "ACPIMemoryNVS",
559 	    "MemoryMappedIO",
560 	    "MemoryMappedIOPortSpace",
561 	    "PalCode"
562 	};
563 
564 	sz = 0;
565 	status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
566 	if (status != EFI_BUFFER_TOO_SMALL) {
567 		printf("Can't determine memory map size\n");
568 		return (CMD_ERROR);
569 	}
570 	map = malloc(sz);
571 	status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
572 	if (EFI_ERROR(status)) {
573 		printf("Can't read memory map\n");
574 		return (CMD_ERROR);
575 	}
576 
577 	ndesc = sz / dsz;
578 	snprintf(line, sizeof(line), "%23s %12s %12s %8s %4s\n",
579 	    "Type", "Physical", "Virtual", "#Pages", "Attr");
580 	pager_open();
581 	if (pager_output(line)) {
582 		pager_close();
583 		return (CMD_OK);
584 	}
585 
586 	for (i = 0, p = map; i < ndesc;
587 	     i++, p = NextMemoryDescriptor(p, dsz)) {
588 		printf("%23s %012jx %012jx %08jx ", types[p->Type],
589 		    (uintmax_t)p->PhysicalStart, (uintmax_t)p->VirtualStart,
590 		    (uintmax_t)p->NumberOfPages);
591 		if (p->Attribute & EFI_MEMORY_UC)
592 			printf("UC ");
593 		if (p->Attribute & EFI_MEMORY_WC)
594 			printf("WC ");
595 		if (p->Attribute & EFI_MEMORY_WT)
596 			printf("WT ");
597 		if (p->Attribute & EFI_MEMORY_WB)
598 			printf("WB ");
599 		if (p->Attribute & EFI_MEMORY_UCE)
600 			printf("UCE ");
601 		if (p->Attribute & EFI_MEMORY_WP)
602 			printf("WP ");
603 		if (p->Attribute & EFI_MEMORY_RP)
604 			printf("RP ");
605 		if (p->Attribute & EFI_MEMORY_XP)
606 			printf("XP ");
607 		if (pager_output("\n"))
608 			break;
609 	}
610 
611 	pager_close();
612 	return (CMD_OK);
613 }
614 
615 COMMAND_SET(configuration, "configuration", "print configuration tables",
616     command_configuration);
617 
618 static const char *
619 guid_to_string(EFI_GUID *guid)
620 {
621 	static char buf[40];
622 
623 	sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
624 	    guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
625 	    guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
626 	    guid->Data4[5], guid->Data4[6], guid->Data4[7]);
627 	return (buf);
628 }
629 
630 static int
631 command_configuration(int argc, char *argv[])
632 {
633 	char line[80];
634 	UINTN i;
635 
636 	snprintf(line, sizeof(line), "NumberOfTableEntries=%lu\n",
637 		(unsigned long)ST->NumberOfTableEntries);
638 	pager_open();
639 	if (pager_output(line)) {
640 		pager_close();
641 		return (CMD_OK);
642 	}
643 
644 	for (i = 0; i < ST->NumberOfTableEntries; i++) {
645 		EFI_GUID *guid;
646 
647 		printf("  ");
648 		guid = &ST->ConfigurationTable[i].VendorGuid;
649 		if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
650 			printf("MPS Table");
651 		else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
652 			printf("ACPI Table");
653 		else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
654 			printf("ACPI 2.0 Table");
655 		else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
656 			printf("SMBIOS Table %p",
657 			    ST->ConfigurationTable[i].VendorTable);
658 		else if (!memcmp(guid, &dxe, sizeof(EFI_GUID)))
659 			printf("DXE Table");
660 		else if (!memcmp(guid, &hoblist, sizeof(EFI_GUID)))
661 			printf("HOB List Table");
662 		else if (!memcmp(guid, &memtype, sizeof(EFI_GUID)))
663 			printf("Memory Type Information Table");
664 		else if (!memcmp(guid, &debugimg, sizeof(EFI_GUID)))
665 			printf("Debug Image Info Table");
666 		else if (!memcmp(guid, &fdtdtb, sizeof(EFI_GUID)))
667 			printf("FDT Table");
668 		else
669 			printf("Unknown Table (%s)", guid_to_string(guid));
670 		snprintf(line, sizeof(line), " at %p\n",
671 		    ST->ConfigurationTable[i].VendorTable);
672 		if (pager_output(line))
673 			break;
674 	}
675 
676 	pager_close();
677 	return (CMD_OK);
678 }
679 
680 
681 COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode);
682 
683 static int
684 command_mode(int argc, char *argv[])
685 {
686 	UINTN cols, rows;
687 	unsigned int mode;
688 	int i;
689 	char *cp;
690 	char rowenv[8];
691 	EFI_STATUS status;
692 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
693 	extern void HO(void);
694 
695 	conout = ST->ConOut;
696 
697 	if (argc > 1) {
698 		mode = strtol(argv[1], &cp, 0);
699 		if (cp[0] != '\0') {
700 			printf("Invalid mode\n");
701 			return (CMD_ERROR);
702 		}
703 		status = conout->QueryMode(conout, mode, &cols, &rows);
704 		if (EFI_ERROR(status)) {
705 			printf("invalid mode %d\n", mode);
706 			return (CMD_ERROR);
707 		}
708 		status = conout->SetMode(conout, mode);
709 		if (EFI_ERROR(status)) {
710 			printf("couldn't set mode %d\n", mode);
711 			return (CMD_ERROR);
712 		}
713 		sprintf(rowenv, "%u", (unsigned)rows);
714 		setenv("LINES", rowenv, 1);
715 		HO();		/* set cursor */
716 		return (CMD_OK);
717 	}
718 
719 	printf("Current mode: %d\n", conout->Mode->Mode);
720 	for (i = 0; i <= conout->Mode->MaxMode; i++) {
721 		status = conout->QueryMode(conout, i, &cols, &rows);
722 		if (EFI_ERROR(status))
723 			continue;
724 		printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols,
725 		    (unsigned)rows);
726 	}
727 
728 	if (i != 0)
729 		printf("Select a mode with the command \"mode <number>\"\n");
730 
731 	return (CMD_OK);
732 }
733 
734 #ifdef EFI_ZFS_BOOT
735 COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset",
736     command_lszfs);
737 
738 static int
739 command_lszfs(int argc, char *argv[])
740 {
741 	int err;
742 
743 	if (argc != 2) {
744 		command_errmsg = "wrong number of arguments";
745 		return (CMD_ERROR);
746 	}
747 
748 	err = zfs_list(argv[1]);
749 	if (err != 0) {
750 		command_errmsg = strerror(err);
751 		return (CMD_ERROR);
752 	}
753 	return (CMD_OK);
754 }
755 
756 COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments",
757 	    command_reloadbe);
758 
759 static int
760 command_reloadbe(int argc, char *argv[])
761 {
762 	int err;
763 	char *root;
764 
765 	if (argc > 2) {
766 		command_errmsg = "wrong number of arguments";
767 		return (CMD_ERROR);
768 	}
769 
770 	if (argc == 2) {
771 		err = zfs_bootenv(argv[1]);
772 	} else {
773 		root = getenv("zfs_be_root");
774 		if (root == NULL) {
775 			return (CMD_OK);
776 		}
777 		err = zfs_bootenv(root);
778 	}
779 
780 	if (err != 0) {
781 		command_errmsg = strerror(err);
782 		return (CMD_ERROR);
783 	}
784 
785 	return (CMD_OK);
786 }
787 #endif
788 
789 #ifdef LOADER_FDT_SUPPORT
790 extern int command_fdt_internal(int argc, char *argv[]);
791 
792 /*
793  * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
794  * and declaring it as extern is in contradiction with COMMAND_SET() macro
795  * (which uses static pointer), we're defining wrapper function, which
796  * calls the proper fdt handling routine.
797  */
798 static int
799 command_fdt(int argc, char *argv[])
800 {
801 
802 	return (command_fdt_internal(argc, argv));
803 }
804 
805 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
806 #endif
807 
808 /*
809  * Chain load another efi loader.
810  */
811 static int
812 command_chain(int argc, char *argv[])
813 {
814 	EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
815 	EFI_HANDLE loaderhandle;
816 	EFI_LOADED_IMAGE *loaded_image;
817 	EFI_STATUS status;
818 	struct stat st;
819 	struct devdesc *dev;
820 	char *name, *path;
821 	void *buf;
822 	int fd;
823 
824 	if (argc < 2) {
825 		command_errmsg = "wrong number of arguments";
826 		return (CMD_ERROR);
827 	}
828 
829 	name = argv[1];
830 
831 	if ((fd = open(name, O_RDONLY)) < 0) {
832 		command_errmsg = "no such file";
833 		return (CMD_ERROR);
834 	}
835 
836 	if (fstat(fd, &st) < -1) {
837 		command_errmsg = "stat failed";
838 		close(fd);
839 		return (CMD_ERROR);
840 	}
841 
842 	status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf);
843 	if (status != EFI_SUCCESS) {
844 		command_errmsg = "failed to allocate buffer";
845 		close(fd);
846 		return (CMD_ERROR);
847 	}
848 	if (read(fd, buf, st.st_size) != st.st_size) {
849 		command_errmsg = "error while reading the file";
850 		(void)BS->FreePool(buf);
851 		close(fd);
852 		return (CMD_ERROR);
853 	}
854 	close(fd);
855 	status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle);
856 	(void)BS->FreePool(buf);
857 	if (status != EFI_SUCCESS) {
858 		command_errmsg = "LoadImage failed";
859 		return (CMD_ERROR);
860 	}
861 	status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
862 	    (void **)&loaded_image);
863 
864 	if (argc > 2) {
865 		int i, len = 0;
866 		CHAR16 *argp;
867 
868 		for (i = 2; i < argc; i++)
869 			len += strlen(argv[i]) + 1;
870 
871 		len *= sizeof (*argp);
872 		loaded_image->LoadOptions = argp = malloc (len);
873 		loaded_image->LoadOptionsSize = len;
874 		for (i = 2; i < argc; i++) {
875 			char *ptr = argv[i];
876 			while (*ptr)
877 				*(argp++) = *(ptr++);
878 			*(argp++) = ' ';
879 		}
880 		*(--argv) = 0;
881 	}
882 
883 	if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) {
884 #ifdef EFI_ZFS_BOOT
885 		struct zfs_devdesc *z_dev;
886 #endif
887 		struct disk_devdesc *d_dev;
888 		pdinfo_t *hd, *pd;
889 
890 		switch (dev->d_type) {
891 #ifdef EFI_ZFS_BOOT
892 		case DEVT_ZFS:
893 			z_dev = (struct zfs_devdesc *)dev;
894 			loaded_image->DeviceHandle =
895 			    efizfs_get_handle_by_guid(z_dev->pool_guid);
896 			break;
897 #endif
898 		case DEVT_NET:
899 			loaded_image->DeviceHandle =
900 			    efi_find_handle(dev->d_dev, dev->d_unit);
901 			break;
902 		default:
903 			hd = efiblk_get_pdinfo(dev);
904 			if (STAILQ_EMPTY(&hd->pd_part)) {
905 				loaded_image->DeviceHandle = hd->pd_handle;
906 				break;
907 			}
908 			d_dev = (struct disk_devdesc *)dev;
909 			STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
910 				/*
911 				 * d_partition should be 255
912 				 */
913 				if (pd->pd_unit == (uint32_t)d_dev->d_slice) {
914 					loaded_image->DeviceHandle =
915 					    pd->pd_handle;
916 					break;
917 				}
918 			}
919 			break;
920 		}
921 	}
922 
923 	dev_cleanup();
924 	status = BS->StartImage(loaderhandle, NULL, NULL);
925 	if (status != EFI_SUCCESS) {
926 		command_errmsg = "StartImage failed";
927 		free(loaded_image->LoadOptions);
928 		loaded_image->LoadOptions = NULL;
929 		status = BS->UnloadImage(loaded_image);
930 		return (CMD_ERROR);
931 	}
932 
933 	return (CMD_ERROR);	/* not reached */
934 }
935 
936 COMMAND_SET(chain, "chain", "chain load file", command_chain);
937