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>
31 #include <sys/param.h>
32 #include <sys/reboot.h>
34 #include <sys/consplat.h>
47 #include <bootstrap.h>
54 #include "loader_efi.h"
56 struct arch_switch archsw
; /* MI/MD interface boundary */
58 EFI_GUID devid
= DEVICE_PATH_PROTOCOL
;
59 EFI_GUID imgid
= LOADED_IMAGE_PROTOCOL
;
60 EFI_GUID smbios
= SMBIOS_TABLE_GUID
;
61 EFI_GUID smbios3
= SMBIOS3_TABLE_GUID
;
62 EFI_GUID inputid
= SIMPLE_TEXT_INPUT_PROTOCOL
;
64 extern void acpi_detect(void);
65 extern void efi_getsmap(void);
67 static EFI_LOADED_IMAGE
*img
;
70 * Number of seconds to wait for a keystroke before exiting with failure
71 * in the event no currdev is found. -2 means always break, -1 means
72 * never break, 0 means poll once and then reboot, > 0 means wait for
73 * that many seconds. "fail_timeout" can be set in the environment as
76 static int fail_timeout
= 5;
79 efi_zfs_is_preferred(EFI_HANDLE
*h
)
81 EFI_DEVICE_PATH
*devpath
, *dp
, *node
;
82 HARDDRIVE_DEVICE_PATH
*hd
;
84 extern UINT64 start_sector
; /* from multiboot.S */
86 /* This check is true for chainloader case. */
87 if (h
== img
->DeviceHandle
)
91 * Make sure the image was loaded from the hard disk.
93 devpath
= efi_lookup_devpath(img
->DeviceHandle
);
96 node
= efi_devpath_last_node(devpath
);
99 if (DevicePathType(node
) != MEDIA_DEVICE_PATH
&&
100 (DevicePathSubType(node
) != MEDIA_FILEPATH_DP
||
101 DevicePathSubType(node
) != MEDIA_HARDDRIVE_DP
)) {
106 * XXX We ignore the MEDIA_FILEPATH_DP here for now as it is
107 * used on arm and we do not support arm.
110 dp
= efi_devpath_trim(devpath
);
115 devpath
= efi_lookup_devpath(h
);
118 hd
= (HARDDRIVE_DEVICE_PATH
*)efi_devpath_last_node(devpath
);
123 devpath
= efi_devpath_trim(devpath
);
127 if (!efi_devpath_match(dp
, devpath
))
130 /* It is the same disk, do we have partition start? */
131 if (start_sector
== 0)
133 else if (start_sector
== hd
->PartitionStart
)
146 EFI_DEVICE_PATH
*path
;
147 EFI_HANDLE
*hin
, *hin_end
, *walker
;
152 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
153 * do the typical dance to get the right sized buffer.
157 status
= BS
->LocateHandle(ByProtocol
, &inputid
, 0, &sz
, 0);
158 if (status
== EFI_BUFFER_TOO_SMALL
) {
159 hin
= (EFI_HANDLE
*)malloc(sz
);
160 status
= BS
->LocateHandle(ByProtocol
, &inputid
, 0, &sz
,
162 if (EFI_ERROR(status
))
165 if (EFI_ERROR(status
))
169 * Look at each of the handles. If it supports the device path protocol,
170 * use it to get the device path for this handle. Then see if that
171 * device path matches either the USB device path for keyboards or the
172 * legacy device path for keyboards.
174 hin_end
= &hin
[sz
/ sizeof(*hin
)];
175 for (walker
= hin
; walker
< hin_end
; walker
++) {
176 status
= BS
->HandleProtocol(*walker
, &devid
, (VOID
**)&path
);
177 if (EFI_ERROR(status
))
180 while (!IsDevicePathEnd(path
)) {
182 * Check for the ACPI keyboard node. All PNP3xx nodes
183 * are keyboards of different flavors. Note: It is
184 * unclear of there's always a keyboard node when
185 * there's a keyboard controller, or if there's only one
186 * when a keyboard is detected at boot.
188 if (DevicePathType(path
) == ACPI_DEVICE_PATH
&&
189 (DevicePathSubType(path
) == ACPI_DP
||
190 DevicePathSubType(path
) == ACPI_EXTENDED_DP
)) {
191 ACPI_HID_DEVICE_PATH
*acpi
;
193 acpi
= (ACPI_HID_DEVICE_PATH
*)(void *)path
;
194 if ((EISA_ID_TO_NUM(acpi
->HID
) & 0xff00) == 0x300 &&
195 (acpi
->HID
& 0xffff) == PNP_EISA_ID_CONST
) {
200 * Check for USB keyboard node, if present. Unlike a
201 * PS/2 keyboard, these definitely only appear when
202 * connected to the system.
204 } else if (DevicePathType(path
) == MESSAGING_DEVICE_PATH
&&
205 DevicePathSubType(path
) == MSG_USB_CLASS_DP
) {
206 USB_CLASS_DEVICE_PATH
*usb
;
208 usb
= (USB_CLASS_DEVICE_PATH
*)(void *)path
;
209 if (usb
->DeviceClass
== 3 && /* HID */
210 usb
->DeviceSubClass
== 1 && /* Boot devices */
211 usb
->DeviceProtocol
== 1) { /* Boot keyboards */
216 path
= NextDevicePathNode(path
);
225 set_currdev_devdesc(struct devdesc
*currdev
)
229 devname
= efi_fmtdev(currdev
);
231 printf("Setting currdev to %s\n", devname
);
233 env_setenv("currdev", EV_VOLATILE
, devname
, efi_setcurrdev
,
235 env_setenv("loaddev", EV_VOLATILE
, devname
, env_noset
, env_nounset
);
239 set_currdev_devsw(struct devsw
*dev
, int unit
)
241 struct devdesc currdev
;
244 currdev
.d_unit
= unit
;
246 set_currdev_devdesc(&currdev
);
250 set_currdev_pdinfo(pdinfo_t
*dp
)
254 * Disks are special: they have partitions. if the parent
255 * pointer is non-null, we're a partition not a full disk
256 * and we need to adjust currdev appropriately.
258 if (dp
->pd_devsw
->dv_type
== DEVT_DISK
) {
259 struct disk_devdesc currdev
;
261 currdev
.dd
.d_dev
= dp
->pd_devsw
;
262 if (dp
->pd_parent
== NULL
) {
263 currdev
.dd
.d_unit
= dp
->pd_unit
;
264 currdev
.d_slice
= -1;
265 currdev
.d_partition
= -1;
267 currdev
.dd
.d_unit
= dp
->pd_parent
->pd_unit
;
268 currdev
.d_slice
= dp
->pd_unit
;
269 currdev
.d_partition
= 255; /* Assumes GPT */
271 set_currdev_devdesc((struct devdesc
*)&currdev
);
273 set_currdev_devsw(dp
->pd_devsw
, dp
->pd_unit
);
278 sanity_check_currdev(void)
282 return (stat("/boot/defaults/loader.conf", &st
) == 0);
286 probe_zfs_currdev(uint64_t guid
)
288 struct zfs_devdesc currdev
;
290 currdev
.dd
.d_dev
= &zfs_dev
;
291 currdev
.dd
.d_unit
= 0;
292 currdev
.pool_guid
= guid
;
293 currdev
.root_guid
= 0;
294 set_currdev_devdesc((struct devdesc
*)&currdev
);
296 return (sanity_check_currdev());
300 try_as_currdev(pdinfo_t
*pp
)
305 * If there's a zpool on this device, try it as a ZFS
306 * filesystem, which has somewhat different setup than all
307 * other types of fs due to imperfect loader integration.
308 * This all stems from ZFS being both a device (zpool) and
309 * a filesystem, plus the boot env feature.
311 if (efizfs_get_guid_by_handle(pp
->pd_handle
, &guid
))
312 return (probe_zfs_currdev(guid
));
315 * All other filesystems just need the pdinfo
316 * initialized in the standard way.
318 set_currdev_pdinfo(pp
);
319 return (sanity_check_currdev());
323 find_currdev(EFI_LOADED_IMAGE
*img
)
326 EFI_DEVICE_PATH
*devpath
, *copy
;
334 * Did efi_zfs_probe() detect the boot pool? If so, use the zpool
335 * it found, if it's sane. ZFS is the only thing that looks for
336 * disks and pools to boot.
338 if (pool_guid
!= 0) {
339 printf("Trying ZFS pool\n");
340 if (probe_zfs_currdev(pool_guid
))
345 * Try to find the block device by its handle based on the
346 * image we're booting. If we can't find a sane partition,
347 * search all the other partitions of the disk. We do not
348 * search other disks because it's a violation of the UEFI
349 * boot protocol to do so. We fail and let UEFI go on to
350 * the next candidate.
352 dp
= efiblk_get_pdinfo_by_handle(img
->DeviceHandle
);
354 text
= efi_devpath_name(dp
->pd_devpath
);
356 printf("Trying ESP: %S\n", text
);
357 efi_free_devpath_name(text
);
359 set_currdev_pdinfo(dp
);
360 if (sanity_check_currdev())
362 if (dp
->pd_parent
!= NULL
) {
364 STAILQ_FOREACH(pp
, &dp
->pd_part
, pd_link
) {
365 text
= efi_devpath_name(pp
->pd_devpath
);
367 printf("And now the part: %S\n", text
);
368 efi_free_devpath_name(text
);
371 * Roll up the ZFS special case
372 * for those partitions that have
375 if (try_as_currdev(pp
))
380 printf("Can't find device by handle\n");
384 * Try the device handle from our loaded image first. If that
385 * fails, use the device path from the loaded image and see if
386 * any of the nodes in that path match one of the enumerated
387 * handles. Currently, this handle list is only for netboot.
389 if (efi_handle_lookup(img
->DeviceHandle
, &dev
, &unit
, &extra
) == 0) {
390 set_currdev_devsw(dev
, unit
);
391 if (sanity_check_currdev())
396 devpath
= efi_lookup_image_devpath(IH
);
397 while (devpath
!= NULL
) {
398 h
= efi_devpath_handle(devpath
);
405 if (efi_handle_lookup(h
, &dev
, &unit
, &extra
) == 0) {
406 set_currdev_devsw(dev
, unit
);
407 if (sanity_check_currdev())
411 devpath
= efi_lookup_devpath(h
);
412 if (devpath
!= NULL
) {
413 copy
= efi_devpath_trim(devpath
);
423 interactive_interrupt(const char *msg
)
425 time_t now
, then
, last
;
428 now
= then
= getsecs();
430 if (fail_timeout
== -2) /* Always break to OK */
432 if (fail_timeout
== -1) /* Never break to OK */
436 printf("press any key to interrupt reboot in %d seconds\r",
437 fail_timeout
- (int)(now
- then
));
441 /* XXX no pause or timeout wait for char */
445 } while (now
- then
< fail_timeout
);
450 main(int argc
, CHAR16
*argv
[])
458 EFI_DEVICE_PATH
*imgpath
;
463 UINT16 boot_order
[100];
465 archsw
.arch_autoload
= efi_autoload
;
466 archsw
.arch_getdev
= efi_getdev
;
467 archsw
.arch_copyin
= efi_copyin
;
468 archsw
.arch_copyout
= efi_copyout
;
469 archsw
.arch_readin
= efi_readin
;
470 archsw
.arch_loadaddr
= efi_loadaddr
;
471 archsw
.arch_free_loadaddr
= efi_free_loadaddr
;
472 /* Note this needs to be set before ZFS init. */
473 archsw
.arch_zfs_probe
= efi_zfs_probe
;
475 /* Get our loaded image protocol interface structure. */
476 BS
->HandleProtocol(IH
, &imgid
, (VOID
**)&img
);
478 /* Init the time source */
481 has_kbd
= has_keyboard();
484 * XXX Chicken-and-egg problem; we want to have console output
485 * early, but some console attributes may depend on reading from
486 * eg. the boot device, which we can't do yet. We can use
487 * printf() etc. once this is done.
493 * Initialise the block cache. Set the upper limit.
495 bcache_init(32768, 512);
498 * Parse the args to set the console settings, etc
499 * boot1.efi passes these in, if it can read /boot.config or /boot/config
500 * or iPXE may be setup to pass these in. Or the optional argument in the
501 * boot environment was used to pass these arguments in (in which case
502 * neither /boot.config nor /boot/config are consulted).
504 * Loop through the args, and for each one that contains an '=' that is
505 * not the first character, add it to the environment. This allows
506 * loader and kernel env vars to be passed on the command line. Convert
507 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though this
508 * method is flawed for non-ASCII characters).
511 for (i
= 1; i
< argc
; i
++) {
512 if (argv
[i
][0] == '-') {
513 for (j
= 1; argv
[i
][j
] != 0; j
++) {
525 howto
|= RB_MULTIPLE
;
538 howto
|= RB_SERIAL
| RB_MULTIPLE
;
541 howto
|= RB_DFLTROOT
;
547 if (argv
[i
][j
+ 1] == 0) {
549 strncpy(var
, "115200",
553 ptr
= &argv
[i
+ 1][0];
559 cpy16to8(&argv
[i
][j
+ 1], var
,
562 strncat(var
, ",8,n,1,-", sizeof(var
));
563 setenv("ttya-mode", var
, 1);
572 for (j
= 0; argv
[i
][j
] != 0; j
++) {
573 if (j
== sizeof(var
)) {
577 if (j
> 0 && argv
[i
][j
] == '=')
579 var
[j
] = (char)argv
[i
][j
];
587 for (i
= 0; howto_names
[i
].ev
!= NULL
; i
++)
588 if (howto
& howto_names
[i
].mask
)
589 setenv(howto_names
[i
].ev
, "YES", 1);
592 * XXX we need fallback to this stuff after looking at the ConIn,
593 * ConOut and ConErr variables.
595 if (howto
& RB_MULTIPLE
) {
596 if (howto
& RB_SERIAL
)
597 setenv("console", "ttya text" , 1);
599 setenv("console", "text ttya" , 1);
600 } else if (howto
& RB_SERIAL
) {
601 setenv("console", "ttya" , 1);
603 setenv("console", "text" , 1);
605 if ((s
= getenv("fail_timeout")) != NULL
)
606 fail_timeout
= strtol(s
, NULL
, 10);
609 * Scan the BLOCK IO MEDIA handles then
610 * march through the device switch probing for things.
612 if ((i
= efipart_inithandles()) == 0) {
613 for (i
= 0; devsw
[i
] != NULL
; i
++)
614 if (devsw
[i
]->dv_init
!= NULL
)
615 (devsw
[i
]->dv_init
)();
617 printf("efipart_inithandles failed %d, expect failures", i
);
619 printf("Command line arguments:");
620 for (i
= 0; i
< argc
; i
++) {
621 printf(" %S", argv
[i
]);
625 printf("Image base: 0x%lx\n", (u_long
)img
->ImageBase
);
626 printf("EFI version: %d.%02d\n", ST
->Hdr
.Revision
>> 16,
627 ST
->Hdr
.Revision
& 0xffff);
628 printf("EFI Firmware: %S (rev %d.%02d)\n", ST
->FirmwareVendor
,
629 ST
->FirmwareRevision
>> 16, ST
->FirmwareRevision
& 0xffff);
631 printf("\n%s", bootprog_info
);
633 /* Determine the devpath of our image so we can prefer it. */
634 text
= efi_devpath_name(img
->FilePath
);
636 printf(" Load Path: %S\n", text
);
637 efi_setenv_illumos_wcs("LoaderPath", text
);
638 efi_free_devpath_name(text
);
641 status
= BS
->HandleProtocol(img
->DeviceHandle
, &devid
,
643 if (status
== EFI_SUCCESS
) {
644 text
= efi_devpath_name(imgpath
);
646 printf(" Load Device: %S\n", text
);
647 efi_setenv_illumos_wcs("LoaderDev", text
);
648 efi_free_devpath_name(text
);
653 sz
= sizeof(boot_current
);
654 efi_global_getenv("BootCurrent", &boot_current
, &sz
);
655 printf(" BootCurrent: %04x\n", boot_current
);
657 sz
= sizeof(boot_order
);
658 efi_global_getenv("BootOrder", &boot_order
, &sz
);
659 printf(" BootOrder:");
660 for (i
= 0; i
< sz
/ sizeof(boot_order
[0]); i
++)
661 printf(" %04x%s", boot_order
[i
],
662 boot_order
[i
] == boot_current
? "[*]" : "");
666 * Disable the watchdog timer. By default the boot manager sets
667 * the timer to 5 minutes before invoking a boot option. If we
668 * want to return to the boot manager, we have to disable the
669 * watchdog timer and since we're an interactive program, we don't
670 * want to wait until the user types "quit". The timer may have
671 * fired by then. We don't care if this fails. It does not prevent
672 * normal functioning in any way...
674 BS
->SetWatchdogTimer(0, 0, 0, NULL
);
677 * Try and find a good currdev based on the image that was booted.
678 * It might be desirable here to have a short pause to allow falling
679 * through to the boot loader instead of returning instantly to follow
680 * the boot protocol and also allow an escape hatch for users wishing
681 * to try something different.
683 if (!find_currdev(img
))
684 if (!interactive_interrupt("Failed to find bootable partition"))
685 return (EFI_NOT_FOUND
);
687 autoload_font(); /* Set up the font list for console. */
688 efi_init_environment();
689 setenv("ISADIR", "amd64", 1); /* we only build 64bit */
690 bi_isadir(); /* set ISADIR */
693 if ((ptr
= efi_get_table(&smbios3
)) == NULL
)
694 ptr
= efi_get_table(&smbios
);
697 interact(NULL
); /* doesn't return */
699 return (EFI_SUCCESS
); /* keep compiler happy */
702 COMMAND_SET(reboot
, "reboot", "reboot the system", command_reboot
);
705 command_reboot(int argc __unused
, char *argv
[] __unused
)
709 for (i
= 0; devsw
[i
] != NULL
; ++i
)
710 if (devsw
[i
]->dv_cleanup
!= NULL
)
711 (devsw
[i
]->dv_cleanup
)();
713 RS
->ResetSystem(EfiResetCold
, EFI_SUCCESS
, 0, NULL
);
719 COMMAND_SET(poweroff
, "poweroff", "power off the system", command_poweroff
);
722 command_poweroff(int argc __unused
, char *argv
[] __unused
)
726 for (i
= 0; devsw
[i
] != NULL
; ++i
)
727 if (devsw
[i
]->dv_cleanup
!= NULL
)
728 (devsw
[i
]->dv_cleanup
)();
730 RS
->ResetSystem(EfiResetShutdown
, EFI_SUCCESS
, 0, NULL
);
736 COMMAND_SET(memmap
, "memmap", "print memory map", command_memmap
);
739 command_memmap(int argc __unused
, char *argv
[] __unused
)
742 EFI_MEMORY_DESCRIPTOR
*map
, *p
;
751 status
= BS
->GetMemoryMap(&sz
, 0, &key
, &dsz
, &dver
);
752 if (status
!= EFI_BUFFER_TOO_SMALL
) {
753 printf("Can't determine memory map size\n");
757 status
= BS
->GetMemoryMap(&sz
, map
, &key
, &dsz
, &dver
);
758 if (EFI_ERROR(status
)) {
759 printf("Can't read memory map\n");
764 snprintf(line
, 80, "%23s %12s %12s %8s %4s\n",
765 "Type", "Physical", "Virtual", "#Pages", "Attr");
767 rv
= pager_output(line
);
773 for (i
= 0, p
= map
; i
< ndesc
;
774 i
++, p
= NextMemoryDescriptor(p
, dsz
)) {
775 snprintf(line
, 80, "%23s %012jx %012jx %08jx ",
776 efi_memory_type(p
->Type
), p
->PhysicalStart
,
777 p
->VirtualStart
, p
->NumberOfPages
);
778 rv
= pager_output(line
);
782 if (p
->Attribute
& EFI_MEMORY_UC
)
784 if (p
->Attribute
& EFI_MEMORY_WC
)
786 if (p
->Attribute
& EFI_MEMORY_WT
)
788 if (p
->Attribute
& EFI_MEMORY_WB
)
790 if (p
->Attribute
& EFI_MEMORY_UCE
)
792 if (p
->Attribute
& EFI_MEMORY_WP
)
794 if (p
->Attribute
& EFI_MEMORY_RP
)
796 if (p
->Attribute
& EFI_MEMORY_XP
)
798 if (p
->Attribute
& EFI_MEMORY_NV
)
800 if (p
->Attribute
& EFI_MEMORY_MORE_RELIABLE
)
802 if (p
->Attribute
& EFI_MEMORY_RO
)
804 rv
= pager_output("\n");
813 COMMAND_SET(configuration
, "configuration", "print configuration tables",
814 command_configuration
);
817 command_configuration(int argc __unused
, char *argv
[] __unused
)
822 printf("NumberOfTableEntries=%lu\n",
823 (unsigned long)ST
->NumberOfTableEntries
);
824 for (i
= 0; i
< ST
->NumberOfTableEntries
; i
++) {
828 guid
= &ST
->ConfigurationTable
[i
].VendorGuid
;
830 if (efi_guid_to_name(guid
, &name
) == true) {
834 printf("Error while translating UUID to name");
836 printf(" at %p\n", ST
->ConfigurationTable
[i
].VendorTable
);
843 COMMAND_SET(mode
, "mode", "change or display EFI text modes", command_mode
);
846 command_mode(int argc
, char *argv
[])
853 SIMPLE_TEXT_OUTPUT_INTERFACE
*conout
;
854 EFI_CONSOLE_CONTROL_SCREEN_MODE sm
;
856 if (plat_stdout_is_framebuffer())
857 sm
= EfiConsoleControlScreenGraphics
;
859 sm
= EfiConsoleControlScreenText
;
864 mode
= strtol(argv
[1], &cp
, 0);
866 printf("Invalid mode\n");
869 status
= conout
->QueryMode(conout
, mode
, &cols
, &rows
);
870 if (EFI_ERROR(status
)) {
871 printf("invalid mode %d\n", mode
);
874 status
= conout
->SetMode(conout
, mode
);
875 if (EFI_ERROR(status
)) {
876 printf("couldn't set mode %d\n", mode
);
879 plat_cons_update_mode(sm
);
883 printf("Current mode: %d\n", conout
->Mode
->Mode
);
884 for (i
= 0; i
<= conout
->Mode
->MaxMode
; i
++) {
885 status
= conout
->QueryMode(conout
, i
, &cols
, &rows
);
886 if (EFI_ERROR(status
))
888 printf("Mode %d: %u columns, %u rows\n", i
, (unsigned)cols
,
893 printf("Select a mode with the command \"mode <number>\"\n");
898 COMMAND_SET(lsefi
, "lsefi", "list EFI handles", command_lsefi
);
901 command_lsefi(int argc __unused
, char *argv
[] __unused
)
904 EFI_HANDLE
*buffer
= NULL
;
906 UINTN bufsz
= 0, i
, j
;
910 status
= BS
->LocateHandle(AllHandles
, NULL
, NULL
, &bufsz
, buffer
);
911 if (status
!= EFI_BUFFER_TOO_SMALL
) {
912 snprintf(command_errbuf
, sizeof (command_errbuf
),
913 "unexpected error: %lld", (long long)status
);
916 if ((buffer
= malloc(bufsz
)) == NULL
) {
917 sprintf(command_errbuf
, "out of memory");
921 status
= BS
->LocateHandle(AllHandles
, NULL
, NULL
, &bufsz
, buffer
);
922 if (EFI_ERROR(status
)) {
924 snprintf(command_errbuf
, sizeof (command_errbuf
),
925 "LocateHandle() error: %lld", (long long)status
);
930 for (i
= 0; i
< (bufsz
/ sizeof (EFI_HANDLE
)); i
++) {
932 EFI_GUID
**protocols
= NULL
;
935 printf("Handle %p", handle
);
936 if (pager_output("\n"))
940 status
= BS
->ProtocolsPerHandle(handle
, &protocols
, &nproto
);
941 if (EFI_ERROR(status
)) {
942 snprintf(command_errbuf
, sizeof (command_errbuf
),
943 "ProtocolsPerHandle() error: %lld",
948 for (j
= 0; j
< nproto
; j
++) {
949 if (efi_guid_to_name(protocols
[j
], &name
) == true) {
953 printf("Error while translating UUID to name");
955 if ((ret
= pager_output("\n")) != 0)
958 BS
->FreePool(protocols
);
967 COMMAND_SET(lszfs
, "lszfs", "list child datasets of a zfs dataset",
971 command_lszfs(int argc
, char *argv
[])
976 command_errmsg
= "wrong number of arguments";
980 err
= zfs_list(argv
[1]);
982 command_errmsg
= strerror(err
);
989 COMMAND_SET(reloadbe
, "reloadbe", "refresh the list of ZFS Boot Environments",
993 command_reloadbe(int argc
, char *argv
[])
999 command_errmsg
= "wrong number of arguments";
1004 err
= zfs_bootenv(argv
[1]);
1006 root
= getenv("zfs_be_root");
1010 err
= zfs_bootenv(root
);
1014 command_errmsg
= strerror(err
);
1020 #endif /* __FreeBSD__ */
1022 #ifdef LOADER_FDT_SUPPORT
1023 extern int command_fdt_internal(int argc
, char *argv
[]);
1026 * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
1027 * and declaring it as extern is in contradiction with COMMAND_SET() macro
1028 * (which uses static pointer), we're defining wrapper function, which
1029 * calls the proper fdt handling routine.
1032 command_fdt(int argc
, char *argv
[])
1034 return (command_fdt_internal(argc
, argv
));
1037 COMMAND_SET(fdt
, "fdt", "flattened device tree handling", command_fdt
);
1041 * Chain load another efi loader.
1044 command_chain(int argc
, char *argv
[])
1046 EFI_GUID LoadedImageGUID
= LOADED_IMAGE_PROTOCOL
;
1047 EFI_HANDLE loaderhandle
;
1048 EFI_LOADED_IMAGE
*loaded_image
;
1051 struct devdesc
*dev
;
1057 command_errmsg
= "wrong number of arguments";
1063 if ((fd
= open(name
, O_RDONLY
)) < 0) {
1064 command_errmsg
= "no such file";
1068 if (fstat(fd
, &st
) < -1) {
1069 command_errmsg
= "stat failed";
1074 status
= BS
->AllocatePool(EfiLoaderCode
, (UINTN
)st
.st_size
, &buf
);
1075 if (status
!= EFI_SUCCESS
) {
1076 command_errmsg
= "failed to allocate buffer";
1080 if (read(fd
, buf
, st
.st_size
) != st
.st_size
) {
1081 command_errmsg
= "error while reading the file";
1082 (void)BS
->FreePool(buf
);
1087 status
= BS
->LoadImage(FALSE
, IH
, NULL
, buf
, st
.st_size
, &loaderhandle
);
1088 (void)BS
->FreePool(buf
);
1089 if (status
!= EFI_SUCCESS
) {
1090 command_errmsg
= "LoadImage failed";
1093 status
= BS
->HandleProtocol(loaderhandle
, &LoadedImageGUID
,
1094 (void **)&loaded_image
);
1100 for (i
= 2; i
< argc
; i
++)
1101 len
+= strlen(argv
[i
]) + 1;
1103 len
*= sizeof (*argp
);
1104 loaded_image
->LoadOptions
= argp
= malloc (len
);
1105 if (loaded_image
->LoadOptions
== NULL
) {
1106 (void) BS
->UnloadImage(loaded_image
);
1109 loaded_image
->LoadOptionsSize
= len
;
1110 for (i
= 2; i
< argc
; i
++) {
1111 char *ptr
= argv
[i
];
1113 *(argp
++) = *(ptr
++);
1119 if (efi_getdev((void **)&dev
, name
, (const char **)&path
) == 0) {
1120 struct zfs_devdesc
*z_dev
;
1121 struct disk_devdesc
*d_dev
;
1124 switch (dev
->d_dev
->dv_type
) {
1126 z_dev
= (struct zfs_devdesc
*)dev
;
1127 loaded_image
->DeviceHandle
=
1128 efizfs_get_handle_by_guid(z_dev
->pool_guid
);
1131 loaded_image
->DeviceHandle
=
1132 efi_find_handle(dev
->d_dev
, dev
->d_unit
);
1135 hd
= efiblk_get_pdinfo(dev
);
1136 if (STAILQ_EMPTY(&hd
->pd_part
)) {
1137 loaded_image
->DeviceHandle
= hd
->pd_handle
;
1140 d_dev
= (struct disk_devdesc
*)dev
;
1141 STAILQ_FOREACH(pd
, &hd
->pd_part
, pd_link
) {
1143 * d_partition should be 255
1145 if (pd
->pd_unit
== d_dev
->d_slice
) {
1146 loaded_image
->DeviceHandle
=
1156 status
= BS
->StartImage(loaderhandle
, NULL
, NULL
);
1157 if (status
!= EFI_SUCCESS
) {
1158 command_errmsg
= "StartImage failed";
1159 free(loaded_image
->LoadOptions
);
1160 loaded_image
->LoadOptions
= NULL
;
1161 status
= BS
->UnloadImage(loaded_image
);
1165 return (CMD_ERROR
); /* not reached */
1168 COMMAND_SET(chain
, "chain", "chain load file", command_chain
);