blob: 3cf7894d9222d92822d9e8d0bc975fe4fd669943 [file] [log] [blame]
Toomas Soome199767f2015-10-25 00:06:51 +03001/*-
2 * Copyright (c) 2008-2010 Rui Paulo
3 * Copyright (c) 2006 Marcel Moolenaar
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <sys/param.h>
32#include <sys/reboot.h>
33#include <sys/boot.h>
34#include <stand.h>
35#include <string.h>
36#include <setjmp.h>
37
38#include <efi.h>
39#include <efilib.h>
40#include <efigpt.h>
41
42#include <bootstrap.h>
43#include <smbios.h>
44
45#ifdef EFI_ZFS_BOOT
46#include <libzfs.h>
47#endif
48
49#include "loader_efi.h"
50
51extern char bootprog_name[];
52extern char bootprog_rev[];
53extern char bootprog_date[];
54extern char bootprog_maker[];
55
56struct arch_switch archsw; /* MI/MD interface boundary */
57
58EFI_GUID acpi = ACPI_TABLE_GUID;
59EFI_GUID acpi20 = ACPI_20_TABLE_GUID;
60EFI_GUID devid = DEVICE_PATH_PROTOCOL;
61EFI_GUID imgid = LOADED_IMAGE_PROTOCOL;
62EFI_GUID mps = MPS_TABLE_GUID;
63EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL;
64EFI_GUID smbios = SMBIOS_TABLE_GUID;
65EFI_GUID smbios3 = SMBIOS3_TABLE_GUID;
66EFI_GUID dxe = DXE_SERVICES_TABLE_GUID;
67EFI_GUID hoblist = HOB_LIST_TABLE_GUID;
68EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID;
69EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID;
70EFI_GUID fdtdtb = FDT_TABLE_GUID;
71EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL;
72EFI_GUID serial_io = SERIAL_IO_PROTOCOL;
73
Toomas Soomedcba96f2016-10-09 17:12:23 +030074extern void acpi_detect(void);
Toomas Soome199767f2015-10-25 00:06:51 +030075void efi_serial_init(void);
76#ifdef EFI_ZFS_BOOT
77static void efi_zfs_probe(void);
78#endif
79
80/*
81 * Need this because EFI uses UTF-16 unicode string constants, but we
Toomas Soome03502722016-11-11 22:35:51 +020082 * use UTF-8. We can't use printf due to the possibility of \0 and we
83 * don't support wide characters either.
Toomas Soome199767f2015-10-25 00:06:51 +030084 */
85static void
86print_str16(const CHAR16 *str)
87{
88 int i;
89
90 for (i = 0; str[i]; i++)
91 printf("%c", (char)str[i]);
92}
93
94static void
95cp16to8(const CHAR16 *src, char *dst, size_t len)
96{
97 size_t i;
98
99 for (i = 0; i < len && src[i]; i++)
100 dst[i] = (char)src[i];
101}
102
103static int
104has_keyboard(void)
105{
106 EFI_STATUS status;
107 EFI_DEVICE_PATH *path;
108 EFI_HANDLE *hin, *hin_end, *walker;
109 UINTN sz;
110 int retval = 0;
111
112 /*
113 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
114 * do the typical dance to get the right sized buffer.
115 */
116 sz = 0;
117 hin = NULL;
118 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0);
119 if (status == EFI_BUFFER_TOO_SMALL) {
120 hin = (EFI_HANDLE *)malloc(sz);
121 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz,
122 hin);
123 if (EFI_ERROR(status))
124 free(hin);
125 }
126 if (EFI_ERROR(status))
127 return retval;
128
129 /*
130 * Look at each of the handles. If it supports the device path protocol,
131 * use it to get the device path for this handle. Then see if that
132 * device path matches either the USB device path for keyboards or the
133 * legacy device path for keyboards.
134 */
135 hin_end = &hin[sz / sizeof(*hin)];
136 for (walker = hin; walker < hin_end; walker++) {
137 status = BS->HandleProtocol(*walker, &devid, (VOID **)&path);
138 if (EFI_ERROR(status))
139 continue;
140
141 while (!IsDevicePathEnd(path)) {
142 /*
143 * Check for the ACPI keyboard node. All PNP3xx nodes
144 * are keyboards of different flavors. Note: It is
145 * unclear of there's always a keyboard node when
146 * there's a keyboard controller, or if there's only one
147 * when a keyboard is detected at boot.
148 */
149 if (DevicePathType(path) == ACPI_DEVICE_PATH &&
150 (DevicePathSubType(path) == ACPI_DP ||
151 DevicePathSubType(path) == ACPI_EXTENDED_DP)) {
152 ACPI_HID_DEVICE_PATH *acpi;
153
154 acpi = (ACPI_HID_DEVICE_PATH *)(void *)path;
155 if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 &&
156 (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) {
157 retval = 1;
158 goto out;
159 }
160 /*
161 * Check for USB keyboard node, if present. Unlike a
162 * PS/2 keyboard, these definitely only appear when
163 * connected to the system.
164 */
165 } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH &&
166 DevicePathSubType(path) == MSG_USB_CLASS_DP) {
167 USB_CLASS_DEVICE_PATH *usb;
168
169 usb = (USB_CLASS_DEVICE_PATH *)(void *)path;
170 if (usb->DeviceClass == 3 && /* HID */
171 usb->DeviceSubClass == 1 && /* Boot devices */
172 usb->DeviceProtocol == 1) { /* Boot keyboards */
173 retval = 1;
174 goto out;
175 }
176 }
177 path = NextDevicePathNode(path);
178 }
179 }
180out:
181 free(hin);
182 return retval;
183}
184
185EFI_STATUS
186main(int argc, CHAR16 *argv[])
187{
188 char var[128];
189 EFI_LOADED_IMAGE *img;
190 EFI_GUID *guid;
191 int i, j, vargood, unit, howto;
192 struct devsw *dev;
193 uint64_t pool_guid;
Toomas Soomedcba96f2016-10-09 17:12:23 +0300194 void *ptr;
Toomas Soome199767f2015-10-25 00:06:51 +0300195 UINTN k;
196 int has_kbd;
197
198 archsw.arch_autoload = efi_autoload;
199 archsw.arch_getdev = efi_getdev;
200 archsw.arch_copyin = efi_copyin;
201 archsw.arch_copyout = efi_copyout;
202 archsw.arch_readin = efi_readin;
203#ifdef EFI_ZFS_BOOT
204 /* Note this needs to be set before ZFS init. */
205 archsw.arch_zfs_probe = efi_zfs_probe;
206#endif
207
208 has_kbd = has_keyboard();
209
210 /*
211 * XXX Chicken-and-egg problem; we want to have console output
212 * early, but some console attributes may depend on reading from
213 * eg. the boot device, which we can't do yet. We can use
214 * printf() etc. once this is done.
215 */
216 cons_probe();
217
218 /*
219 * Initialise the block cache. Set the upper limit.
220 */
221 bcache_init(32768, 512);
222
223 /*
224 * Parse the args to set the console settings, etc
225 * boot1.efi passes these in, if it can read /boot.config or /boot/config
226 * or iPXE may be setup to pass these in.
227 *
228 * Loop through the args, and for each one that contains an '=' that is
229 * not the first character, add it to the environment. This allows
230 * loader and kernel env vars to be passed on the command line. Convert
231 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied.
232 */
233 howto = 0;
234 for (i = 1; i < argc; i++) {
235 if (argv[i][0] == '-') {
236 for (j = 1; argv[i][j] != 0; j++) {
237 int ch;
238
239 ch = argv[i][j];
240 switch (ch) {
241 case 'a':
242 howto |= RB_ASKNAME;
243 break;
244 case 'd':
245 howto |= RB_KDB;
246 break;
247 case 'D':
248 howto |= RB_MULTIPLE;
249 break;
250 case 'h':
251 howto |= RB_SERIAL;
252 break;
253 case 'm':
254 howto |= RB_MUTE;
255 break;
256 case 'p':
257 howto |= RB_PAUSE;
258 break;
259 case 'P':
260 if (!has_kbd)
261 howto |= RB_SERIAL | RB_MULTIPLE;
262 break;
263 case 'r':
264 howto |= RB_DFLTROOT;
265 break;
266 case 's':
267 howto |= RB_SINGLE;
268 break;
269 case 'S':
270 if (argv[i][j + 1] == 0) {
271 if (i + 1 == argc) {
272 setenv("comconsole_speed", "115200", 1);
273 } else {
274 cp16to8(&argv[i + 1][0], var,
275 sizeof(var));
276 setenv("comconsole_speedspeed", var, 1);
277 }
278 i++;
279 break;
280 } else {
281 cp16to8(&argv[i][j + 1], var,
282 sizeof(var));
283 setenv("comconsole_speed", var, 1);
284 break;
285 }
286 case 'v':
287 howto |= RB_VERBOSE;
288 break;
289 }
290 }
291 } else {
292 vargood = 0;
293 for (j = 0; argv[i][j] != 0; j++) {
294 if (j == sizeof(var)) {
295 vargood = 0;
296 break;
297 }
298 if (j > 0 && argv[i][j] == '=')
299 vargood = 1;
300 var[j] = (char)argv[i][j];
301 }
302 if (vargood) {
303 var[j] = 0;
304 putenv(var);
305 }
306 }
307 }
308 for (i = 0; howto_names[i].ev != NULL; i++)
309 if (howto & howto_names[i].mask)
310 setenv(howto_names[i].ev, "YES", 1);
311 if (howto & RB_MULTIPLE) {
312 if (howto & RB_SERIAL)
313 setenv("console", "ttya text" , 1);
314 else
315 setenv("console", "text ttya" , 1);
316 } else if (howto & RB_SERIAL) {
317 setenv("console", "ttya" , 1);
318 }
319
320 if (efi_copy_init()) {
321 printf("failed to allocate staging area\n");
322 return (EFI_BUFFER_TOO_SMALL);
323 }
324
325 /*
326 * March through the device switch probing for things.
327 */
328 for (i = 0; devsw[i] != NULL; i++)
329 if (devsw[i]->dv_init != NULL)
330 (devsw[i]->dv_init)();
331
332 /* Get our loaded image protocol interface structure. */
333 BS->HandleProtocol(IH, &imgid, (VOID**)&img);
334
335 printf("Command line arguments:");
336 for (i = 0; i < argc; i++) {
337 printf(" ");
338 print_str16(argv[i]);
339 }
340 printf("\n");
341
342 printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
343 printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
344 ST->Hdr.Revision & 0xffff);
345 printf("EFI Firmware: ");
346 /* printf doesn't understand EFI Unicode */
347 ST->ConOut->OutputString(ST->ConOut, ST->FirmwareVendor);
348 printf(" (rev %d.%02d)\n", ST->FirmwareRevision >> 16,
349 ST->FirmwareRevision & 0xffff);
350
351 printf("\n");
352 printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
353 printf("(%s, %s)\n", bootprog_maker, bootprog_date);
354
355 /*
356 * Disable the watchdog timer. By default the boot manager sets
357 * the timer to 5 minutes before invoking a boot option. If we
358 * want to return to the boot manager, we have to disable the
359 * watchdog timer and since we're an interactive program, we don't
360 * want to wait until the user types "quit". The timer may have
361 * fired by then. We don't care if this fails. It does not prevent
362 * normal functioning in any way...
363 */
364 BS->SetWatchdogTimer(0, 0, 0, NULL);
365
366 if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &pool_guid) != 0)
367 return (EFI_NOT_FOUND);
368
369 switch (dev->dv_type) {
370#ifdef EFI_ZFS_BOOT
371 case DEVT_ZFS: {
372 struct zfs_devdesc currdev;
373
374 currdev.d_dev = dev;
375 currdev.d_unit = unit;
376 currdev.d_type = currdev.d_dev->dv_type;
377 currdev.d_opendata = NULL;
378 currdev.pool_guid = pool_guid;
379 currdev.root_guid = 0;
380 env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
381 efi_setcurrdev, env_nounset);
382 env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
383 env_nounset);
384#ifdef __FreeBSD__
385 init_zfs_bootenv(zfs_fmtdev(&currdev));
386#endif
387 break;
388 }
389#endif
390 default: {
391 struct devdesc currdev;
392
393 currdev.d_dev = dev;
394 currdev.d_unit = unit;
395 currdev.d_opendata = NULL;
396 currdev.d_type = currdev.d_dev->dv_type;
397 env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
398 efi_setcurrdev, env_nounset);
399 env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
400 env_nounset);
401 break;
402 }
403 }
404
405 setenv("LINES", "24", 1); /* optional */
406 setenv("COLUMNS", "80", 1); /* optional */
407 setenv("ISADIR", "amd64", 1); /* we only build 64bit */
Toomas Soomedcba96f2016-10-09 17:12:23 +0300408 acpi_detect();
Toomas Soome199767f2015-10-25 00:06:51 +0300409
Toomas Soomedcba96f2016-10-09 17:12:23 +0300410 if ((ptr = efi_get_table(&smbios3)) == NULL)
411 ptr = efi_get_table(&smbios);
412 smbios_detect(ptr);
Toomas Soome199767f2015-10-25 00:06:51 +0300413
414 efi_serial_init(); /* detect and set up serial ports */
415 interact(NULL); /* doesn't return */
416
417 return (EFI_SUCCESS); /* keep compiler happy */
418}
419
420COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
421
422static int
423command_reboot(int argc __attribute((unused)),
424 char *argv[] __attribute((unused)))
425{
426 int i;
427 const CHAR16 *msg = L"Reboot from the loader";
428
429 for (i = 0; devsw[i] != NULL; ++i)
430 if (devsw[i]->dv_cleanup != NULL)
431 (devsw[i]->dv_cleanup)();
432
433 RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 23, (CHAR16 *)msg);
434
435 /* NOTREACHED */
436 return (CMD_ERROR);
437}
438
439COMMAND_SET(memmap, "memmap", "print memory map", command_memmap);
440
441static int
442command_memmap(int argc __attribute((unused)),
443 char *argv[] __attribute((unused)))
444{
445 UINTN sz;
446 EFI_MEMORY_DESCRIPTOR *map, *p;
447 UINTN key, dsz;
448 UINT32 dver;
449 EFI_STATUS status;
450 int i, ndesc;
451 int rv = 0;
452 char line[80];
453 static const char *types[] = {
454 "Reserved",
455 "LoaderCode",
456 "LoaderData",
457 "BootServicesCode",
458 "BootServicesData",
459 "RuntimeServicesCode",
460 "RuntimeServicesData",
461 "ConventionalMemory",
462 "UnusableMemory",
463 "ACPIReclaimMemory",
464 "ACPIMemoryNVS",
465 "MemoryMappedIO",
466 "MemoryMappedIOPortSpace",
467 "PalCode"
468 };
469
470 sz = 0;
471 status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
472 if (status != EFI_BUFFER_TOO_SMALL) {
473 printf("Can't determine memory map size\n");
474 return (CMD_ERROR);
475 }
476 map = malloc(sz);
477 status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
478 if (EFI_ERROR(status)) {
479 printf("Can't read memory map\n");
480 return (CMD_ERROR);
481 }
482
483 ndesc = sz / dsz;
484 snprintf(line, 80, "%23s %12s %12s %8s %4s\n",
485 "Type", "Physical", "Virtual", "#Pages", "Attr");
486 pager_open();
487 rv = pager_output(line);
488 if (rv) {
489 pager_close();
490 return (CMD_OK);
491 }
492
493 for (i = 0, p = map; i < ndesc;
494 i++, p = NextMemoryDescriptor(p, dsz)) {
495 snprintf(line, 80, "%23s %012lx %012lx %08lx ",
496 types[p->Type],
497 p->PhysicalStart,
498 p->VirtualStart,
499 p->NumberOfPages);
500 rv = pager_output(line);
501 if (rv)
502 break;
503
504 if (p->Attribute & EFI_MEMORY_UC)
505 printf("UC ");
506 if (p->Attribute & EFI_MEMORY_WC)
507 printf("WC ");
508 if (p->Attribute & EFI_MEMORY_WT)
509 printf("WT ");
510 if (p->Attribute & EFI_MEMORY_WB)
511 printf("WB ");
512 if (p->Attribute & EFI_MEMORY_UCE)
513 printf("UCE ");
514 if (p->Attribute & EFI_MEMORY_WP)
515 printf("WP ");
516 if (p->Attribute & EFI_MEMORY_RP)
517 printf("RP ");
518 if (p->Attribute & EFI_MEMORY_XP)
519 printf("XP ");
520 rv = pager_output("\n");
521 if (rv)
522 break;
523 }
524
525 pager_close();
526 return (CMD_OK);
527}
528
529COMMAND_SET(configuration, "configuration", "print configuration tables",
530 command_configuration);
531
532static const char *
533guid_to_string(EFI_GUID *guid)
534{
535 static char buf[40];
536
537 sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
538 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0],
539 guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4],
540 guid->Data4[5], guid->Data4[6], guid->Data4[7]);
541 return (buf);
542}
543
544static int
545command_configuration(int argc __attribute((unused)),
546 char *argv[] __attribute((unused)))
547{
548 UINTN i;
549
550 printf("NumberOfTableEntries=%lu\n",
551 (unsigned long)ST->NumberOfTableEntries);
552 for (i = 0; i < ST->NumberOfTableEntries; i++) {
553 EFI_GUID *guid;
554
555 printf(" ");
556 guid = &ST->ConfigurationTable[i].VendorGuid;
557 if (!memcmp(guid, &mps, sizeof(EFI_GUID)))
558 printf("MPS Table");
559 else if (!memcmp(guid, &acpi, sizeof(EFI_GUID)))
560 printf("ACPI Table");
561 else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID)))
562 printf("ACPI 2.0 Table");
563 else if (!memcmp(guid, &smbios, sizeof(EFI_GUID)))
564 printf("SMBIOS Table");
565 else if (!memcmp(guid, &smbios3, sizeof(EFI_GUID)))
566 printf("SMBIOS3 Table");
567 else if (!memcmp(guid, &dxe, sizeof(EFI_GUID)))
568 printf("DXE Table");
569 else if (!memcmp(guid, &hoblist, sizeof(EFI_GUID)))
570 printf("HOB List Table");
571 else if (!memcmp(guid, &memtype, sizeof(EFI_GUID)))
572 printf("Memory Type Information Table");
573 else if (!memcmp(guid, &debugimg, sizeof(EFI_GUID)))
574 printf("Debug Image Info Table");
575 else if (!memcmp(guid, &fdtdtb, sizeof(EFI_GUID)))
576 printf("FDT Table");
577 else
578 printf("Unknown Table (%s)", guid_to_string(guid));
579 printf(" at %p\n", ST->ConfigurationTable[i].VendorTable);
580 }
581
582 return (CMD_OK);
583}
584
585
586COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode);
587
588static int
589command_mode(int argc, char *argv[])
590{
591 UINTN cols, rows;
592 unsigned int mode;
593 int i;
594 char *cp;
595 char rowenv[8];
596 EFI_STATUS status;
597 SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
598 extern void HO(void);
599
600 conout = ST->ConOut;
601
602 if (argc > 1) {
603 mode = strtol(argv[1], &cp, 0);
604 if (cp[0] != '\0') {
605 printf("Invalid mode\n");
606 return (CMD_ERROR);
607 }
608 status = conout->QueryMode(conout, mode, &cols, &rows);
609 if (EFI_ERROR(status)) {
610 printf("invalid mode %d\n", mode);
611 return (CMD_ERROR);
612 }
613 status = conout->SetMode(conout, mode);
614 if (EFI_ERROR(status)) {
615 printf("couldn't set mode %d\n", mode);
616 return (CMD_ERROR);
617 }
618 sprintf(rowenv, "%u", (unsigned)rows);
619 setenv("LINES", rowenv, 1);
620 sprintf(rowenv, "%u", (unsigned)cols);
621 setenv("COLUMNS", rowenv, 1);
622 HO(); /* set cursor */
623 return (CMD_OK);
624 }
625
626 printf("Current mode: %d\n", conout->Mode->Mode);
627 for (i = 0; i <= conout->Mode->MaxMode; i++) {
628 status = conout->QueryMode(conout, i, &cols, &rows);
629 if (EFI_ERROR(status))
630 continue;
631 printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols,
632 (unsigned)rows);
633 }
634
635 if (i != 0)
636 printf("Select a mode with the command \"mode <number>\"\n");
637
638 return (CMD_OK);
639}
640
641
642COMMAND_SET(nvram, "nvram", "get NVRAM variables", command_nvram);
643
644static int
645command_nvram(int argc __attribute((unused)),
646 char *argv[] __attribute((unused)))
647{
648 CHAR16 var[128];
649 UINT8 *data; /* value is in bytes */
650 EFI_STATUS status;
651 EFI_GUID varguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
652 UINTN varsz, datasz, i;
653 UINT32 attr;
654 SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
655
656 conout = ST->ConOut;
657
658 pager_open();
659 var[0] = 0; /* Initiate the enumeration */
660 varsz = 128;
661
662 for (status = RS->GetNextVariableName(&varsz, var, &varguid);
663 status != EFI_NOT_FOUND;
664 status = RS->GetNextVariableName(&varsz, var, &varguid)) {
665
666 /*
667 * as term emu is keeping track on cursor, use putchar().
668 */
669 for (i = 0; var[i] != 0; i++)
670 putchar(var[i]);
671 varsz = 128; /* GetNextVariableName() did change it. */
672
673 printf(": Attributes:");
674 datasz = 0;
675 status = RS->GetVariable(var, &varguid, &attr, &datasz, NULL);
676 if ((data = malloc(datasz)) == NULL)
677 break;
678 status = RS->GetVariable(var, &varguid, &attr, &datasz, data);
679 if (EFI_ERROR(status))
680 printf("<error retrieving variable>");
681 else {
682 if (attr & EFI_VARIABLE_NON_VOLATILE)
683 printf(" NV");
684 if (attr & EFI_VARIABLE_BOOTSERVICE_ACCESS)
685 printf(" BS");
686 if (attr & EFI_VARIABLE_RUNTIME_ACCESS)
687 printf(" RS");
688 if (attr & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
689 printf(" HR");
690 if (attr & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
691 printf(" AW");
692 if (attr &
693 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
694 printf(" TW");
695
696 printf(": DataLength: %lld", (long long)datasz);
697 }
698 free(data);
699 if (pager_output("\n"))
700 break;
701 }
702
703 pager_close();
704 return (CMD_OK);
705}
706
707struct protocol_name {
708 EFI_GUID guid;
709 const char *name;
710} proto_names[] = {
711 { DEVICE_PATH_PROTOCOL, "device path" },
712 { BLOCK_IO_PROTOCOL, "block io" },
713 { DISK_IO_PROTOCOL, "disk io" },
714 { EFI_DISK_INFO_PROTOCOL_GUID, "disk info" },
715 { SIMPLE_FILE_SYSTEM_PROTOCOL, "simple fs" },
716 { LOAD_FILE_PROTOCOL, "load file" },
717 { DEVICE_IO_PROTOCOL, "device io" },
718 { UNICODE_COLLATION_PROTOCOL, "unicode collation" },
719 { EFI_UNICODE_COLLATION2_PROTOCOL_GUID, "unicode collation2" },
720 { EFI_SIMPLE_NETWORK_PROTOCOL, "simple network" },
721 { SIMPLE_TEXT_OUTPUT_PROTOCOL, "simple text output" },
722 { SIMPLE_TEXT_INPUT_PROTOCOL, "simple text input" },
723 { EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID, "simple text ex input" },
724 { EFI_CONSOLE_CONTROL_PROTOCOL_GUID, "console control" },
725 { EFI_CONSOLE_IN_DEVICE_GUID, "stdin" },
726 { EFI_CONSOLE_OUT_DEVICE_GUID, "stdout" },
727 { EFI_STANDARD_ERROR_DEVICE_GUID, "stderr" },
728 { EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, "GOP" },
729 { EFI_UGA_DRAW_PROTOCOL_GUID, "UGA draw" },
730 { EFI_PXE_BASE_CODE_PROTOCOL, "PXE base code" },
731 { EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL, "PXE base code callback" },
732 { SERIAL_IO_PROTOCOL, "serial io" },
733 { LOADED_IMAGE_PROTOCOL, "loaded image" },
734 { EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID,
735 "loaded image device path" },
736 { EFI_ISA_IO_PROTOCOL_GUID, "ISA io" },
737 { EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID, "IDE controller init" },
738 { EFI_ISA_ACPI_PROTOCOL_GUID, "ISA ACPI" },
739 { EFI_PCI_IO_PROTOCOL_GUID, "PCI" },
740 { EFI_PCI_ROOT_IO_GUID, "PCI root" },
741 { EFI_PCI_ENUMERATION_COMPLETE_GUID, "PCI enumeration" },
742 { EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID, "Driver diagnostics" },
743 { EFI_DRIVER_DIAGNOSTICS2_PROTOCOL_GUID, "Driver diagnostics2" },
744 { EFI_SIMPLE_POINTER_PROTOCOL_GUID, "simple pointer" },
745 { EFI_ABSOLUTE_POINTER_PROTOCOL_GUID, "absolute pointer" },
746 { EFI_VLAN_CONFIG_PROTOCOL_GUID, "VLAN config" },
747 { EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID, "ARP service binding" },
748 { EFI_ARP_PROTOCOL_GUID, "ARP" },
749 { EFI_IP4_SERVICE_BINDING_PROTOCOL, "IPv4 service binding" },
750 { EFI_IP4_PROTOCOL, "IPv4" },
751 { EFI_IP4_CONFIG_PROTOCOL_GUID, "IPv4 config" },
752 { EFI_IP6_SERVICE_BINDING_PROTOCOL, "IPv6 service binding" },
753 { EFI_IP6_PROTOCOL, "IPv6" },
754 { EFI_IP6_CONFIG_PROTOCOL_GUID, "IPv6 config" },
755 { EFI_UDP4_PROTOCOL, "UDPv4" },
756 { EFI_UDP4_SERVICE_BINDING_PROTOCOL, "UDPv4 service binding" },
757 { EFI_UDP6_PROTOCOL, "UDPv6" },
758 { EFI_UDP6_SERVICE_BINDING_PROTOCOL, "UDPv6 service binding" },
759 { EFI_TCP4_PROTOCOL, "TCPv4" },
760 { EFI_TCP4_SERVICE_BINDING_PROTOCOL, "TCPv4 service binding" },
761 { EFI_TCP6_PROTOCOL, "TCPv6" },
762 { EFI_TCP6_SERVICE_BINDING_PROTOCOL, "TCPv6 service binding" },
763 { EFI_PART_TYPE_EFI_SYSTEM_PART_GUID, "EFI System partition" },
764 { EFI_PART_TYPE_LEGACY_MBR_GUID, "MBR legacy" },
765 { EFI_DEVICE_TREE_GUID, "device tree" },
766 { EFI_USB_IO_PROTOCOL_GUID, "USB io" },
767 { EFI_USB2_HC_PROTOCOL_GUID, "USB2 HC" },
768 { EFI_COMPONENT_NAME_PROTOCOL_GUID, "component name" },
769 { EFI_COMPONENT_NAME2_PROTOCOL_GUID, "component name2" },
770 { EFI_DRIVER_BINDING_PROTOCOL_GUID, "driver binding" },
771 { EFI_DRIVER_CONFIGURATION_PROTOCOL_GUID, "driver configuration" },
772 { EFI_DRIVER_CONFIGURATION2_PROTOCOL_GUID, "driver configuration2" },
773 { EFI_DECOMPRESS_PROTOCOL_GUID, "decompress" },
774 { EFI_EBC_INTERPRETER_PROTOCOL_GUID, "ebc interpreter" },
775 { EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL,
776 "network interface identifier" },
777 { EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_31,
778 "network interface identifier_31" },
779 { EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID,
780 "managed network service binding" },
781 { EFI_MANAGED_NETWORK_PROTOCOL_GUID, "managed network" },
782 { EFI_FORM_BROWSER2_PROTOCOL_GUID, "form browser" },
783 { EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID, "HII config routing" },
784 { EFI_HII_DATABASE_PROTOCOL_GUID, "HII database" },
785 { EFI_HII_STRING_PROTOCOL_GUID, "HII string" },
786 { EFI_HII_IMAGE_PROTOCOL_GUID, "HII image" },
787 { EFI_HII_FONT_PROTOCOL_GUID, "HII font" },
788 { EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID, "HII config" },
789 { EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID, "MTFTP4 service binding" },
790 { EFI_MTFTP4_PROTOCOL_GUID, "MTFTP4" },
791 { EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID, "MTFTP6 service binding" },
792 { EFI_MTFTP6_PROTOCOL_GUID, "MTFTP6" },
793 { EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID, "DHCP4 service binding" },
794 { EFI_DHCP4_PROTOCOL_GUID, "DHCP4" },
795 { EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID, "DHCP6 service binding" },
796 { EFI_DHCP6_PROTOCOL_GUID, "DHCP6" },
797 { EFI_SCSI_IO_PROTOCOL_GUID, "SCSI io" },
798 { EFI_SCSI_PASS_THRU_PROTOCOL_GUID, "SCSI pass thru" },
799 { EFI_EXT_SCSI_PASS_THRU_PROTOCOL_GUID, "SCSI pass thru ext" },
800 { EFI_CAPSULE_ARCH_PROTOCOL_GUID, "Capsule arch" },
801 { EFI_MONOTONIC_COUNTER_ARCH_PROTOCOL_GUID, "monotonic counter arch" },
802 { EFI_REALTIME_CLOCK_ARCH_PROTOCOL_GUID, "realtime clock arch" },
803 { EFI_VARIABLE_ARCH_PROTOCOL_GUID, "variable arch" },
804 { EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID, "variable write arch" },
805 { EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID, "watchdog timer arch" },
806 { EFI_MP_SERVICES_PROTOCOL_GUID, "MP services" },
807 { EFI_ACPI_SUPPORT_PROTOCOL_GUID, "ACPI support" },
808 { EFI_BDS_ARCH_PROTOCOL_GUID, "BDS arch" },
809 { EFI_METRONOME_ARCH_PROTOCOL_GUID, "metronome arch" },
810 { EFI_TIMER_ARCH_PROTOCOL_GUID, "timer arch" },
811 { EFI_DPC_PROTOCOL_GUID, "DPC" },
812 { EFI_PRINT2_PROTOCOL_GUID, "print2" },
813 { EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID, "device path to text" },
814 { EFI_RESET_ARCH_PROTOCOL_GUID, "reset arch" },
815 { EFI_CPU_ARCH_PROTOCOL_GUID, "CPU arch" },
816 { EFI_CPU_IO2_PROTOCOL_GUID, "CPU IO2" },
817 { EFI_LEGACY_8259_PROTOCOL_GUID, "Legacy 8259" },
818 { EFI_SECURITY_ARCH_PROTOCOL_GUID, "Security arch" },
819 { EFI_SECURITY2_ARCH_PROTOCOL_GUID, "Security2 arch" },
820 { EFI_RUNTIME_ARCH_PROTOCOL_GUID, "Runtime arch" },
821 { EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID, "status code runtime" },
822 { EFI_DATA_HUB_PROTOCOL_GUID, "data hub" },
823 { PCD_PROTOCOL_GUID, "PCD" },
824 { EFI_PCD_PROTOCOL_GUID, "EFI PCD" },
825 { EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID, "firmware volume block" },
826 { EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID, "firmware volume2" },
827 { EFI_FIRMWARE_VOLUME_DISPATCH_PROTOCOL_GUID,
828 "firmware volume dispatch" },
829 { LZMA_COMPRESS_GUID, "lzma compress" },
830 { { 0,0,0,{0,0,0,0,0,0,0,0} }, NULL } /* must be last entry */
831};
832
833COMMAND_SET(lsefi, "lsefi", "list EFI handles", command_lsefi);
834
835static int
836command_lsefi(int argc __attribute((unused)),
837 char *argv[] __attribute((unused)))
838{
839 EFI_HANDLE *buffer = NULL;
840 EFI_HANDLE handle;
841 UINTN bufsz = 0, i, j;
842 EFI_STATUS status;
843 int k, ret;
844
845 status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
846 if (status != EFI_BUFFER_TOO_SMALL) {
847 snprintf(command_errbuf, sizeof (command_errbuf),
848 "unexpected error: %lld", (long long)status);
849 return (CMD_ERROR);
850 }
851 if ((buffer = malloc(bufsz)) == NULL) {
852 sprintf(command_errbuf, "out of memory");
853 return (CMD_ERROR);
854 }
855
856 status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer);
857 if (EFI_ERROR(status)) {
858 free(buffer);
859 snprintf(command_errbuf, sizeof (command_errbuf),
860 "LocateHandle() error: %lld", (long long)status);
861 return (CMD_ERROR);
862 }
863
864 pager_open();
865 for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) {
866 UINTN nproto = 0;
867 EFI_GUID **protocols = NULL;
868
869 handle = buffer[i];
870 printf("Handle %p", handle);
871 if (pager_output("\n"))
872 break;
873 /* device path */
874
875 status = BS->ProtocolsPerHandle(handle, &protocols, &nproto);
876 if (EFI_ERROR(status)) {
877 snprintf(command_errbuf, sizeof (command_errbuf),
878 "ProtocolsPerHandle() error: %lld",
879 (long long)status);
880 continue;
881 }
882 for (j = 0; j < nproto; j++) {
883 for (k = 0; proto_names[k].name != NULL; k++)
884 if (memcmp(protocols[j], &proto_names[k].guid,
885 sizeof (proto_names[k].guid)) == 0)
886 break;
887 if (proto_names[k].name != NULL)
888 printf(" %s", proto_names[k].name);
889 else
890 printf(" %s", guid_to_string(protocols[j]));
891 ret = pager_output("\n");
892 if (ret)
893 break;
894 }
895 BS->FreePool(protocols);
896 if (ret)
897 break;
898 }
899 pager_close();
900 free(buffer);
901 return (CMD_OK);
902}
903
904#ifdef EFI_ZFS_BOOT
905COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset",
906 command_lszfs);
907
908static int
909command_lszfs(int argc, char *argv[])
910{
911 int err;
912
913 if (argc != 2) {
914 command_errmsg = "wrong number of arguments";
915 return (CMD_ERROR);
916 }
917
918 err = zfs_list(argv[1]);
919 if (err != 0) {
920 command_errmsg = strerror(err);
921 return (CMD_ERROR);
922 }
923 return (CMD_OK);
924}
925
926#ifdef __FreeBSD__
927COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments",
928 command_reloadbe);
929
930static int
931command_reloadbe(int argc, char *argv[])
932{
933 int err;
934 char *root;
935
936 if (argc > 2) {
937 command_errmsg = "wrong number of arguments";
938 return (CMD_ERROR);
939 }
940
941 if (argc == 2) {
942 err = zfs_bootenv(argv[1]);
943 } else {
944 root = getenv("zfs_be_root");
945 if (root == NULL) {
946 return (CMD_OK);
947 }
948 err = zfs_bootenv(root);
949 }
950
951 if (err != 0) {
952 command_errmsg = strerror(err);
953 return (CMD_ERROR);
954 }
955
956 return (CMD_OK);
957}
958#endif /* __FreeBSD__ */
959#endif
960
961void
962efi_serial_init(void)
963{
964 EFI_HANDLE *buffer = NULL;
965 UINTN bufsz = 0, i;
966 EFI_STATUS status;
967 int serial = 0;
968
969 /*
970 * get buffer size
971 */
972 status = BS->LocateHandle(ByProtocol, &serial_io, NULL, &bufsz, buffer);
973 if (status != EFI_BUFFER_TOO_SMALL) {
974 snprintf(command_errbuf, sizeof (command_errbuf),
975 "unexpected error: %lld", (long long)status);
976 return;
977 }
978 if ((buffer = malloc(bufsz)) == NULL) {
979 sprintf(command_errbuf, "out of memory");
980 return;
981 }
982
983 /*
984 * get handle array
985 */
986 status = BS->LocateHandle(ByProtocol, &serial_io, NULL, &bufsz, buffer);
987 if (EFI_ERROR(status)) {
988 free(buffer);
989 snprintf(command_errbuf, sizeof (command_errbuf),
990 "LocateHandle() error: %lld", (long long)status);
991 return;
992 }
993
994 for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) {
995 SERIAL_IO_INTERFACE *sio;
996 status = BS->OpenProtocol(buffer[i], &serial_io, (void**)&sio,
997 IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
998 if (EFI_ERROR(status)) {
999 snprintf(command_errbuf, sizeof (command_errbuf),
1000 "OpenProtocol() error: %lld", (long long)status);
1001 }
1002 printf("serial# %d\n", serial++);
1003 }
1004
1005 free(buffer);
1006}
1007
1008#ifdef LOADER_FDT_SUPPORT
1009extern int command_fdt_internal(int argc, char *argv[]);
1010
1011/*
1012 * Since proper fdt command handling function is defined in fdt_loader_cmd.c,
1013 * and declaring it as extern is in contradiction with COMMAND_SET() macro
1014 * (which uses static pointer), we're defining wrapper function, which
1015 * calls the proper fdt handling routine.
1016 */
1017static int
1018command_fdt(int argc, char *argv[])
1019{
1020 return (command_fdt_internal(argc, argv));
1021}
1022
1023COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
1024#endif
1025
1026#ifdef EFI_ZFS_BOOT
1027static void
1028efi_zfs_probe(void)
1029{
1030 EFI_HANDLE h;
1031 u_int unit;
1032 int i;
1033 char dname[SPECNAMELEN + 1];
1034 uint64_t guid;
1035
1036 unit = 0;
1037 h = efi_find_handle(&efipart_dev, 0);
1038 for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) {
1039 snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i);
1040 if (zfs_probe_dev(dname, &guid) == 0)
1041 (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid);
1042 }
1043}
1044#endif