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