Merge commit '37e84ab74e939caf52150fc3352081786ecc0c29' into merges
[unleashed.git] / usr / src / boot / sys / boot / efi / loader / main.c
blob472ce865094c10843a7405cc6720f9d6152a9cea
1 /*-
2 * Copyright (c) 2008-2010 Rui Paulo
3 * Copyright (c) 2006 Marcel Moolenaar
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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>
30 #include <sys/disk.h>
31 #include <sys/param.h>
32 #include <sys/reboot.h>
33 #include <sys/boot.h>
34 #include <stand.h>
35 #include <inttypes.h>
36 #include <string.h>
37 #include <setjmp.h>
39 #include <efi.h>
40 #include <efilib.h>
41 #include <efigpt.h>
43 #include <uuid.h>
44 #include <stdbool.h>
46 #include <bootstrap.h>
47 #include <smbios.h>
49 #ifdef EFI_ZFS_BOOT
50 #include <libzfs.h>
51 #endif
53 #include "loader_efi.h"
55 extern char bootprog_info[];
57 struct arch_switch archsw; /* MI/MD interface boundary */
59 EFI_GUID devid = DEVICE_PATH_PROTOCOL;
60 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
61 EFI_GUID smbios = SMBIOS_TABLE_GUID;
62 EFI_GUID smbios3 = SMBIOS3_TABLE_GUID;
63 EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL;
64 EFI_GUID serial_io = SERIAL_IO_PROTOCOL;
66 extern void acpi_detect(void);
67 void efi_serial_init(void);
68 extern void efi_getsmap(void);
69 #ifdef EFI_ZFS_BOOT
70 static void efi_zfs_probe(void);
71 #endif
73 static int
74 has_keyboard(void)
76 EFI_STATUS status;
77 EFI_DEVICE_PATH *path;
78 EFI_HANDLE *hin, *hin_end, *walker;
79 UINTN sz;
80 int retval = 0;
83 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
84 * do the typical dance to get the right sized buffer.
86 sz = 0;
87 hin = NULL;
88 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0);
89 if (status == EFI_BUFFER_TOO_SMALL) {
90 hin = (EFI_HANDLE *)malloc(sz);
91 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz,
92 hin);
93 if (EFI_ERROR(status))
94 free(hin);
96 if (EFI_ERROR(status))
97 return retval;
100 * Look at each of the handles. If it supports the device path protocol,
101 * use it to get the device path for this handle. Then see if that
102 * device path matches either the USB device path for keyboards or the
103 * legacy device path for keyboards.
105 hin_end = &hin[sz / sizeof(*hin)];
106 for (walker = hin; walker < hin_end; walker++) {
107 status = BS->HandleProtocol(*walker, &devid, (VOID **)&path);
108 if (EFI_ERROR(status))
109 continue;
111 while (!IsDevicePathEnd(path)) {
113 * Check for the ACPI keyboard node. All PNP3xx nodes
114 * are keyboards of different flavors. Note: It is
115 * unclear of there's always a keyboard node when
116 * there's a keyboard controller, or if there's only one
117 * when a keyboard is detected at boot.
119 if (DevicePathType(path) == ACPI_DEVICE_PATH &&
120 (DevicePathSubType(path) == ACPI_DP ||
121 DevicePathSubType(path) == ACPI_EXTENDED_DP)) {
122 ACPI_HID_DEVICE_PATH *acpi;
124 acpi = (ACPI_HID_DEVICE_PATH *)(void *)path;
125 if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 &&
126 (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) {
127 retval = 1;
128 goto out;
131 * Check for USB keyboard node, if present. Unlike a
132 * PS/2 keyboard, these definitely only appear when
133 * connected to the system.
135 } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH &&
136 DevicePathSubType(path) == MSG_USB_CLASS_DP) {
137 USB_CLASS_DEVICE_PATH *usb;
139 usb = (USB_CLASS_DEVICE_PATH *)(void *)path;
140 if (usb->DeviceClass == 3 && /* HID */
141 usb->DeviceSubClass == 1 && /* Boot devices */
142 usb->DeviceProtocol == 1) { /* Boot keyboards */
143 retval = 1;
144 goto out;
147 path = NextDevicePathNode(path);
150 out:
151 free(hin);
152 return retval;
155 static int
156 find_currdev(EFI_LOADED_IMAGE *img, struct devsw **dev, int *unit,
157 uint64_t *extra)
159 EFI_DEVICE_PATH *devpath, *copy;
160 EFI_HANDLE h;
163 * Try the device handle from our loaded image first. If that
164 * fails, use the device path from the loaded image and see if
165 * any of the nodes in that path match one of the enumerated
166 * handles.
168 if (efi_handle_lookup(img->DeviceHandle, dev, unit, extra) == 0)
169 return (0);
171 copy = NULL;
172 devpath = efi_lookup_image_devpath(IH);
173 while (devpath != NULL) {
174 h = efi_devpath_handle(devpath);
175 if (h == NULL)
176 break;
178 free(copy);
179 copy = NULL;
181 if (efi_handle_lookup(h, dev, unit, extra) == 0)
182 return (0);
184 devpath = efi_lookup_devpath(h);
185 if (devpath != NULL) {
186 copy = efi_devpath_trim(devpath);
187 devpath = copy;
190 free(copy);
192 return (ENOENT);
195 EFI_STATUS
196 main(int argc, CHAR16 *argv[])
198 char var[128];
199 EFI_LOADED_IMAGE *img;
200 EFI_GUID *guid;
201 int i, j, vargood, unit, howto;
202 struct devsw *dev;
203 uint64_t pool_guid;
204 void *ptr;
205 UINTN k;
206 int has_kbd;
208 archsw.arch_autoload = efi_autoload;
209 archsw.arch_getdev = efi_getdev;
210 archsw.arch_copyin = efi_copyin;
211 archsw.arch_copyout = efi_copyout;
212 archsw.arch_readin = efi_readin;
213 archsw.arch_loadaddr = efi_loadaddr;
214 archsw.arch_free_loadaddr = efi_free_loadaddr;
215 #ifdef EFI_ZFS_BOOT
216 /* Note this needs to be set before ZFS init. */
217 archsw.arch_zfs_probe = efi_zfs_probe;
218 #endif
220 /* Init the time source */
221 efi_time_init();
223 has_kbd = has_keyboard();
226 * XXX Chicken-and-egg problem; we want to have console output
227 * early, but some console attributes may depend on reading from
228 * eg. the boot device, which we can't do yet. We can use
229 * printf() etc. once this is done.
231 cons_probe();
232 efi_getsmap();
235 * Initialise the block cache. Set the upper limit.
237 bcache_init(32768, 512);
240 * Parse the args to set the console settings, etc
241 * boot1.efi passes these in, if it can read /boot.config or /boot/config
242 * or iPXE may be setup to pass these in.
244 * Loop through the args, and for each one that contains an '=' that is
245 * not the first character, add it to the environment. This allows
246 * loader and kernel env vars to be passed on the command line. Convert
247 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied.
249 howto = 0;
250 for (i = 1; i < argc; i++) {
251 if (argv[i][0] == '-') {
252 for (j = 1; argv[i][j] != 0; j++) {
253 int ch;
255 ch = argv[i][j];
256 switch (ch) {
257 case 'a':
258 howto |= RB_ASKNAME;
259 break;
260 case 'd':
261 howto |= RB_KDB;
262 break;
263 case 'D':
264 howto |= RB_MULTIPLE;
265 break;
266 case 'h':
267 howto |= RB_SERIAL;
268 break;
269 case 'm':
270 howto |= RB_MUTE;
271 break;
272 case 'p':
273 howto |= RB_PAUSE;
274 break;
275 case 'P':
276 if (!has_kbd)
277 howto |= RB_SERIAL | RB_MULTIPLE;
278 break;
279 case 'r':
280 howto |= RB_DFLTROOT;
281 break;
282 case 's':
283 howto |= RB_SINGLE;
284 break;
285 case 'S':
286 if (argv[i][j + 1] == 0) {
287 if (i + 1 == argc) {
288 setenv("comconsole_speed", "115200", 1);
289 } else {
290 cpy16to8(&argv[i + 1][0], var,
291 sizeof(var));
292 setenv("comconsole_speedspeed", var, 1);
294 i++;
295 break;
296 } else {
297 cpy16to8(&argv[i][j + 1], var,
298 sizeof(var));
299 setenv("comconsole_speed", var, 1);
300 break;
302 case 'v':
303 howto |= RB_VERBOSE;
304 break;
307 } else {
308 vargood = 0;
309 for (j = 0; argv[i][j] != 0; j++) {
310 if (j == sizeof(var)) {
311 vargood = 0;
312 break;
314 if (j > 0 && argv[i][j] == '=')
315 vargood = 1;
316 var[j] = (char)argv[i][j];
318 if (vargood) {
319 var[j] = 0;
320 putenv(var);
324 for (i = 0; howto_names[i].ev != NULL; i++)
325 if (howto & howto_names[i].mask)
326 setenv(howto_names[i].ev, "YES", 1);
327 if (howto & RB_MULTIPLE) {
328 if (howto & RB_SERIAL)
329 setenv("console", "ttya text" , 1);
330 else
331 setenv("console", "text ttya" , 1);
332 } else if (howto & RB_SERIAL) {
333 setenv("console", "ttya" , 1);
337 * March through the device switch probing for things.
339 for (i = 0; devsw[i] != NULL; i++)
340 if (devsw[i]->dv_init != NULL)
341 (devsw[i]->dv_init)();
343 /* Get our loaded image protocol interface structure. */
344 BS->HandleProtocol(IH, &imgid, (VOID**)&img);
346 printf("Command line arguments:");
347 for (i = 0; i < argc; i++) {
348 printf(" %S", argv[i]);
350 printf("\n");
352 printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
353 printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
354 ST->Hdr.Revision & 0xffff);
355 printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor,
356 ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
358 printf("\n%s", bootprog_info);
361 * Disable the watchdog timer. By default the boot manager sets
362 * the timer to 5 minutes before invoking a boot option. If we
363 * want to return to the boot manager, we have to disable the
364 * watchdog timer and since we're an interactive program, we don't
365 * want to wait until the user types "quit". The timer may have
366 * fired by then. We don't care if this fails. It does not prevent
367 * normal functioning in any way...
369 BS->SetWatchdogTimer(0, 0, 0, NULL);
371 if (find_currdev(img, &dev, &unit, &pool_guid) != 0)
372 return (EFI_NOT_FOUND);
374 switch (dev->dv_type) {
375 #ifdef EFI_ZFS_BOOT
376 case DEVT_ZFS: {
377 struct zfs_devdesc currdev;
379 currdev.d_dev = dev;
380 currdev.d_unit = unit;
381 currdev.d_type = currdev.d_dev->dv_type;
382 currdev.d_opendata = NULL;
383 currdev.pool_guid = pool_guid;
384 currdev.root_guid = 0;
385 env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
386 efi_setcurrdev, env_nounset);
387 env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
388 env_nounset);
389 #ifdef __FreeBSD__
390 init_zfs_bootenv(zfs_fmtdev(&currdev));
391 #endif
392 break;
394 #endif
395 default: {
396 struct devdesc currdev;
398 currdev.d_dev = dev;
399 currdev.d_unit = unit;
400 currdev.d_opendata = NULL;
401 currdev.d_type = currdev.d_dev->dv_type;
402 env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
403 efi_setcurrdev, env_nounset);
404 env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
405 env_nounset);
406 break;
410 efi_init_environment();
411 setenv("ISADIR", "amd64", 1); /* we only build 64bit */
412 acpi_detect();
414 if ((ptr = efi_get_table(&smbios3)) == NULL)
415 ptr = efi_get_table(&smbios);
416 smbios_detect(ptr);
418 efi_serial_init(); /* detect and set up serial ports */
419 interact(NULL); /* doesn't return */
421 return (EFI_SUCCESS); /* keep compiler happy */
424 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
426 static int
427 command_reboot(int argc __attribute((unused)),
428 char *argv[] __attribute((unused)))
430 int i;
432 for (i = 0; devsw[i] != NULL; ++i)
433 if (devsw[i]->dv_cleanup != NULL)
434 (devsw[i]->dv_cleanup)();
436 RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
438 /* NOTREACHED */
439 return (CMD_ERROR);
442 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
444 static int
445 command_memmap(int argc __attribute((unused)),
446 char *argv[] __attribute((unused)))
448 UINTN sz;
449 EFI_MEMORY_DESCRIPTOR *map, *p;
450 UINTN key, dsz;
451 UINT32 dver;
452 EFI_STATUS status;
453 int i, ndesc;
454 int rv = 0;
455 char line[80];
457 sz = 0;
458 status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
459 if (status != EFI_BUFFER_TOO_SMALL) {
460 printf("Can't determine memory map size\n");
461 return (CMD_ERROR);
463 map = malloc(sz);
464 status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
465 if (EFI_ERROR(status)) {
466 printf("Can't read memory map\n");
467 return (CMD_ERROR);
470 ndesc = sz / dsz;
471 snprintf(line, 80, "%23s %12s %12s %8s %4s\n",
472 "Type", "Physical", "Virtual", "#Pages", "Attr");
473 pager_open();
474 rv = pager_output(line);
475 if (rv) {
476 pager_close();
477 return (CMD_OK);
480 for (i = 0, p = map; i < ndesc;
481 i++, p = NextMemoryDescriptor(p, dsz)) {
482 snprintf(line, 80, "%23s %012lx %012lx %08lx ",
483 efi_memory_type(p->Type),
484 p->PhysicalStart,
485 p->VirtualStart,
486 p->NumberOfPages);
487 rv = pager_output(line);
488 if (rv)
489 break;
491 if (p->Attribute & EFI_MEMORY_UC)
492 printf("UC ");
493 if (p->Attribute & EFI_MEMORY_WC)
494 printf("WC ");
495 if (p->Attribute & EFI_MEMORY_WT)
496 printf("WT ");
497 if (p->Attribute & EFI_MEMORY_WB)
498 printf("WB ");
499 if (p->Attribute & EFI_MEMORY_UCE)
500 printf("UCE ");
501 if (p->Attribute & EFI_MEMORY_WP)
502 printf("WP ");
503 if (p->Attribute & EFI_MEMORY_RP)
504 printf("RP ");
505 if (p->Attribute & EFI_MEMORY_XP)
506 printf("XP ");
507 if (p->Attribute & EFI_MEMORY_NV)
508 printf("NV ");
509 if (p->Attribute & EFI_MEMORY_MORE_RELIABLE)
510 printf("MR ");
511 if (p->Attribute & EFI_MEMORY_RO)
512 printf("RO ");
513 rv = pager_output("\n");
514 if (rv)
515 break;
518 pager_close();
519 return (CMD_OK);
522 COMMAND_SET(configuration, "configuration", "print configuration tables",
523 command_configuration);
525 static int
526 command_configuration(int argc __attribute((unused)),
527 char *argv[] __attribute((unused)))
529 UINTN i;
530 char *name;
532 printf("NumberOfTableEntries=%lu\n",
533 (unsigned long)ST->NumberOfTableEntries);
534 for (i = 0; i < ST->NumberOfTableEntries; i++) {
535 EFI_GUID *guid;
537 printf(" ");
538 guid = &ST->ConfigurationTable[i].VendorGuid;
540 if (efi_guid_to_name(guid, &name) == true) {
541 printf(name);
542 free(name);
543 } else {
544 printf("Error while translating UUID to name");
546 printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
549 return (CMD_OK);
553 COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode);
555 static int
556 command_mode(int argc, char *argv[])
558 UINTN cols, rows;
559 unsigned int mode;
560 int i;
561 char *cp;
562 char rowenv[8];
563 EFI_STATUS status;
564 SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
565 extern void HO(void);
567 conout = ST->ConOut;
569 if (argc > 1) {
570 mode = strtol(argv[1], &cp, 0);
571 if (cp[0] != '\0') {
572 printf("Invalid mode\n");
573 return (CMD_ERROR);
575 status = conout->QueryMode(conout, mode, &cols, &rows);
576 if (EFI_ERROR(status)) {
577 printf("invalid mode %d\n", mode);
578 return (CMD_ERROR);
580 status = conout->SetMode(conout, mode);
581 if (EFI_ERROR(status)) {
582 printf("couldn't set mode %d\n", mode);
583 return (CMD_ERROR);
585 sprintf(rowenv, "%u", (unsigned)rows);
586 setenv("LINES", rowenv, 1);
587 sprintf(rowenv, "%u", (unsigned)cols);
588 setenv("COLUMNS", rowenv, 1);
589 HO(); /* set cursor */
590 return (CMD_OK);
593 printf("Current mode: %d\n", conout->Mode->Mode);
594 for (i = 0; i <= conout->Mode->MaxMode; i++) {
595 status = conout->QueryMode(conout, i, &cols, &rows);
596 if (EFI_ERROR(status))
597 continue;
598 printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols,
599 (unsigned)rows);
602 if (i != 0)
603 printf("Select a mode with the command \"mode <number>\"\n");
605 return (CMD_OK);
608 COMMAND_SET(lsefi, "lsefi", "list EFI handles", command_lsefi);
610 static int
611 command_lsefi(int argc __attribute((unused)),
612 char *argv[] __attribute((unused)))
614 char *name;
615 EFI_HANDLE *buffer = NULL;
616 EFI_HANDLE handle;
617 UINTN bufsz = 0, i, j;
618 EFI_STATUS status;
619 int ret;
621 status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
622 if (status != EFI_BUFFER_TOO_SMALL) {
623 snprintf(command_errbuf, sizeof (command_errbuf),
624 "unexpected error: %lld", (long long)status);
625 return (CMD_ERROR);
627 if ((buffer = malloc(bufsz)) == NULL) {
628 sprintf(command_errbuf, "out of memory");
629 return (CMD_ERROR);
632 status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
633 if (EFI_ERROR(status)) {
634 free(buffer);
635 snprintf(command_errbuf, sizeof (command_errbuf),
636 "LocateHandle() error: %lld", (long long)status);
637 return (CMD_ERROR);
640 pager_open();
641 for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) {
642 UINTN nproto = 0;
643 EFI_GUID **protocols = NULL;
645 handle = buffer[i];
646 printf("Handle %p", handle);
647 if (pager_output("\n"))
648 break;
649 /* device path */
651 status = BS->ProtocolsPerHandle(handle, &protocols, &nproto);
652 if (EFI_ERROR(status)) {
653 snprintf(command_errbuf, sizeof (command_errbuf),
654 "ProtocolsPerHandle() error: %lld",
655 (long long)status);
656 continue;
659 for (j = 0; j < nproto; j++) {
660 if (efi_guid_to_name(protocols[j], &name) == true) {
661 printf(" %s", name);
662 free(name);
663 } else {
664 printf("Error while translating UUID to name");
666 if ((ret = pager_output("\n")) != 0)
667 break;
669 BS->FreePool(protocols);
670 if (ret != 0)
671 break;
673 pager_close();
674 free(buffer);
675 return (CMD_OK);
678 COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset",
679 command_lszfs);
681 static int
682 command_lszfs(int argc, char *argv[])
684 int err;
686 if (argc != 2) {
687 command_errmsg = "wrong number of arguments";
688 return (CMD_ERROR);
691 err = zfs_list(argv[1]);
692 if (err != 0) {
693 command_errmsg = strerror(err);
694 return (CMD_ERROR);
696 return (CMD_OK);
699 #ifdef __FreeBSD__
700 COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments",
701 command_reloadbe);
703 static int
704 command_reloadbe(int argc, char *argv[])
706 int err;
707 char *root;
709 if (argc > 2) {
710 command_errmsg = "wrong number of arguments";
711 return (CMD_ERROR);
714 if (argc == 2) {
715 err = zfs_bootenv(argv[1]);
716 } else {
717 root = getenv("zfs_be_root");
718 if (root == NULL) {
719 return (CMD_OK);
721 err = zfs_bootenv(root);
724 if (err != 0) {
725 command_errmsg = strerror(err);
726 return (CMD_ERROR);
729 return (CMD_OK);
731 #endif /* __FreeBSD__ */
733 void
734 efi_serial_init(void)
736 EFI_HANDLE *buffer = NULL;
737 UINTN bufsz = 0, i;
738 EFI_STATUS status;
739 int serial = 0;
742 * get buffer size
744 status = BS->LocateHandle(ByProtocol, &serial_io, NULL, &bufsz, buffer);
745 if (status != EFI_BUFFER_TOO_SMALL) {
746 snprintf(command_errbuf, sizeof (command_errbuf),
747 "unexpected error: %lld", (long long)status);
748 return;
750 if ((buffer = malloc(bufsz)) == NULL) {
751 sprintf(command_errbuf, "out of memory");
752 return;
756 * get handle array
758 status = BS->LocateHandle(ByProtocol, &serial_io, NULL, &bufsz, buffer);
759 if (EFI_ERROR(status)) {
760 free(buffer);
761 snprintf(command_errbuf, sizeof (command_errbuf),
762 "LocateHandle() error: %lld", (long long)status);
763 return;
766 for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) {
767 SERIAL_IO_INTERFACE *sio;
768 status = BS->OpenProtocol(buffer[i], &serial_io, (void**)&sio,
769 IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
770 if (EFI_ERROR(status)) {
771 snprintf(command_errbuf, sizeof (command_errbuf),
772 "OpenProtocol() error: %lld", (long long)status);
774 printf("serial# %d\n", serial++);
777 free(buffer);
780 #ifdef LOADER_FDT_SUPPORT
781 extern int command_fdt_internal(int argc, char *argv[]);
784 * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
785 * and declaring it as extern is in contradiction with COMMAND_SET() macro
786 * (which uses static pointer), we're defining wrapper function, which
787 * calls the proper fdt handling routine.
789 static int
790 command_fdt(int argc, char *argv[])
792 return (command_fdt_internal(argc, argv));
795 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
796 #endif
799 * Chain load another efi loader.
801 static int
802 command_chain(int argc, char *argv[])
804 EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
805 EFI_HANDLE loaderhandle;
806 EFI_LOADED_IMAGE *loaded_image;
807 EFI_STATUS status;
808 struct stat st;
809 struct devdesc *dev;
810 char *name, *path;
811 void *buf;
812 int fd;
814 if (argc < 2) {
815 command_errmsg = "wrong number of arguments";
816 return (CMD_ERROR);
819 name = argv[1];
821 if ((fd = open(name, O_RDONLY)) < 0) {
822 command_errmsg = "no such file";
823 return (CMD_ERROR);
826 if (fstat(fd, &st) < -1) {
827 command_errmsg = "stat failed";
828 close(fd);
829 return (CMD_ERROR);
832 status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf);
833 if (status != EFI_SUCCESS) {
834 command_errmsg = "failed to allocate buffer";
835 close(fd);
836 return (CMD_ERROR);
838 if (read(fd, buf, st.st_size) != st.st_size) {
839 command_errmsg = "error while reading the file";
840 (void)BS->FreePool(buf);
841 close(fd);
842 return (CMD_ERROR);
844 close(fd);
845 status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle);
846 (void)BS->FreePool(buf);
847 if (status != EFI_SUCCESS) {
848 command_errmsg = "LoadImage failed";
849 return (CMD_ERROR);
851 status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
852 (void **)&loaded_image);
854 if (argc > 2) {
855 int i, len = 0;
856 CHAR16 *argp;
858 for (i = 2; i < argc; i++)
859 len += strlen(argv[i]) + 1;
861 len *= sizeof (*argp);
862 loaded_image->LoadOptions = argp = malloc (len);
863 if (loaded_image->LoadOptions == NULL) {
864 (void) BS->UnloadImage(loaded_image);
865 return (CMD_ERROR);
867 loaded_image->LoadOptionsSize = len;
868 for (i = 2; i < argc; i++) {
869 char *ptr = argv[i];
870 while (*ptr)
871 *(argp++) = *(ptr++);
872 *(argp++) = ' ';
874 *(--argv) = 0;
877 if (efi_getdev((void **)&dev, name, (const char **)&path) == 0)
878 loaded_image->DeviceHandle =
879 efi_find_handle(dev->d_dev, dev->d_unit);
881 dev_cleanup();
882 status = BS->StartImage(loaderhandle, NULL, NULL);
883 if (status != EFI_SUCCESS) {
884 command_errmsg = "StartImage failed";
885 free(loaded_image->LoadOptions);
886 loaded_image->LoadOptions = NULL;
887 status = BS->UnloadImage(loaded_image);
888 return (CMD_ERROR);
891 return (CMD_ERROR); /* not reached */
894 COMMAND_SET(chain, "chain", "chain load file", command_chain);
896 #ifdef EFI_ZFS_BOOT
897 static void
898 efi_zfs_probe(void)
900 EFI_HANDLE h;
901 u_int unit;
902 int i;
903 char dname[SPECNAMELEN + 1];
904 uint64_t guid;
906 unit = 0;
907 h = efi_find_handle(&efipart_dev, 0);
908 for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) {
909 snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i);
910 if (zfs_probe_dev(dname, &guid) == 0)
911 (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid);
915 uint64_t
916 ldi_get_size(void *priv)
918 int fd = (uintptr_t) priv;
919 uint64_t size;
921 ioctl(fd, DIOCGMEDIASIZE, &size);
922 return (size);
924 #endif