cmd: efidebug: simplify get_guid_text()
[platform/kernel/u-boot.git] / cmd / efidebug.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  UEFI Shell-like command
4  *
5  *  Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
6  */
7
8 #include <charset.h>
9 #include <common.h>
10 #include <command.h>
11 #include <efi_loader.h>
12 #include <exports.h>
13 #include <hexdump.h>
14 #include <malloc.h>
15 #include <search.h>
16 #include <linux/ctype.h>
17
18 #define BS systab.boottime
19 #define RT systab.runtime
20
21 /**
22  * efi_get_device_handle_info() - get information of UEFI device
23  *
24  * @handle:             Handle of UEFI device
25  * @dev_path_text:      Pointer to text of device path
26  * Return:              0 on success, -1 on failure
27  *
28  * Currently return a formatted text of device path.
29  */
30 static int efi_get_device_handle_info(efi_handle_t handle, u16 **dev_path_text)
31 {
32         struct efi_device_path *dp;
33         efi_status_t ret;
34
35         ret = EFI_CALL(BS->open_protocol(handle, &efi_guid_device_path,
36                                          (void **)&dp, NULL /* FIXME */, NULL,
37                                          EFI_OPEN_PROTOCOL_GET_PROTOCOL));
38         if (ret == EFI_SUCCESS) {
39                 *dev_path_text = efi_dp_str(dp);
40                 return 0;
41         } else {
42                 return -1;
43         }
44 }
45
46 #define EFI_HANDLE_WIDTH ((int)sizeof(efi_handle_t) * 2)
47
48 static const char spc[] = "                ";
49 static const char sep[] = "================";
50
51 /**
52  * do_efi_show_devices() - show UEFI devices
53  *
54  * @cmdtp:      Command table
55  * @flag:       Command flag
56  * @argc:       Number of arguments
57  * @argv:       Argument array
58  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
59  *
60  * Implement efidebug "devices" sub-command.
61  * Show all UEFI devices and their information.
62  */
63 static int do_efi_show_devices(cmd_tbl_t *cmdtp, int flag,
64                                int argc, char * const argv[])
65 {
66         efi_handle_t *handles;
67         efi_uintn_t num, i;
68         u16 *dev_path_text;
69         efi_status_t ret;
70
71         ret = EFI_CALL(BS->locate_handle_buffer(ALL_HANDLES, NULL, NULL,
72                                                 &num, &handles));
73         if (ret != EFI_SUCCESS)
74                 return CMD_RET_FAILURE;
75
76         if (!num)
77                 return CMD_RET_SUCCESS;
78
79         printf("Device%.*s Device Path\n", EFI_HANDLE_WIDTH - 6, spc);
80         printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
81         for (i = 0; i < num; i++) {
82                 if (!efi_get_device_handle_info(handles[i], &dev_path_text)) {
83                         printf("%p %ls\n", handles[i], dev_path_text);
84                         efi_free_pool(dev_path_text);
85                 }
86         }
87
88         EFI_CALL(BS->free_pool(handles));
89
90         return CMD_RET_SUCCESS;
91 }
92
93 /**
94  * efi_get_driver_handle_info() - get information of UEFI driver
95  *
96  * @handle:             Handle of UEFI device
97  * @driver_name:        Driver name
98  * @image_path:         Pointer to text of device path
99  * Return:              0 on success, -1 on failure
100  *
101  * Currently return no useful information as all UEFI drivers are
102  * built-in..
103  */
104 static int efi_get_driver_handle_info(efi_handle_t handle, u16 **driver_name,
105                                       u16 **image_path)
106 {
107         struct efi_handler *handler;
108         struct efi_loaded_image *image;
109         efi_status_t ret;
110
111         /*
112          * driver name
113          * TODO: support EFI_COMPONENT_NAME2_PROTOCOL
114          */
115         *driver_name = NULL;
116
117         /* image name */
118         ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler);
119         if (ret != EFI_SUCCESS) {
120                 *image_path = NULL;
121                 return 0;
122         }
123
124         image = handler->protocol_interface;
125         *image_path = efi_dp_str(image->file_path);
126
127         return 0;
128 }
129
130 /**
131  * do_efi_show_drivers() - show UEFI drivers
132  *
133  * @cmdtp:      Command table
134  * @flag:       Command flag
135  * @argc:       Number of arguments
136  * @argv:       Argument array
137  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
138  *
139  * Implement efidebug "drivers" sub-command.
140  * Show all UEFI drivers and their information.
141  */
142 static int do_efi_show_drivers(cmd_tbl_t *cmdtp, int flag,
143                                int argc, char * const argv[])
144 {
145         efi_handle_t *handles;
146         efi_uintn_t num, i;
147         u16 *driver_name, *image_path_text;
148         efi_status_t ret;
149
150         ret = EFI_CALL(BS->locate_handle_buffer(
151                                 BY_PROTOCOL, &efi_guid_driver_binding_protocol,
152                                 NULL, &num, &handles));
153         if (ret != EFI_SUCCESS)
154                 return CMD_RET_FAILURE;
155
156         if (!num)
157                 return CMD_RET_SUCCESS;
158
159         printf("Driver%.*s Name                 Image Path\n",
160                EFI_HANDLE_WIDTH - 6, spc);
161         printf("%.*s ==================== ====================\n",
162                EFI_HANDLE_WIDTH, sep);
163         for (i = 0; i < num; i++) {
164                 if (!efi_get_driver_handle_info(handles[i], &driver_name,
165                                                 &image_path_text)) {
166                         if (image_path_text)
167                                 printf("%p %-20ls %ls\n", handles[i],
168                                        driver_name, image_path_text);
169                         else
170                                 printf("%p %-20ls <built-in>\n",
171                                        handles[i], driver_name);
172                         EFI_CALL(BS->free_pool(driver_name));
173                         EFI_CALL(BS->free_pool(image_path_text));
174                 }
175         }
176
177         EFI_CALL(BS->free_pool(handles));
178
179         return CMD_RET_SUCCESS;
180 }
181
182 static const struct {
183         const char *text;
184         const efi_guid_t guid;
185 } guid_list[] = {
186         {
187                 "Device Path",
188                 EFI_DEVICE_PATH_PROTOCOL_GUID,
189         },
190         {
191                 "Device Path To Text",
192                 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID,
193         },
194         {
195                 "Device Path Utilities",
196                 EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID,
197         },
198         {
199                 "Unicode Collation 2",
200                 EFI_UNICODE_COLLATION_PROTOCOL2_GUID,
201         },
202         {
203                 "Driver Binding",
204                 EFI_DRIVER_BINDING_PROTOCOL_GUID,
205         },
206         {
207                 "Simple Text Input",
208                 EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID,
209         },
210         {
211                 "Simple Text Input Ex",
212                 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID,
213         },
214         {
215                 "Simple Text Output",
216                 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID,
217         },
218         {
219                 "Block IO",
220                 EFI_BLOCK_IO_PROTOCOL_GUID,
221         },
222         {
223                 "Simple File System",
224                 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID,
225         },
226         {
227                 "Loaded Image",
228                 EFI_LOADED_IMAGE_PROTOCOL_GUID,
229         },
230         {
231                 "Graphics Output",
232                 EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID,
233         },
234         {
235                 "HII String",
236                 EFI_HII_STRING_PROTOCOL_GUID,
237         },
238         {
239                 "HII Database",
240                 EFI_HII_DATABASE_PROTOCOL_GUID,
241         },
242         {
243                 "HII Config Routing",
244                 EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID,
245         },
246         {
247                 "Simple Network",
248                 EFI_SIMPLE_NETWORK_PROTOCOL_GUID,
249         },
250         {
251                 "PXE Base Code",
252                 EFI_PXE_BASE_CODE_PROTOCOL_GUID,
253         },
254 };
255
256 /**
257  * get_guid_text - get string of GUID
258  *
259  * Return description of GUID.
260  *
261  * @guid:       GUID
262  * Return:      description of GUID or NULL
263  */
264 static const char *get_guid_text(const void *guid)
265 {
266         int i;
267
268         for (i = 0; i < ARRAY_SIZE(guid_list); i++) {
269                 /*
270                  * As guidcmp uses memcmp() we can safely accept unaligned
271                  * GUIDs.
272                  */
273                 if (!guidcmp(&guid_list[i].guid, guid))
274                         return guid_list[i].text;
275         }
276
277         return NULL;
278 }
279
280 /**
281  * do_efi_show_handles() - show UEFI handles
282  *
283  * @cmdtp:      Command table
284  * @flag:       Command flag
285  * @argc:       Number of arguments
286  * @argv:       Argument array
287  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
288  *
289  * Implement efidebug "dh" sub-command.
290  * Show all UEFI handles and their information, currently all protocols
291  * added to handle.
292  */
293 static int do_efi_show_handles(cmd_tbl_t *cmdtp, int flag,
294                                int argc, char * const argv[])
295 {
296         efi_handle_t *handles;
297         efi_guid_t **guid;
298         efi_uintn_t num, count, i, j;
299         const char *guid_text;
300         efi_status_t ret;
301
302         ret = EFI_CALL(BS->locate_handle_buffer(ALL_HANDLES, NULL, NULL,
303                                                 &num, &handles));
304         if (ret != EFI_SUCCESS)
305                 return CMD_RET_FAILURE;
306
307         if (!num)
308                 return CMD_RET_SUCCESS;
309
310         printf("Handle%.*s Protocols\n", EFI_HANDLE_WIDTH - 6, spc);
311         printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
312         for (i = 0; i < num; i++) {
313                 printf("%p", handles[i]);
314                 ret = EFI_CALL(BS->protocols_per_handle(handles[i], &guid,
315                                                         &count));
316                 if (ret || !count) {
317                         putc('\n');
318                         continue;
319                 }
320
321                 for (j = 0; j < count; j++) {
322                         if (j)
323                                 printf(", ");
324                         else
325                                 putc(' ');
326
327                         guid_text = get_guid_text(guid[j]);
328                         if (guid_text)
329                                 puts(guid_text);
330                         else
331                                 printf("%pUl", guid[j]);
332                 }
333                 putc('\n');
334         }
335
336         EFI_CALL(BS->free_pool(handles));
337
338         return CMD_RET_SUCCESS;
339 }
340
341 /**
342  * do_efi_show_images() - show UEFI images
343  *
344  * @cmdtp:      Command table
345  * @flag:       Command flag
346  * @argc:       Number of arguments
347  * @argv:       Argument array
348  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
349  *
350  * Implement efidebug "images" sub-command.
351  * Show all UEFI loaded images and their information.
352  */
353 static int do_efi_show_images(cmd_tbl_t *cmdtp, int flag,
354                               int argc, char * const argv[])
355 {
356         efi_print_image_infos(NULL);
357
358         return CMD_RET_SUCCESS;
359 }
360
361 static const char * const efi_mem_type_string[] = {
362         [EFI_RESERVED_MEMORY_TYPE] = "RESERVED",
363         [EFI_LOADER_CODE] = "LOADER CODE",
364         [EFI_LOADER_DATA] = "LOADER DATA",
365         [EFI_BOOT_SERVICES_CODE] = "BOOT CODE",
366         [EFI_BOOT_SERVICES_DATA] = "BOOT DATA",
367         [EFI_RUNTIME_SERVICES_CODE] = "RUNTIME CODE",
368         [EFI_RUNTIME_SERVICES_DATA] = "RUNTIME DATA",
369         [EFI_CONVENTIONAL_MEMORY] = "CONVENTIONAL",
370         [EFI_UNUSABLE_MEMORY] = "UNUSABLE MEM",
371         [EFI_ACPI_RECLAIM_MEMORY] = "ACPI RECLAIM MEM",
372         [EFI_ACPI_MEMORY_NVS] = "ACPI NVS",
373         [EFI_MMAP_IO] = "IO",
374         [EFI_MMAP_IO_PORT] = "IO PORT",
375         [EFI_PAL_CODE] = "PAL",
376 };
377
378 static const struct efi_mem_attrs {
379         const u64 bit;
380         const char *text;
381 } efi_mem_attrs[] = {
382         {EFI_MEMORY_UC, "UC"},
383         {EFI_MEMORY_UC, "UC"},
384         {EFI_MEMORY_WC, "WC"},
385         {EFI_MEMORY_WT, "WT"},
386         {EFI_MEMORY_WB, "WB"},
387         {EFI_MEMORY_UCE, "UCE"},
388         {EFI_MEMORY_WP, "WP"},
389         {EFI_MEMORY_RP, "RP"},
390         {EFI_MEMORY_XP, "WP"},
391         {EFI_MEMORY_NV, "NV"},
392         {EFI_MEMORY_MORE_RELIABLE, "REL"},
393         {EFI_MEMORY_RO, "RO"},
394         {EFI_MEMORY_RUNTIME, "RT"},
395 };
396
397 /**
398  * print_memory_attributes() - print memory map attributes
399  *
400  * @attributes: Attribute value
401  *
402  * Print memory map attributes
403  */
404 static void print_memory_attributes(u64 attributes)
405 {
406         int sep, i;
407
408         for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++)
409                 if (attributes & efi_mem_attrs[i].bit) {
410                         if (sep) {
411                                 putc('|');
412                         } else {
413                                 putc(' ');
414                                 sep = 1;
415                         }
416                         puts(efi_mem_attrs[i].text);
417                 }
418 }
419
420 #define EFI_PHYS_ADDR_WIDTH (int)(sizeof(efi_physical_addr_t) * 2)
421
422 /**
423  * do_efi_show_memmap() - show UEFI memory map
424  *
425  * @cmdtp:      Command table
426  * @flag:       Command flag
427  * @argc:       Number of arguments
428  * @argv:       Argument array
429  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
430  *
431  * Implement efidebug "memmap" sub-command.
432  * Show UEFI memory map.
433  */
434 static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag,
435                               int argc, char * const argv[])
436 {
437         struct efi_mem_desc *memmap = NULL, *map;
438         efi_uintn_t map_size = 0;
439         const char *type;
440         int i;
441         efi_status_t ret;
442
443         ret = EFI_CALL(BS->get_memory_map(&map_size, memmap, NULL, NULL, NULL));
444         if (ret == EFI_BUFFER_TOO_SMALL) {
445                 map_size += sizeof(struct efi_mem_desc); /* for my own */
446                 ret = EFI_CALL(BS->allocate_pool(EFI_LOADER_DATA,
447                                                  map_size, (void *)&memmap));
448                 if (ret != EFI_SUCCESS)
449                         return CMD_RET_FAILURE;
450                 ret = EFI_CALL(BS->get_memory_map(&map_size, memmap,
451                                                   NULL, NULL, NULL));
452         }
453         if (ret != EFI_SUCCESS) {
454                 EFI_CALL(BS->free_pool(memmap));
455                 return CMD_RET_FAILURE;
456         }
457
458         printf("Type             Start%.*s End%.*s Attributes\n",
459                EFI_PHYS_ADDR_WIDTH - 5, spc, EFI_PHYS_ADDR_WIDTH - 3, spc);
460         printf("================ %.*s %.*s ==========\n",
461                EFI_PHYS_ADDR_WIDTH, sep, EFI_PHYS_ADDR_WIDTH, sep);
462         for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) {
463                 if (map->type < EFI_MAX_MEMORY_TYPE)
464                         type = efi_mem_type_string[map->type];
465                 else
466                         type = "(unknown)";
467
468                 printf("%-16s %.*llx-%.*llx", type,
469                        EFI_PHYS_ADDR_WIDTH,
470                        map->physical_start,
471                        EFI_PHYS_ADDR_WIDTH,
472                        map->physical_start + map->num_pages * EFI_PAGE_SIZE);
473
474                 print_memory_attributes(map->attribute);
475                 putc('\n');
476         }
477
478         EFI_CALL(BS->free_pool(memmap));
479
480         return CMD_RET_SUCCESS;
481 }
482
483 /**
484  * do_efi_boot_add() - set UEFI load option
485  *
486  * @cmdtp:      Command table
487  * @flag:       Command flag
488  * @argc:       Number of arguments
489  * @argv:       Argument array
490  * Return:      CMD_RET_SUCCESS on success,
491  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
492  *
493  * Implement efidebug "boot add" sub-command. Create or change UEFI load option.
494  *
495  *     efidebug boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
496  */
497 static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag,
498                            int argc, char * const argv[])
499 {
500         int id;
501         char *endp;
502         char var_name[9];
503         u16 var_name16[9], *p;
504         efi_guid_t guid;
505         size_t label_len, label_len16;
506         u16 *label;
507         struct efi_device_path *device_path = NULL, *file_path = NULL;
508         struct efi_load_option lo;
509         void *data = NULL;
510         efi_uintn_t size;
511         efi_status_t ret;
512         int r = CMD_RET_SUCCESS;
513
514         if (argc < 6 || argc > 7)
515                 return CMD_RET_USAGE;
516
517         id = (int)simple_strtoul(argv[1], &endp, 16);
518         if (*endp != '\0' || id > 0xffff)
519                 return CMD_RET_USAGE;
520
521         sprintf(var_name, "Boot%04X", id);
522         p = var_name16;
523         utf8_utf16_strncpy(&p, var_name, 9);
524
525         guid = efi_global_variable_guid;
526
527         /* attributes */
528         lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */
529
530         /* label */
531         label_len = strlen(argv[2]);
532         label_len16 = utf8_utf16_strnlen(argv[2], label_len);
533         label = malloc((label_len16 + 1) * sizeof(u16));
534         if (!label)
535                 return CMD_RET_FAILURE;
536         lo.label = label; /* label will be changed below */
537         utf8_utf16_strncpy(&label, argv[2], label_len);
538
539         /* file path */
540         ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path,
541                                &file_path);
542         if (ret != EFI_SUCCESS) {
543                 printf("Cannot create device path for \"%s %s\"\n",
544                        argv[3], argv[4]);
545                 r = CMD_RET_FAILURE;
546                 goto out;
547         }
548         lo.file_path = file_path;
549         lo.file_path_length = efi_dp_size(file_path)
550                                 + sizeof(struct efi_device_path); /* for END */
551
552         /* optional data */
553         if (argc < 6)
554                 lo.optional_data = NULL;
555         else
556                 lo.optional_data = (const u8 *)argv[6];
557
558         size = efi_serialize_load_option(&lo, (u8 **)&data);
559         if (!size) {
560                 r = CMD_RET_FAILURE;
561                 goto out;
562         }
563
564         ret = EFI_CALL(RT->set_variable(var_name16, &guid,
565                                         EFI_VARIABLE_NON_VOLATILE |
566                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
567                                         EFI_VARIABLE_RUNTIME_ACCESS,
568                                         size, data));
569         if (ret != EFI_SUCCESS) {
570                 printf("Cannot set %ls\n", var_name16);
571                 r = CMD_RET_FAILURE;
572         }
573 out:
574         free(data);
575         efi_free_pool(device_path);
576         efi_free_pool(file_path);
577         free(lo.label);
578
579         return r;
580 }
581
582 /**
583  * do_efi_boot_rm() - delete UEFI load options
584  *
585  * @cmdtp:      Command table
586  * @flag:       Command flag
587  * @argc:       Number of arguments
588  * @argv:       Argument array
589  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
590  *
591  * Implement efidebug "boot rm" sub-command.
592  * Delete UEFI load options.
593  *
594  *     efidebug boot rm <id> ...
595  */
596 static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag,
597                           int argc, char * const argv[])
598 {
599         efi_guid_t guid;
600         int id, i;
601         char *endp;
602         char var_name[9];
603         u16 var_name16[9];
604         efi_status_t ret;
605
606         if (argc == 1)
607                 return CMD_RET_USAGE;
608
609         guid = efi_global_variable_guid;
610         for (i = 1; i < argc; i++, argv++) {
611                 id = (int)simple_strtoul(argv[1], &endp, 16);
612                 if (*endp != '\0' || id > 0xffff)
613                         return CMD_RET_FAILURE;
614
615                 sprintf(var_name, "Boot%04X", id);
616                 utf8_utf16_strncpy((u16 **)&var_name16, var_name, 9);
617
618                 ret = EFI_CALL(RT->set_variable(var_name16, &guid, 0, 0, NULL));
619                 if (ret) {
620                         printf("Cannot remove Boot%04X", id);
621                         return CMD_RET_FAILURE;
622                 }
623         }
624
625         return CMD_RET_SUCCESS;
626 }
627
628 /**
629  * show_efi_boot_opt_data() - dump UEFI load option
630  *
631  * @id:         load option number
632  * @data:       value of UEFI load option variable
633  * @size:       size of the boot option
634  *
635  * Decode the value of UEFI load option variable and print information.
636  */
637 static void show_efi_boot_opt_data(int id, void *data, size_t size)
638 {
639         struct efi_load_option lo;
640         char *label, *p;
641         size_t label_len16, label_len;
642         u16 *dp_str;
643
644         efi_deserialize_load_option(&lo, data);
645
646         label_len16 = u16_strlen(lo.label);
647         label_len = utf16_utf8_strnlen(lo.label, label_len16);
648         label = malloc(label_len + 1);
649         if (!label)
650                 return;
651         p = label;
652         utf16_utf8_strncpy(&p, lo.label, label_len16);
653
654         printf("Boot%04X:\n", id);
655         printf("  attributes: %c%c%c (0x%08x)\n",
656                /* ACTIVE */
657                lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-',
658                /* FORCE RECONNECT */
659                lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-',
660                /* HIDDEN */
661                lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-',
662                lo.attributes);
663         printf("  label: %s\n", label);
664
665         dp_str = efi_dp_str(lo.file_path);
666         printf("  file_path: %ls\n", dp_str);
667         efi_free_pool(dp_str);
668
669         printf("  data:\n");
670         print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
671                        lo.optional_data, size + (u8 *)data -
672                        (u8 *)lo.optional_data, true);
673         free(label);
674 }
675
676 /**
677  * show_efi_boot_opt() - dump UEFI load option
678  *
679  * @id:         Load option number
680  *
681  * Dump information defined by UEFI load option.
682  */
683 static void show_efi_boot_opt(int id)
684 {
685         char var_name[9];
686         u16 var_name16[9], *p;
687         efi_guid_t guid;
688         void *data = NULL;
689         efi_uintn_t size;
690         efi_status_t ret;
691
692         sprintf(var_name, "Boot%04X", id);
693         p = var_name16;
694         utf8_utf16_strncpy(&p, var_name, 9);
695         guid = efi_global_variable_guid;
696
697         size = 0;
698         ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, NULL));
699         if (ret == EFI_BUFFER_TOO_SMALL) {
700                 data = malloc(size);
701                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
702                                                 data));
703         }
704         if (ret == EFI_SUCCESS)
705                 show_efi_boot_opt_data(id, data, size);
706         else if (ret == EFI_NOT_FOUND)
707                 printf("Boot%04X: not found\n", id);
708
709         free(data);
710 }
711
712 static int u16_tohex(u16 c)
713 {
714         if (c >= '0' && c <= '9')
715                 return c - '0';
716         if (c >= 'A' && c <= 'F')
717                 return c - 'A' + 10;
718
719         /* not hexadecimal */
720         return -1;
721 }
722
723 /**
724  * show_efi_boot_dump() - dump all UEFI load options
725  *
726  * @cmdtp:      Command table
727  * @flag:       Command flag
728  * @argc:       Number of arguments
729  * @argv:       Argument array
730  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
731  *
732  * Implement efidebug "boot dump" sub-command.
733  * Dump information of all UEFI load options defined.
734  *
735  *     efidebug boot dump
736  */
737 static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag,
738                             int argc, char * const argv[])
739 {
740         u16 *var_name16, *p;
741         efi_uintn_t buf_size, size;
742         efi_guid_t guid;
743         int id, i, digit;
744         efi_status_t ret;
745
746         if (argc > 1)
747                 return CMD_RET_USAGE;
748
749         buf_size = 128;
750         var_name16 = malloc(buf_size);
751         if (!var_name16)
752                 return CMD_RET_FAILURE;
753
754         var_name16[0] = 0;
755         for (;;) {
756                 size = buf_size;
757                 ret = EFI_CALL(efi_get_next_variable_name(&size, var_name16,
758                                                           &guid));
759                 if (ret == EFI_NOT_FOUND)
760                         break;
761                 if (ret == EFI_BUFFER_TOO_SMALL) {
762                         buf_size = size;
763                         p = realloc(var_name16, buf_size);
764                         if (!p) {
765                                 free(var_name16);
766                                 return CMD_RET_FAILURE;
767                         }
768                         var_name16 = p;
769                         ret = EFI_CALL(efi_get_next_variable_name(&size,
770                                                                   var_name16,
771                                                                   &guid));
772                 }
773                 if (ret != EFI_SUCCESS) {
774                         free(var_name16);
775                         return CMD_RET_FAILURE;
776                 }
777
778                 if (memcmp(var_name16, L"Boot", 8))
779                         continue;
780
781                 for (id = 0, i = 0; i < 4; i++) {
782                         digit = u16_tohex(var_name16[4 + i]);
783                         if (digit < 0)
784                                 break;
785                         id = (id << 4) + digit;
786                 }
787                 if (i == 4 && !var_name16[8])
788                         show_efi_boot_opt(id);
789         }
790
791         free(var_name16);
792
793         return CMD_RET_SUCCESS;
794 }
795
796 /**
797  * show_efi_boot_order() - show order of UEFI load options
798  *
799  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
800  *
801  * Show order of UEFI load options defined by BootOrder variable.
802  */
803 static int show_efi_boot_order(void)
804 {
805         efi_guid_t guid;
806         u16 *bootorder = NULL;
807         efi_uintn_t size;
808         int num, i;
809         char var_name[9];
810         u16 var_name16[9], *p16;
811         void *data;
812         struct efi_load_option lo;
813         char *label, *p;
814         size_t label_len16, label_len;
815         efi_status_t ret;
816
817         guid = efi_global_variable_guid;
818         size = 0;
819         ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL, &size,
820                                         NULL));
821         if (ret == EFI_BUFFER_TOO_SMALL) {
822                 bootorder = malloc(size);
823                 ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL,
824                                                 &size, bootorder));
825         }
826         if (ret == EFI_NOT_FOUND) {
827                 printf("BootOrder not defined\n");
828                 ret = CMD_RET_SUCCESS;
829                 goto out;
830         } else if (ret != EFI_SUCCESS) {
831                 ret = CMD_RET_FAILURE;
832                 goto out;
833         }
834
835         num = size / sizeof(u16);
836         for (i = 0; i < num; i++) {
837                 sprintf(var_name, "Boot%04X", bootorder[i]);
838                 p16 = var_name16;
839                 utf8_utf16_strncpy(&p16, var_name, 9);
840
841                 size = 0;
842                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
843                                                 NULL));
844                 if (ret != EFI_BUFFER_TOO_SMALL) {
845                         printf("%2d: Boot%04X: (not defined)\n",
846                                i + 1, bootorder[i]);
847                         continue;
848                 }
849
850                 data = malloc(size);
851                 if (!data) {
852                         ret = CMD_RET_FAILURE;
853                         goto out;
854                 }
855                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
856                                                 data));
857                 if (ret != EFI_SUCCESS) {
858                         free(data);
859                         ret = CMD_RET_FAILURE;
860                         goto out;
861                 }
862
863                 efi_deserialize_load_option(&lo, data);
864
865                 label_len16 = u16_strlen(lo.label);
866                 label_len = utf16_utf8_strnlen(lo.label, label_len16);
867                 label = malloc(label_len + 1);
868                 if (!label) {
869                         free(data);
870                         ret = CMD_RET_FAILURE;
871                         goto out;
872                 }
873                 p = label;
874                 utf16_utf8_strncpy(&p, lo.label, label_len16);
875                 printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label);
876                 free(label);
877
878                 free(data);
879         }
880 out:
881         free(bootorder);
882
883         return ret;
884 }
885
886 /**
887  * do_efi_boot_next() - manage UEFI BootNext variable
888  *
889  * @cmdtp:      Command table
890  * @flag:       Command flag
891  * @argc:       Number of arguments
892  * @argv:       Argument array
893  * Return:      CMD_RET_SUCCESS on success,
894  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
895  *
896  * Implement efidebug "boot next" sub-command.
897  * Set BootNext variable.
898  *
899  *     efidebug boot next <id>
900  */
901 static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag,
902                             int argc, char * const argv[])
903 {
904         u16 bootnext;
905         efi_uintn_t size;
906         char *endp;
907         efi_guid_t guid;
908         efi_status_t ret;
909         int r = CMD_RET_SUCCESS;
910
911         if (argc != 2)
912                 return CMD_RET_USAGE;
913
914         bootnext = (u16)simple_strtoul(argv[1], &endp, 16);
915         if (*endp != '\0' || bootnext > 0xffff) {
916                 printf("invalid value: %s\n", argv[1]);
917                 r = CMD_RET_FAILURE;
918                 goto out;
919         }
920
921         guid = efi_global_variable_guid;
922         size = sizeof(u16);
923         ret = EFI_CALL(RT->set_variable(L"BootNext", &guid,
924                                         EFI_VARIABLE_NON_VOLATILE |
925                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
926                                         EFI_VARIABLE_RUNTIME_ACCESS,
927                                         size, &bootnext));
928         if (ret != EFI_SUCCESS) {
929                 printf("Cannot set BootNext\n");
930                 r = CMD_RET_FAILURE;
931         }
932 out:
933         return r;
934 }
935
936 /**
937  * do_efi_boot_order() - manage UEFI BootOrder variable
938  *
939  * @cmdtp:      Command table
940  * @flag:       Command flag
941  * @argc:       Number of arguments
942  * @argv:       Argument array
943  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
944  *
945  * Implement efidebug "boot order" sub-command.
946  * Show order of UEFI load options, or change it in BootOrder variable.
947  *
948  *     efidebug boot order [<id> ...]
949  */
950 static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag,
951                              int argc, char * const argv[])
952 {
953         u16 *bootorder = NULL;
954         efi_uintn_t size;
955         int id, i;
956         char *endp;
957         efi_guid_t guid;
958         efi_status_t ret;
959         int r = CMD_RET_SUCCESS;
960
961         if (argc == 1)
962                 return show_efi_boot_order();
963
964         argc--;
965         argv++;
966
967         size = argc * sizeof(u16);
968         bootorder = malloc(size);
969         if (!bootorder)
970                 return CMD_RET_FAILURE;
971
972         for (i = 0; i < argc; i++) {
973                 id = (int)simple_strtoul(argv[i], &endp, 16);
974                 if (*endp != '\0' || id > 0xffff) {
975                         printf("invalid value: %s\n", argv[i]);
976                         r = CMD_RET_FAILURE;
977                         goto out;
978                 }
979
980                 bootorder[i] = (u16)id;
981         }
982
983         guid = efi_global_variable_guid;
984         ret = EFI_CALL(RT->set_variable(L"BootOrder", &guid,
985                                         EFI_VARIABLE_NON_VOLATILE |
986                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
987                                         EFI_VARIABLE_RUNTIME_ACCESS,
988                                         size, bootorder));
989         if (ret != EFI_SUCCESS) {
990                 printf("Cannot set BootOrder\n");
991                 r = CMD_RET_FAILURE;
992         }
993 out:
994         free(bootorder);
995
996         return r;
997 }
998
999 static cmd_tbl_t cmd_efidebug_boot_sub[] = {
1000         U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""),
1001         U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""),
1002         U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""),
1003         U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""),
1004         U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order,
1005                          "", ""),
1006 };
1007
1008 /**
1009  * do_efi_boot_opt() - manage UEFI load options
1010  *
1011  * @cmdtp:      Command table
1012  * @flag:       Command flag
1013  * @argc:       Number of arguments
1014  * @argv:       Argument array
1015  * Return:      CMD_RET_SUCCESS on success,
1016  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1017  *
1018  * Implement efidebug "boot" sub-command.
1019  */
1020 static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag,
1021                            int argc, char * const argv[])
1022 {
1023         cmd_tbl_t *cp;
1024
1025         if (argc < 2)
1026                 return CMD_RET_USAGE;
1027
1028         argc--; argv++;
1029
1030         cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub,
1031                           ARRAY_SIZE(cmd_efidebug_boot_sub));
1032         if (!cp)
1033                 return CMD_RET_USAGE;
1034
1035         return cp->cmd(cmdtp, flag, argc, argv);
1036 }
1037
1038 static cmd_tbl_t cmd_efidebug_sub[] = {
1039         U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
1040         U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices,
1041                          "", ""),
1042         U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers,
1043                          "", ""),
1044         U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles,
1045                          "", ""),
1046         U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images,
1047                          "", ""),
1048         U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap,
1049                          "", ""),
1050 };
1051
1052 /**
1053  * do_efidebug() - display and configure UEFI environment
1054  *
1055  * @cmdtp:      Command table
1056  * @flag:       Command flag
1057  * @argc:       Number of arguments
1058  * @argv:       Argument array
1059  * Return:      CMD_RET_SUCCESS on success,
1060  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1061  *
1062  * Implement efidebug command which allows us to display and
1063  * configure UEFI environment.
1064  */
1065 static int do_efidebug(cmd_tbl_t *cmdtp, int flag,
1066                        int argc, char * const argv[])
1067 {
1068         cmd_tbl_t *cp;
1069         efi_status_t r;
1070
1071         if (argc < 2)
1072                 return CMD_RET_USAGE;
1073
1074         argc--; argv++;
1075
1076         /* Initialize UEFI drivers */
1077         r = efi_init_obj_list();
1078         if (r != EFI_SUCCESS) {
1079                 printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
1080                        r & ~EFI_ERROR_MASK);
1081                 return CMD_RET_FAILURE;
1082         }
1083
1084         cp = find_cmd_tbl(argv[0], cmd_efidebug_sub,
1085                           ARRAY_SIZE(cmd_efidebug_sub));
1086         if (!cp)
1087                 return CMD_RET_USAGE;
1088
1089         return cp->cmd(cmdtp, flag, argc, argv);
1090 }
1091
1092 #ifdef CONFIG_SYS_LONGHELP
1093 static char efidebug_help_text[] =
1094         "  - UEFI Shell-like interface to configure UEFI environment\n"
1095         "\n"
1096         "efidebug boot add <bootid> <label> <interface> <devnum>[:<part>] <file path> [<load options>]\n"
1097         "  - set UEFI BootXXXX variable\n"
1098         "    <load options> will be passed to UEFI application\n"
1099         "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
1100         "  - delete UEFI BootXXXX variables\n"
1101         "efidebug boot dump\n"
1102         "  - dump all UEFI BootXXXX variables\n"
1103         "efidebug boot next <bootid>\n"
1104         "  - set UEFI BootNext variable\n"
1105         "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
1106         "  - set/show UEFI boot order\n"
1107         "\n"
1108         "efidebug devices\n"
1109         "  - show uefi devices\n"
1110         "efidebug drivers\n"
1111         "  - show uefi drivers\n"
1112         "efidebug dh\n"
1113         "  - show uefi handles\n"
1114         "efidebug images\n"
1115         "  - show loaded images\n"
1116         "efidebug memmap\n"
1117         "  - show uefi memory map\n";
1118 #endif
1119
1120 U_BOOT_CMD(
1121         efidebug, 10, 0, do_efidebug,
1122         "Configure UEFI environment",
1123         efidebug_help_text
1124 );