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