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