boot.c revision 1.17.12.2 1 /* $NetBSD: boot.c,v 1.17.12.2 2021/08/01 22:42:10 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * 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.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include "efiboot.h"
30
31 #include <sys/bootblock.h>
32 #include <sys/boot_flag.h>
33 #include <machine/limits.h>
34
35 #include "bootcfg.h"
36 #include "bootmod.h"
37 #include "bootmenu.h"
38 #include "biosdisk.h"
39 #include "devopen.h"
40
41 #ifdef _STANDALONE
42 #include <bootinfo.h>
43 #endif
44
45 int errno;
46 int boot_biosdev;
47 daddr_t boot_biossector;
48
49 extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[];
50
51 extern struct x86_boot_params boot_params;
52 extern char twiddle_toggle;
53
54 static const char * const names[][2] = {
55 { "netbsd", "netbsd.gz" },
56 { "onetbsd", "onetbsd.gz" },
57 { "netbsd.old", "netbsd.old.gz" },
58 };
59
60 #define NUMNAMES __arraycount(names)
61 #define DEFFILENAME names[0][0]
62
63 #ifndef EFIBOOTCFG_FILENAME
64 #define EFIBOOTCFG_FILENAME "esp:/EFI/NetBSD/boot.cfg"
65 #endif
66
67 void command_help(char *);
68 void command_quit(char *);
69 void command_boot(char *);
70 void command_pkboot(char *);
71 void command_consdev(char *);
72 void command_root(char *);
73 void command_dev(char *);
74 void command_devpath(char *);
75 void command_efivar(char *);
76 void command_gop(char *);
77 #if LIBSA_ENABLE_LS_OP
78 void command_ls(char *);
79 #endif
80 void command_memmap(char *);
81 #ifndef SMALL
82 void command_menu(char *);
83 #endif
84 void command_modules(char *);
85 void command_multiboot(char *);
86 void command_text(char *);
87 void command_version(char *);
88
89 const struct bootblk_command commands[] = {
90 { "help", command_help },
91 { "?", command_help },
92 { "quit", command_quit },
93 { "boot", command_boot },
94 { "pkboot", command_pkboot },
95 { "consdev", command_consdev },
96 { "root", command_root },
97 { "dev", command_dev },
98 { "devpath", command_devpath },
99 { "efivar", command_efivar },
100 { "fs", fs_add },
101 { "gop", command_gop },
102 { "load", module_add },
103 #if LIBSA_ENABLE_LS_OP
104 { "ls", command_ls },
105 #endif
106 { "memmap", command_memmap },
107 #ifndef SMALL
108 { "menu", command_menu },
109 #endif
110 { "modules", command_modules },
111 { "multiboot", command_multiboot },
112 { "rndseed", rnd_add },
113 { "splash", splash_add },
114 { "text", command_text },
115 { "userconf", userconf_add },
116 { "version", command_version },
117 { NULL, NULL },
118 };
119
120 static char *default_fsname;
121 static char *default_devname;
122 static int default_unit, default_partition;
123 static const char *default_filename;
124 static const char *default_part_name;
125
126 static char *sprint_bootsel(const char *);
127 static void bootit(const char *, int);
128
129 int
130 parsebootfile(const char *fname, char **fsname, char **devname, int *unit,
131 int *partition, const char **file)
132 {
133 const char *col;
134 static char savedevname[MAXDEVNAME+1];
135 #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
136 const struct netboot_fstab *nf;
137 #endif
138
139 *fsname = default_fsname;
140 if (default_part_name == NULL) {
141 *devname = default_devname;
142 } else {
143 snprintf(savedevname, sizeof(savedevname),
144 "NAME=%s", default_part_name);
145 *devname = savedevname;
146 }
147 *unit = default_unit;
148 *partition = default_partition;
149 *file = default_filename;
150
151 if (fname == NULL)
152 return 0;
153
154 if ((col = strchr(fname, ':')) != NULL) { /* device given */
155 int devlen;
156 int u = 0, p = 0;
157 int i = 0;
158
159 devlen = col - fname;
160 if (devlen > MAXDEVNAME)
161 return EINVAL;
162
163 if (strstr(fname, "NAME=") == fname) {
164 strlcpy(savedevname, fname, devlen + 1);
165 *fsname = "ufs";
166 *devname = savedevname;
167 *unit = -1;
168 *partition = -1;
169 fname = col + 1;
170 goto out;
171 }
172
173 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z')
174 if (!isvalidname(fname[i]))
175 return EINVAL;
176 do {
177 savedevname[i] = fname[i];
178 i++;
179 } while (isvalidname(fname[i]));
180 savedevname[i] = '\0';
181
182 #define isnum(c) ((c) >= '0' && (c) <= '9')
183 if (i < devlen) {
184 if (!isnum(fname[i]))
185 return EUNIT;
186 do {
187 u *= 10;
188 u += fname[i++] - '0';
189 } while (isnum(fname[i]));
190 }
191
192 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z')
193 if (i < devlen) {
194 if (!isvalidpart(fname[i]))
195 return EPART;
196 p = fname[i++] - 'a';
197 }
198
199 if (i != devlen)
200 return ENXIO;
201
202 #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
203 nf = netboot_fstab_find(savedevname);
204 if (nf != NULL)
205 *fsname = (char *)nf->name;
206 else
207 #endif
208 *fsname = "ufs";
209 *devname = savedevname;
210 *unit = u;
211 *partition = p;
212 fname = col + 1;
213 }
214
215 out:
216 if (*fname)
217 *file = fname;
218
219 return 0;
220 }
221
222 static char *
223 snprint_bootdev(char *buf, size_t bufsize, const char *devname, int unit,
224 int partition)
225 {
226 static const char *no_partition_devs[] = { "esp", "net", "nfs", "tftp" };
227 int i;
228
229 for (i = 0; i < __arraycount(no_partition_devs); i++)
230 if (strcmp(devname, no_partition_devs[i]) == 0)
231 break;
232 if (strstr(devname, "NAME=") == devname)
233 strlcpy(buf, devname, bufsize);
234 else
235 snprintf(buf, bufsize, "%s%d%c", devname, unit,
236 i < __arraycount(no_partition_devs) ? '\0' : 'a' + partition);
237 return buf;
238 }
239
240 static char *
241 sprint_bootsel(const char *filename)
242 {
243 char *fsname, *devname;
244 int unit, partition;
245 const char *file;
246 static char buf[80];
247
248 if (parsebootfile(filename, &fsname, &devname, &unit,
249 &partition, &file) == 0) {
250 snprintf(buf, sizeof(buf), "%s:%s", snprint_bootdev(buf,
251 sizeof(buf), devname, unit, partition), file);
252 return buf;
253 }
254 return "(invalid)";
255 }
256
257 void
258 clearit(void)
259 {
260
261 if (bootcfg_info.clear)
262 clear_pc_screen();
263 }
264
265 static void
266 bootit(const char *filename, int howto)
267 {
268
269 if (howto & AB_VERBOSE)
270 printf("booting %s (howto 0x%x)\n", sprint_bootsel(filename),
271 howto);
272
273 if (exec_netbsd(filename, efi_loadaddr, howto, 0, efi_cleanup) < 0)
274 printf("boot: %s: %s\n", sprint_bootsel(filename),
275 strerror(errno));
276 else
277 printf("boot returned\n");
278 }
279
280 void
281 print_banner(void)
282 {
283 int n;
284
285 clearit();
286 if (bootcfg_info.banner[0]) {
287 for (n = 0; n < BOOTCFG_MAXBANNER && bootcfg_info.banner[n];
288 n++)
289 printf("%s\n", bootcfg_info.banner[n]);
290 } else {
291 printf("\n"
292 " \\-__,------,___.\n"
293 " \\ __,---` %s (from NetBSD %s)\n"
294 " \\ `---,_. Revision %s\n"
295 " \\-,_____,.---` Memory: %d/%d k\n"
296 " \\\n"
297 " \\\n"
298 " \\\n",
299 bootprog_name, bootprog_kernrev,
300 bootprog_rev,
301 getbasemem(), getextmem());
302 }
303 }
304
305 void
306 boot(void)
307 {
308 int currname;
309 int c;
310 #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
311 const struct netboot_fstab *nf;
312 #endif
313
314 boot_modules_enabled = !(boot_params.bp_flags & X86_BP_FLAGS_NOMODULES);
315
316 /* try to set default device to what BIOS tells us */
317 bios2dev(boot_biosdev, boot_biossector, &default_devname, &default_unit,
318 &default_partition, &default_part_name);
319
320 /* if the user types "boot" without filename */
321 default_filename = DEFFILENAME;
322
323 #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
324 nf = netboot_fstab_find(default_devname);
325 if (nf != NULL)
326 default_fsname = (char *)nf->name;
327 else
328 #endif
329 default_fsname = "ufs";
330
331 if (!(boot_params.bp_flags & X86_BP_FLAGS_NOBOOTCONF)) {
332 #ifdef EFIBOOTCFG_FILENAME
333 int rv = EINVAL;
334 if (efi_bootdp_type != BOOT_DEVICE_TYPE_NET)
335 rv = parsebootconf(EFIBOOTCFG_FILENAME);
336 if (rv)
337 #endif
338 parsebootconf(BOOTCFG_FILENAME);
339 } else {
340 bootcfg_info.timeout = boot_params.bp_timeout;
341 }
342
343 /*
344 * If console set in boot.cfg, switch to it.
345 * This will print the banner, so we don't need to explicitly do it
346 */
347 if (bootcfg_info.consdev)
348 command_consdev(bootcfg_info.consdev);
349 else
350 print_banner();
351
352 /* Display the menu, if applicable */
353 twiddle_toggle = 0;
354 if (bootcfg_info.nummenu > 0) {
355 /* Does not return */
356 doboottypemenu();
357 }
358
359 printf("Press return to boot now, any other key for boot menu\n");
360 for (currname = 0; currname < NUMNAMES; currname++) {
361 printf("booting %s - starting in ",
362 sprint_bootsel(names[currname][0]));
363
364 c = awaitkey((bootcfg_info.timeout < 0) ? 0
365 : bootcfg_info.timeout, 1);
366 if ((c != '\r') && (c != '\n') && (c != '\0')) {
367 if ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0) {
368 /* do NOT ask for password */
369 bootmenu(); /* does not return */
370 } else {
371 /* DO ask for password */
372 if (check_password((char *)boot_params.bp_password)) {
373 /* password ok */
374 printf("type \"?\" or \"help\" for help.\n");
375 bootmenu(); /* does not return */
376 } else {
377 /* bad password */
378 printf("Wrong password.\n");
379 currname = 0;
380 continue;
381 }
382 }
383 }
384
385 /*
386 * try pairs of names[] entries, foo and foo.gz
387 */
388 /* don't print "booting..." again */
389 bootit(names[currname][0], 0);
390 /* since it failed, try compressed bootfile. */
391 bootit(names[currname][1], AB_VERBOSE);
392 }
393
394 bootmenu(); /* does not return */
395 }
396
397 /* ARGSUSED */
398 void
399 command_help(char *arg)
400 {
401
402 printf("commands are:\n"
403 "boot [dev:][filename] [-12acdqsvxz]\n"
404 #ifndef NO_RAIDFRAME
405 " dev syntax is (hd|fd|cd|raid)[N[x]]\n"
406 #else
407 " dev syntax is (hd|fd|cd)[N[x]]\n"
408 #endif
409 #ifndef NO_GPT
410 " or NAME=gpt_label\n"
411 #endif
412 " (ex. \"hd0a:netbsd.old -s\")\n"
413 "pkboot [dev:][filename] [-12acdqsvxz]\n"
414 "dev [dev:]\n"
415 "consdev {pc|com[0123][,{speed}]|com,{ioport}[,{speed}]}\n"
416 "root {spec}\n"
417 " spec can be disk, e.g. wd0, sd0\n"
418 " or string like wedge:name\n"
419 "devpath\n"
420 "efivar\n"
421 "gop [{modenum|list}]\n"
422 "load {path_to_module}\n"
423 #if LIBSA_ENABLE_LS_OP
424 "ls [dev:][path]\n"
425 #endif
426 "memmap [{sorted|unsorted|compact}]\n"
427 #ifndef SMALL
428 "menu (reenters boot menu, if defined in boot.cfg)\n"
429 #endif
430 "modules {on|off|enabled|disabled}\n"
431 "multiboot [dev:][filename] [<args>]\n"
432 "rndseed {path_to_rndseed_file}\n"
433 "splash {path_to_image_file}\n"
434 "text [{modenum|list}]\n"
435 "userconf {command}\n"
436 "version\n"
437 "help|?\n"
438 "quit\n");
439 }
440
441 #if LIBSA_ENABLE_LS_OP
442 void
443 command_ls(char *arg)
444 {
445 const char *save = default_filename;
446
447 default_filename = "/";
448 ls(arg);
449 default_filename = save;
450 }
451 #endif
452
453 /* ARGSUSED */
454 void
455 command_quit(char *arg)
456 {
457
458 printf("Exiting...\n");
459 delay(1 * 1000 * 1000);
460 reboot();
461 /* Note: we shouldn't get to this point! */
462 panic("Could not reboot!");
463 }
464
465 void
466 command_boot(char *arg)
467 {
468 char *filename;
469 int howto;
470
471 if (!parseboot(arg, &filename, &howto))
472 return;
473
474 if (filename != NULL) {
475 bootit(filename, howto);
476 } else {
477 int i;
478
479 if (howto == 0)
480 bootdefault();
481 for (i = 0; i < NUMNAMES; i++) {
482 bootit(names[i][0], howto);
483 bootit(names[i][1], howto);
484 }
485 }
486 }
487
488 void
489 command_pkboot(char *arg)
490 {
491 extern int has_prekern;
492 has_prekern = 1;
493 command_boot(arg);
494 has_prekern = 0;
495 }
496
497 void
498 command_dev(char *arg)
499 {
500 static char savedevname[MAXDEVNAME + 1];
501 char buf[80];
502 char *devname;
503 const char *file; /* dummy */
504
505 if (*arg == '\0') {
506 efi_disk_show();
507 efi_net_show();
508
509 if (default_part_name != NULL)
510 printf("default NAME=%s\n", default_part_name);
511 else
512 printf("default %s\n",
513 snprint_bootdev(buf, sizeof(buf),
514 default_devname, default_unit,
515 default_partition));
516 return;
517 }
518
519 if (strchr(arg, ':') == NULL ||
520 parsebootfile(arg, &default_fsname, &devname, &default_unit,
521 &default_partition, &file)) {
522 command_help(NULL);
523 return;
524 }
525
526 /* put to own static storage */
527 strncpy(savedevname, devname, MAXDEVNAME + 1);
528 default_devname = savedevname;
529
530 /* +5 to skip leading NAME= */
531 if (strstr(devname, "NAME=") == devname)
532 default_part_name = default_devname + 5;
533 }
534
535 static const struct cons_devs {
536 const char *name;
537 u_int tag;
538 int ioport;
539 } cons_devs[] = {
540 { "pc", CONSDEV_PC, 0 },
541 { "com0", CONSDEV_COM0, 0 },
542 { "com1", CONSDEV_COM1, 0 },
543 { "com2", CONSDEV_COM2, 0 },
544 { "com3", CONSDEV_COM3, 0 },
545 { "com0kbd", CONSDEV_COM0KBD, 0 },
546 { "com1kbd", CONSDEV_COM1KBD, 0 },
547 { "com2kbd", CONSDEV_COM2KBD, 0 },
548 { "com3kbd", CONSDEV_COM3KBD, 0 },
549 { "com", CONSDEV_COM0, -1 },
550 { "auto", CONSDEV_AUTO, 0 },
551 { NULL, 0 }
552 };
553
554 void
555 command_consdev(char *arg)
556 {
557 const struct cons_devs *cdp;
558 char *sep, *sep2 = NULL;
559 int ioport, speed = 0;
560
561 if (*arg == '\0') {
562 efi_cons_show();
563 return;
564 }
565
566 sep = strchr(arg, ',');
567 if (sep != NULL) {
568 *sep++ = '\0';
569 sep2 = strchr(sep, ',');
570 if (sep2 != NULL)
571 *sep2++ = '\0';
572 }
573
574 for (cdp = cons_devs; cdp->name; cdp++) {
575 if (strcmp(arg, cdp->name) == 0) {
576 ioport = cdp->ioport;
577 if (cdp->tag == CONSDEV_PC || cdp->tag == CONSDEV_AUTO) {
578 if (sep != NULL || sep2 != NULL)
579 goto error;
580 } else {
581 /* com? */
582 if (ioport == -1) {
583 if (sep != NULL) {
584 u_long t = strtoul(sep, NULL, 0);
585 if (t > INT_MAX)
586 goto error;
587 ioport = (int)t;
588 }
589 if (sep2 != NULL) {
590 speed = atoi(sep2);
591 if (speed < 0)
592 goto error;
593 }
594 } else {
595 if (sep != NULL) {
596 speed = atoi(sep);
597 if (speed < 0)
598 goto error;
599 }
600 if (sep2 != NULL)
601 goto error;
602 }
603 }
604 efi_consinit(cdp->tag, ioport, speed);
605 print_banner();
606 return;
607 }
608 }
609 error:
610 printf("invalid console device.\n");
611 }
612
613 void
614 command_root(char *arg)
615 {
616 struct btinfo_rootdevice *biv = &bi_root;
617
618 strncpy(biv->devname, arg, sizeof(biv->devname));
619 if (biv->devname[sizeof(biv->devname)-1] != '\0') {
620 biv->devname[sizeof(biv->devname)-1] = '\0';
621 printf("truncated to %s\n",biv->devname);
622 }
623 }
624
625
626 #ifndef SMALL
627 /* ARGSUSED */
628 void
629 command_menu(char *arg)
630 {
631
632 if (bootcfg_info.nummenu > 0) {
633 /* Does not return */
634 doboottypemenu();
635 } else
636 printf("No menu defined in boot.cfg\n");
637 }
638 #endif /* !SMALL */
639
640 void
641 command_modules(char *arg)
642 {
643
644 if (strcmp(arg, "enabled") == 0 ||
645 strcmp(arg, "on") == 0)
646 boot_modules_enabled = true;
647 else if (strcmp(arg, "disabled") == 0 ||
648 strcmp(arg, "off") == 0)
649 boot_modules_enabled = false;
650 else
651 printf("invalid flag, must be 'enabled' or 'disabled'.\n");
652 }
653
654 void
655 command_multiboot(char *arg)
656 {
657 char *filename;
658
659 filename = arg;
660 if (exec_multiboot(filename, gettrailer(arg)) < 0)
661 printf("multiboot: %s: %s\n", sprint_bootsel(filename),
662 strerror(errno));
663 else
664 printf("boot returned\n");
665 }
666
667 void
668 command_version(char *arg)
669 {
670 CHAR16 *path;
671 char *upath, *ufirmware;
672 int rv;
673
674 if (strcmp(arg, "full") == 0) {
675 printf("ImageBase: 0x%" PRIxPTR "\n",
676 (uintptr_t)efi_li->ImageBase);
677 printf("Stack: 0x%" PRIxPTR "\n", efi_main_sp);
678 printf("EFI version: %d.%02d\n",
679 ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
680 ufirmware = NULL;
681 rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware);
682 if (rv == 0) {
683 printf("EFI Firmware: %s (rev %d.%02d)\n", ufirmware,
684 ST->FirmwareRevision >> 16,
685 ST->FirmwareRevision & 0xffff);
686 FreePool(ufirmware);
687 }
688 path = DevicePathToStr(efi_bootdp);
689 upath = NULL;
690 rv = ucs2_to_utf8(path, &upath);
691 FreePool(path);
692 if (rv == 0) {
693 printf("Boot DevicePath: %d:%d:%s\n",
694 DevicePathType(efi_bootdp),
695 DevicePathSubType(efi_bootdp), upath);
696 FreePool(upath);
697 }
698 }
699
700 printf("\n"
701 ">> %s, Revision %s (from NetBSD %s)\n"
702 ">> Memory: %d/%d k\n",
703 bootprog_name, bootprog_rev, bootprog_kernrev,
704 getbasemem(), getextmem());
705 }
706
707 void
708 command_memmap(char *arg)
709 {
710 bool sorted = true;
711 bool compact = false;
712
713 if (*arg == '\0' || strcmp(arg, "sorted") == 0)
714 /* Already sorted is true. */;
715 else if (strcmp(arg, "unsorted") == 0)
716 sorted = false;
717 else if (strcmp(arg, "compact") == 0)
718 compact = true;
719 else {
720 printf("invalid flag, "
721 "must be 'sorted', 'unsorted' or 'compact'.\n");
722 return;
723 }
724
725 efi_memory_show_map(sorted, compact);
726 }
727
728 void
729 command_devpath(char *arg)
730 {
731 EFI_STATUS status;
732 UINTN i, nhandles;
733 EFI_HANDLE *handles;
734 EFI_DEVICE_PATH *dp0, *dp;
735 CHAR16 *path;
736 char *upath;
737 UINTN cols, rows, row = 0;
738 int rv;
739
740 status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut,
741 ST->ConOut->Mode->Mode, &cols, &rows);
742 if (EFI_ERROR(status) || rows <= 2)
743 rows = 0;
744 else
745 rows -= 2;
746
747 /*
748 * all devices.
749 */
750 status = LibLocateHandle(ByProtocol, &DevicePathProtocol, NULL,
751 &nhandles, &handles);
752 if (EFI_ERROR(status))
753 return;
754
755 for (i = 0; i < nhandles; i++) {
756 status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
757 &DevicePathProtocol, (void **)&dp0);
758 if (EFI_ERROR(status))
759 break;
760
761 printf("DevicePathType %d\n", DevicePathType(dp0));
762 if (++row >= rows) {
763 row = 0;
764 printf("Press Any Key to continue :");
765 (void) awaitkey(-1, 0);
766 printf("\n");
767 }
768 for (dp = dp0;
769 !IsDevicePathEnd(dp);
770 dp = NextDevicePathNode(dp)) {
771
772 path = DevicePathToStr(dp);
773 upath = NULL;
774 rv = ucs2_to_utf8(path, &upath);
775 FreePool(path);
776 if (rv) {
777 printf("convert failed\n");
778 break;
779 }
780
781 printf("%d:%d:%s\n", DevicePathType(dp),
782 DevicePathSubType(dp), upath);
783 FreePool(upath);
784
785 if (++row >= rows) {
786 row = 0;
787 printf("Press Any Key to continue :");
788 (void) awaitkey(-1, 0);
789 printf("\n");
790 }
791 }
792 }
793 }
794
795
796 void
797 command_efivar(char *arg)
798 {
799 static const char header[] =
800 "GUID Variable Name Value\n"
801 "==================================== ==================== ========\n";
802 EFI_STATUS status;
803 UINTN sz = 64, osz;
804 CHAR16 *name = NULL, *tmp, *val, guid[128];
805 char *uname, *uval, *uguid;
806 EFI_GUID vendor;
807 UINTN cols, rows, row = 0;
808 int rv;
809
810 status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut,
811 ST->ConOut->Mode->Mode, &cols, &rows);
812 if (EFI_ERROR(status) || rows <= 2)
813 rows = 0;
814 else
815 rows -= 2;
816
817 name = AllocatePool(sz);
818 if (name == NULL) {
819 printf("memory allocation failed: %" PRIuMAX" bytes\n",
820 (uintmax_t)sz);
821 return;
822 }
823
824 SetMem(name, sz, 0);
825 vendor = NullGuid;
826
827 printf("%s", header);
828 for (;;) {
829 osz = sz;
830 status = uefi_call_wrapper(RT->GetNextVariableName, 3,
831 &sz, name, &vendor);
832 if (EFI_ERROR(status)) {
833 if (status == EFI_NOT_FOUND)
834 break;
835 if (status != EFI_BUFFER_TOO_SMALL) {
836 printf("GetNextVariableName failed: %" PRIxMAX "\n",
837 (uintmax_t)status);
838 break;
839 }
840
841 tmp = AllocatePool(sz);
842 if (tmp == NULL) {
843 printf("memory allocation failed: %" PRIuMAX
844 "bytes\n", (uintmax_t)sz);
845 break;
846 }
847 SetMem(tmp, sz, 0);
848 CopyMem(tmp, name, osz);
849 FreePool(name);
850 name = tmp;
851 continue;
852 }
853
854 val = LibGetVariable(name, &vendor);
855 if (val != NULL) {
856 uval = NULL;
857 rv = ucs2_to_utf8(val, &uval);
858 FreePool(val);
859 if (rv) {
860 printf("value convert failed\n");
861 break;
862 }
863 } else
864 uval = NULL;
865 uname = NULL;
866 rv = ucs2_to_utf8(name, &uname);
867 if (rv) {
868 printf("name convert failed\n");
869 FreePool(uval);
870 break;
871 }
872 GuidToString(guid, &vendor);
873 uguid = NULL;
874 rv = ucs2_to_utf8(guid, &uguid);
875 if (rv) {
876 printf("GUID convert failed\n");
877 FreePool(uval);
878 FreePool(uname);
879 break;
880 }
881 printf("%-35s %-20s %s\n", uguid, uname, uval ? uval : "(null)");
882 FreePool(uguid);
883 FreePool(uname);
884 if (uval != NULL)
885 FreePool(uval);
886
887 if (++row >= rows) {
888 row = 0;
889 printf("Press Any Key to continue :");
890 (void) awaitkey(-1, 0);
891 printf("\n");
892 }
893 }
894
895 FreePool(name);
896 }
897