2 * Copyright (c) 2008-2010 Rui Paulo
3 * Copyright (c) 2006 Marcel Moolenaar
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/reboot.h>
45 #include <bootstrap.h>
54 #include "loader_efi.h"
56 extern char bootprog_info[];
58 struct arch_switch archsw; /* MI/MD interface boundary */
60 EFI_GUID acpi = ACPI_TABLE_GUID;
61 EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
62 EFI_GUID devid = DEVICE_PATH_PROTOCOL;
63 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
64 EFI_GUID mps = MPS_TABLE_GUID;
65 EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
66 EFI_GUID smbios = SMBIOS_TABLE_GUID;
67 EFI_GUID smbios3 = SMBIOS3_TABLE_GUID;
68 EFI_GUID dxe = DXE_SERVICES_TABLE_GUID;
69 EFI_GUID hoblist = HOB_LIST_TABLE_GUID;
70 EFI_GUID lzmadecomp = LZMA_DECOMPRESSION_GUID;
71 EFI_GUID mpcore = ARM_MP_CORE_INFO_TABLE_GUID;
72 EFI_GUID esrt = ESRT_TABLE_GUID;
73 EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID;
74 EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID;
75 EFI_GUID fdtdtb = FDT_TABLE_GUID;
76 EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL;
78 static EFI_LOADED_IMAGE *img;
81 * Number of seconds to wait for a keystroke before exiting with failure
82 * in the event no currdev is found. -2 means always break, -1 means
83 * never break, 0 means poll once and then reboot, > 0 means wait for
84 * that many seconds. "fail_timeout" can be set in the environment as
87 static int fail_timeout = 5;
91 efi_zfs_is_preferred(EFI_HANDLE *h)
93 return (h == img->DeviceHandle);
101 EFI_DEVICE_PATH *path;
102 EFI_HANDLE *hin, *hin_end, *walker;
107 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
108 * do the typical dance to get the right sized buffer.
112 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0);
113 if (status == EFI_BUFFER_TOO_SMALL) {
114 hin = (EFI_HANDLE *)malloc(sz);
115 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz,
117 if (EFI_ERROR(status))
120 if (EFI_ERROR(status))
124 * Look at each of the handles. If it supports the device path protocol,
125 * use it to get the device path for this handle. Then see if that
126 * device path matches either the USB device path for keyboards or the
127 * legacy device path for keyboards.
129 hin_end = &hin[sz / sizeof(*hin)];
130 for (walker = hin; walker < hin_end; walker++) {
131 status = BS->HandleProtocol(*walker, &devid, (VOID **)&path);
132 if (EFI_ERROR(status))
135 while (!IsDevicePathEnd(path)) {
137 * Check for the ACPI keyboard node. All PNP3xx nodes
138 * are keyboards of different flavors. Note: It is
139 * unclear of there's always a keyboard node when
140 * there's a keyboard controller, or if there's only one
141 * when a keyboard is detected at boot.
143 if (DevicePathType(path) == ACPI_DEVICE_PATH &&
144 (DevicePathSubType(path) == ACPI_DP ||
145 DevicePathSubType(path) == ACPI_EXTENDED_DP)) {
146 ACPI_HID_DEVICE_PATH *acpi;
148 acpi = (ACPI_HID_DEVICE_PATH *)(void *)path;
149 if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 &&
150 (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) {
155 * Check for USB keyboard node, if present. Unlike a
156 * PS/2 keyboard, these definitely only appear when
157 * connected to the system.
159 } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH &&
160 DevicePathSubType(path) == MSG_USB_CLASS_DP) {
161 USB_CLASS_DEVICE_PATH *usb;
163 usb = (USB_CLASS_DEVICE_PATH *)(void *)path;
164 if (usb->DeviceClass == 3 && /* HID */
165 usb->DeviceSubClass == 1 && /* Boot devices */
166 usb->DeviceProtocol == 1) { /* Boot keyboards */
171 path = NextDevicePathNode(path);
180 set_currdev_devdesc(struct devdesc *currdev)
184 devname = efi_fmtdev(currdev);
186 printf("Setting currdev to %s\n", devname);
188 env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, env_nounset);
189 env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset);
193 set_currdev_devsw(struct devsw *dev, int unit)
195 struct devdesc currdev;
198 currdev.d_unit = unit;
200 set_currdev_devdesc(&currdev);
204 set_currdev_pdinfo(pdinfo_t *dp)
208 * Disks are special: they have partitions. if the parent
209 * pointer is non-null, we're a partition not a full disk
210 * and we need to adjust currdev appropriately.
212 if (dp->pd_devsw->dv_type == DEVT_DISK) {
213 struct disk_devdesc currdev;
215 currdev.dd.d_dev = dp->pd_devsw;
216 if (dp->pd_parent == NULL) {
217 currdev.dd.d_unit = dp->pd_unit;
218 currdev.d_slice = -1;
219 currdev.d_partition = -1;
221 currdev.dd.d_unit = dp->pd_parent->pd_unit;
222 currdev.d_slice = dp->pd_unit;
223 currdev.d_partition = 255; /* Assumes GPT */
225 set_currdev_devdesc((struct devdesc *)&currdev);
227 set_currdev_devsw(dp->pd_devsw, dp->pd_unit);
232 sanity_check_currdev(void)
236 return (stat("/boot/defaults/loader.conf", &st) == 0);
241 probe_zfs_currdev(uint64_t guid)
244 struct zfs_devdesc currdev;
246 currdev.dd.d_dev = &zfs_dev;
247 currdev.dd.d_unit = 0;
248 currdev.pool_guid = guid;
249 currdev.root_guid = 0;
250 set_currdev_devdesc((struct devdesc *)&currdev);
251 devname = efi_fmtdev(&currdev);
252 init_zfs_bootenv(devname);
254 return (sanity_check_currdev());
259 try_as_currdev(pdinfo_t *hd, pdinfo_t *pp)
265 * If there's a zpool on this device, try it as a ZFS
266 * filesystem, which has somewhat different setup than all
267 * other types of fs due to imperfect loader integration.
268 * This all stems from ZFS being both a device (zpool) and
269 * a filesystem, plus the boot env feature.
271 if (efizfs_get_guid_by_handle(pp->pd_handle, &guid))
272 return (probe_zfs_currdev(guid));
275 * All other filesystems just need the pdinfo
276 * initialized in the standard way.
278 set_currdev_pdinfo(pp);
279 return (sanity_check_currdev());
283 find_currdev(EFI_LOADED_IMAGE *img)
286 EFI_DEVICE_PATH *devpath, *copy;
295 * Did efi_zfs_probe() detect the boot pool? If so, use the zpool
296 * it found, if it's sane. ZFS is the only thing that looks for
297 * disks and pools to boot. This may change in the future, however,
298 * if we allow specifying which pool to boot from via UEFI variables
299 * rather than the bootenv stuff that FreeBSD uses today.
301 if (pool_guid != 0) {
302 printf("Trying ZFS pool\n");
303 if (probe_zfs_currdev(pool_guid))
306 #endif /* EFI_ZFS_BOOT */
309 * Try to find the block device by its handle based on the
310 * image we're booting. If we can't find a sane partition,
311 * search all the other partitions of the disk. We do not
312 * search other disks because it's a violation of the UEFI
313 * boot protocol to do so. We fail and let UEFI go on to
314 * the next candidate.
316 dp = efiblk_get_pdinfo_by_handle(img->DeviceHandle);
318 text = efi_devpath_name(dp->pd_devpath);
320 printf("Trying ESP: %S\n", text);
321 efi_free_devpath_name(text);
323 set_currdev_pdinfo(dp);
324 if (sanity_check_currdev())
326 if (dp->pd_parent != NULL) {
328 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
329 text = efi_devpath_name(pp->pd_devpath);
331 printf("And now the part: %S\n", text);
332 efi_free_devpath_name(text);
335 * Roll up the ZFS special case
336 * for those partitions that have
339 if (try_as_currdev(dp, pp))
344 printf("Can't find device by handle\n");
348 * Try the device handle from our loaded image first. If that
349 * fails, use the device path from the loaded image and see if
350 * any of the nodes in that path match one of the enumerated
351 * handles. Currently, this handle list is only for netboot.
353 if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) {
354 set_currdev_devsw(dev, unit);
355 if (sanity_check_currdev())
360 devpath = efi_lookup_image_devpath(IH);
361 while (devpath != NULL) {
362 h = efi_devpath_handle(devpath);
369 if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) {
370 set_currdev_devsw(dev, unit);
371 if (sanity_check_currdev())
375 devpath = efi_lookup_devpath(h);
376 if (devpath != NULL) {
377 copy = efi_devpath_trim(devpath);
387 interactive_interrupt(const char *msg)
389 time_t now, then, last;
392 now = then = getsecs();
394 if (fail_timeout == -2) /* Always break to OK */
396 if (fail_timeout == -1) /* Never break to OK */
400 printf("press any key to interrupt reboot in %d seconds\r",
401 fail_timeout - (int)(now - then));
405 /* XXX no pause or timeout wait for char */
409 } while (now - then < fail_timeout);
414 main(int argc, CHAR16 *argv[])
423 EFI_DEVICE_PATH *imgpath;
428 UINT16 boot_order[100];
429 #if !defined(__arm__)
433 archsw.arch_autoload = efi_autoload;
434 archsw.arch_getdev = efi_getdev;
435 archsw.arch_copyin = efi_copyin;
436 archsw.arch_copyout = efi_copyout;
437 archsw.arch_readin = efi_readin;
439 /* Note this needs to be set before ZFS init. */
440 archsw.arch_zfs_probe = efi_zfs_probe;
443 /* Get our loaded image protocol interface structure. */
444 BS->HandleProtocol(IH, &imgid, (VOID**)&img);
446 /* Init the time source */
449 has_kbd = has_keyboard();
452 * XXX Chicken-and-egg problem; we want to have console output
453 * early, but some console attributes may depend on reading from
454 * eg. the boot device, which we can't do yet. We can use
455 * printf() etc. once this is done.
460 * Initialise the block cache. Set the upper limit.
462 bcache_init(32768, 512);
465 * Parse the args to set the console settings, etc
466 * boot1.efi passes these in, if it can read /boot.config or /boot/config
467 * or iPXE may be setup to pass these in. Or the optional argument in the
468 * boot environment was used to pass these arguments in (in which case
469 * neither /boot.config nor /boot/config are consulted).
471 * Loop through the args, and for each one that contains an '=' that is
472 * not the first character, add it to the environment. This allows
473 * loader and kernel env vars to be passed on the command line. Convert
474 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though this
475 * method is flawed for non-ASCII characters).
478 for (i = 1; i < argc; i++) {
479 if (argv[i][0] == '-') {
480 for (j = 1; argv[i][j] != 0; j++) {
492 howto |= RB_MULTIPLE;
505 howto |= RB_SERIAL | RB_MULTIPLE;
508 howto |= RB_DFLTROOT;
514 if (argv[i][j + 1] == 0) {
516 setenv("comconsole_speed", "115200", 1);
518 cpy16to8(&argv[i + 1][0], var,
520 setenv("comconsole_speed", var, 1);
525 cpy16to8(&argv[i][j + 1], var,
527 setenv("comconsole_speed", var, 1);
537 for (j = 0; argv[i][j] != 0; j++) {
538 if (j == sizeof(var)) {
542 if (j > 0 && argv[i][j] == '=')
544 var[j] = (char)argv[i][j];
556 * XXX we need fallback to this stuff after looking at the ConIn, ConOut and ConErr variables
558 if (howto & RB_MULTIPLE) {
559 if (howto & RB_SERIAL)
560 setenv("console", "comconsole efi" , 1);
562 setenv("console", "efi comconsole" , 1);
563 } else if (howto & RB_SERIAL) {
564 setenv("console", "comconsole" , 1);
566 setenv("console", "efi", 1);
568 if (efi_copy_init()) {
569 printf("failed to allocate staging area\n");
570 return (EFI_BUFFER_TOO_SMALL);
573 if ((s = getenv("fail_timeout")) != NULL)
574 fail_timeout = strtol(s, NULL, 10);
577 * Scan the BLOCK IO MEDIA handles then
578 * march through the device switch probing for things.
580 if ((i = efipart_inithandles()) == 0) {
581 for (i = 0; devsw[i] != NULL; i++)
582 if (devsw[i]->dv_init != NULL)
583 (devsw[i]->dv_init)();
585 printf("efipart_inithandles failed %d, expect failures", i);
587 printf("Command line arguments:");
588 for (i = 0; i < argc; i++)
589 printf(" %S", argv[i]);
592 printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
593 printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
594 ST->Hdr.Revision & 0xffff);
595 printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor,
596 ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
598 printf("\n%s", bootprog_info);
600 /* Determine the devpath of our image so we can prefer it. */
601 text = efi_devpath_name(img->FilePath);
603 printf(" Load Path: %S\n", text);
604 efi_setenv_freebsd_wcs("LoaderPath", text);
605 efi_free_devpath_name(text);
608 status = BS->HandleProtocol(img->DeviceHandle, &devid, (void **)&imgpath);
609 if (status == EFI_SUCCESS) {
610 text = efi_devpath_name(imgpath);
612 printf(" Load Device: %S\n", text);
613 efi_setenv_freebsd_wcs("LoaderDev", text);
614 efi_free_devpath_name(text);
619 sz = sizeof(boot_current);
620 efi_global_getenv("BootCurrent", &boot_current, &sz);
621 printf(" BootCurrent: %04x\n", boot_current);
623 sz = sizeof(boot_order);
624 efi_global_getenv("BootOrder", &boot_order, &sz);
625 printf(" BootOrder:");
626 for (i = 0; i < sz / sizeof(boot_order[0]); i++)
627 printf(" %04x%s", boot_order[i],
628 boot_order[i] == boot_current ? "[*]" : "");
632 * Disable the watchdog timer. By default the boot manager sets
633 * the timer to 5 minutes before invoking a boot option. If we
634 * want to return to the boot manager, we have to disable the
635 * watchdog timer and since we're an interactive program, we don't
636 * want to wait until the user types "quit". The timer may have
637 * fired by then. We don't care if this fails. It does not prevent
638 * normal functioning in any way...
640 BS->SetWatchdogTimer(0, 0, 0, NULL);
643 * Try and find a good currdev based on the image that was booted.
644 * It might be desirable here to have a short pause to allow falling
645 * through to the boot loader instead of returning instantly to follow
646 * the boot protocol and also allow an escape hatch for users wishing
647 * to try something different.
649 if (find_currdev(img) != 0)
650 if (!interactive_interrupt("Failed to find bootable partition"))
651 return (EFI_NOT_FOUND);
653 efi_init_environment();
654 setenv("LINES", "24", 1); /* optional */
656 for (k = 0; k < ST->NumberOfTableEntries; k++) {
657 guid = &ST->ConfigurationTable[k].VendorGuid;
658 #if !defined(__arm__)
659 if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) {
660 snprintf(buf, sizeof(buf), "%p",
661 ST->ConfigurationTable[k].VendorTable);
662 setenv("hint.smbios.0.mem", buf, 1);
663 smbios_detect(ST->ConfigurationTable[k].VendorTable);
669 interact(); /* doesn't return */
671 return (EFI_SUCCESS); /* keep compiler happy */
674 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
677 command_reboot(int argc, char *argv[])
681 for (i = 0; devsw[i] != NULL; ++i)
682 if (devsw[i]->dv_cleanup != NULL)
683 (devsw[i]->dv_cleanup)();
685 RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
691 COMMAND_SET(quit, "quit", "exit the loader", command_quit);
694 command_quit(int argc, char *argv[])
700 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
703 command_memmap(int argc, char *argv[])
706 EFI_MEMORY_DESCRIPTOR *map, *p;
712 static char *types[] = {
718 "RuntimeServicesCode",
719 "RuntimeServicesData",
720 "ConventionalMemory",
725 "MemoryMappedIOPortSpace",
730 status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
731 if (status != EFI_BUFFER_TOO_SMALL) {
732 printf("Can't determine memory map size\n");
736 status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
737 if (EFI_ERROR(status)) {
738 printf("Can't read memory map\n");
743 snprintf(line, sizeof(line), "%23s %12s %12s %8s %4s\n",
744 "Type", "Physical", "Virtual", "#Pages", "Attr");
746 if (pager_output(line)) {
751 for (i = 0, p = map; i < ndesc;
752 i++, p = NextMemoryDescriptor(p, dsz)) {
753 printf("%23s %012jx %012jx %08jx ", types[p->Type],
754 (uintmax_t)p->PhysicalStart, (uintmax_t)p->VirtualStart,
755 (uintmax_t)p->NumberOfPages);
756 if (p->Attribute & EFI_MEMORY_UC)
758 if (p->Attribute & EFI_MEMORY_WC)
760 if (p->Attribute & EFI_MEMORY_WT)
762 if (p->Attribute & EFI_MEMORY_WB)
764 if (p->Attribute & EFI_MEMORY_UCE)
766 if (p->Attribute & EFI_MEMORY_WP)
768 if (p->Attribute & EFI_MEMORY_RP)
770 if (p->Attribute & EFI_MEMORY_XP)
772 if (pager_output("\n"))
780 COMMAND_SET(configuration, "configuration", "print configuration tables",
781 command_configuration);
784 guid_to_string(EFI_GUID *guid)
788 sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
789 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
790 guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
791 guid->Data4[5], guid->Data4[6], guid->Data4[7]);
796 command_configuration(int argc, char *argv[])
801 snprintf(line, sizeof(line), "NumberOfTableEntries=%lu\n",
802 (unsigned long)ST->NumberOfTableEntries);
804 if (pager_output(line)) {
809 for (i = 0; i < ST->NumberOfTableEntries; i++) {
813 guid = &ST->ConfigurationTable[i].VendorGuid;
814 if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
816 else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
817 printf("ACPI Table");
818 else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
819 printf("ACPI 2.0 Table");
820 else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
821 printf("SMBIOS Table %p",
822 ST->ConfigurationTable[i].VendorTable);
823 else if (!memcmp(guid, &smbios3, sizeof(EFI_GUID)))
824 printf("SMBIOS3 Table");
825 else if (!memcmp(guid, &dxe, sizeof(EFI_GUID)))
827 else if (!memcmp(guid, &hoblist, sizeof(EFI_GUID)))
828 printf("HOB List Table");
829 else if (!memcmp(guid, &lzmadecomp, sizeof(EFI_GUID)))
830 printf("LZMA Compression");
831 else if (!memcmp(guid, &mpcore, sizeof(EFI_GUID)))
832 printf("ARM MpCore Information Table");
833 else if (!memcmp(guid, &esrt, sizeof(EFI_GUID)))
834 printf("ESRT Table");
835 else if (!memcmp(guid, &memtype, sizeof(EFI_GUID)))
836 printf("Memory Type Information Table");
837 else if (!memcmp(guid, &debugimg, sizeof(EFI_GUID)))
838 printf("Debug Image Info Table");
839 else if (!memcmp(guid, &fdtdtb, sizeof(EFI_GUID)))
842 printf("Unknown Table (%s)", guid_to_string(guid));
843 snprintf(line, sizeof(line), " at %p\n",
844 ST->ConfigurationTable[i].VendorTable);
845 if (pager_output(line))
854 COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode);
857 command_mode(int argc, char *argv[])
865 SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
866 extern void HO(void);
871 mode = strtol(argv[1], &cp, 0);
873 printf("Invalid mode\n");
876 status = conout->QueryMode(conout, mode, &cols, &rows);
877 if (EFI_ERROR(status)) {
878 printf("invalid mode %d\n", mode);
881 status = conout->SetMode(conout, mode);
882 if (EFI_ERROR(status)) {
883 printf("couldn't set mode %d\n", mode);
886 sprintf(rowenv, "%u", (unsigned)rows);
887 setenv("LINES", rowenv, 1);
888 HO(); /* set cursor */
892 printf("Current mode: %d\n", conout->Mode->Mode);
893 for (i = 0; i <= conout->Mode->MaxMode; i++) {
894 status = conout->QueryMode(conout, i, &cols, &rows);
895 if (EFI_ERROR(status))
897 printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols,
902 printf("Select a mode with the command \"mode <number>\"\n");
907 #ifdef LOADER_FDT_SUPPORT
908 extern int command_fdt_internal(int argc, char *argv[]);
911 * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
912 * and declaring it as extern is in contradiction with COMMAND_SET() macro
913 * (which uses static pointer), we're defining wrapper function, which
914 * calls the proper fdt handling routine.
917 command_fdt(int argc, char *argv[])
920 return (command_fdt_internal(argc, argv));
923 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
927 * Chain load another efi loader.
930 command_chain(int argc, char *argv[])
932 EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
933 EFI_HANDLE loaderhandle;
934 EFI_LOADED_IMAGE *loaded_image;
943 command_errmsg = "wrong number of arguments";
949 if ((fd = open(name, O_RDONLY)) < 0) {
950 command_errmsg = "no such file";
954 if (fstat(fd, &st) < -1) {
955 command_errmsg = "stat failed";
960 status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf);
961 if (status != EFI_SUCCESS) {
962 command_errmsg = "failed to allocate buffer";
966 if (read(fd, buf, st.st_size) != st.st_size) {
967 command_errmsg = "error while reading the file";
968 (void)BS->FreePool(buf);
973 status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle);
974 (void)BS->FreePool(buf);
975 if (status != EFI_SUCCESS) {
976 command_errmsg = "LoadImage failed";
979 status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
980 (void **)&loaded_image);
986 for (i = 2; i < argc; i++)
987 len += strlen(argv[i]) + 1;
989 len *= sizeof (*argp);
990 loaded_image->LoadOptions = argp = malloc (len);
991 loaded_image->LoadOptionsSize = len;
992 for (i = 2; i < argc; i++) {
995 *(argp++) = *(ptr++);
1001 if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) {
1003 struct zfs_devdesc *z_dev;
1005 struct disk_devdesc *d_dev;
1008 switch (dev->d_dev->dv_type) {
1011 z_dev = (struct zfs_devdesc *)dev;
1012 loaded_image->DeviceHandle =
1013 efizfs_get_handle_by_guid(z_dev->pool_guid);
1017 loaded_image->DeviceHandle =
1018 efi_find_handle(dev->d_dev, dev->d_unit);
1021 hd = efiblk_get_pdinfo(dev);
1022 if (STAILQ_EMPTY(&hd->pd_part)) {
1023 loaded_image->DeviceHandle = hd->pd_handle;
1026 d_dev = (struct disk_devdesc *)dev;
1027 STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
1029 * d_partition should be 255
1031 if (pd->pd_unit == (uint32_t)d_dev->d_slice) {
1032 loaded_image->DeviceHandle =
1042 status = BS->StartImage(loaderhandle, NULL, NULL);
1043 if (status != EFI_SUCCESS) {
1044 command_errmsg = "StartImage failed";
1045 free(loaded_image->LoadOptions);
1046 loaded_image->LoadOptions = NULL;
1047 status = BS->UnloadImage(loaded_image);
1051 return (CMD_ERROR); /* not reached */
1054 COMMAND_SET(chain, "chain", "chain load file", command_chain);