Merge tag 'efi-2020-04-rc4' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi
[oweals/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         /* Configuration table GUIDs */
255         {
256                 "ACPI table",
257                 EFI_ACPI_TABLE_GUID,
258         },
259         {
260                 "device tree",
261                 EFI_FDT_GUID,
262         },
263         {
264                 "SMBIOS table",
265                 SMBIOS_TABLE_GUID,
266         },
267         {
268                 "Runtime properties",
269                 EFI_RT_PROPERTIES_TABLE_GUID,
270         },
271 };
272
273 /**
274  * get_guid_text - get string of GUID
275  *
276  * Return description of GUID.
277  *
278  * @guid:       GUID
279  * Return:      description of GUID or NULL
280  */
281 static const char *get_guid_text(const void *guid)
282 {
283         int i;
284
285         for (i = 0; i < ARRAY_SIZE(guid_list); i++) {
286                 /*
287                  * As guidcmp uses memcmp() we can safely accept unaligned
288                  * GUIDs.
289                  */
290                 if (!guidcmp(&guid_list[i].guid, guid))
291                         return guid_list[i].text;
292         }
293
294         return NULL;
295 }
296
297 /**
298  * do_efi_show_handles() - show UEFI handles
299  *
300  * @cmdtp:      Command table
301  * @flag:       Command flag
302  * @argc:       Number of arguments
303  * @argv:       Argument array
304  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
305  *
306  * Implement efidebug "dh" sub-command.
307  * Show all UEFI handles and their information, currently all protocols
308  * added to handle.
309  */
310 static int do_efi_show_handles(cmd_tbl_t *cmdtp, int flag,
311                                int argc, char * const argv[])
312 {
313         efi_handle_t *handles;
314         efi_guid_t **guid;
315         efi_uintn_t num, count, i, j;
316         const char *guid_text;
317         efi_status_t ret;
318
319         ret = EFI_CALL(BS->locate_handle_buffer(ALL_HANDLES, NULL, NULL,
320                                                 &num, &handles));
321         if (ret != EFI_SUCCESS)
322                 return CMD_RET_FAILURE;
323
324         if (!num)
325                 return CMD_RET_SUCCESS;
326
327         printf("Handle%.*s Protocols\n", EFI_HANDLE_WIDTH - 6, spc);
328         printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
329         for (i = 0; i < num; i++) {
330                 printf("%p", handles[i]);
331                 ret = EFI_CALL(BS->protocols_per_handle(handles[i], &guid,
332                                                         &count));
333                 if (ret || !count) {
334                         putc('\n');
335                         continue;
336                 }
337
338                 for (j = 0; j < count; j++) {
339                         if (j)
340                                 printf(", ");
341                         else
342                                 putc(' ');
343
344                         guid_text = get_guid_text(guid[j]);
345                         if (guid_text)
346                                 puts(guid_text);
347                         else
348                                 printf("%pUl", guid[j]);
349                 }
350                 putc('\n');
351         }
352
353         EFI_CALL(BS->free_pool(handles));
354
355         return CMD_RET_SUCCESS;
356 }
357
358 /**
359  * do_efi_show_images() - show UEFI images
360  *
361  * @cmdtp:      Command table
362  * @flag:       Command flag
363  * @argc:       Number of arguments
364  * @argv:       Argument array
365  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
366  *
367  * Implement efidebug "images" sub-command.
368  * Show all UEFI loaded images and their information.
369  */
370 static int do_efi_show_images(cmd_tbl_t *cmdtp, int flag,
371                               int argc, char * const argv[])
372 {
373         efi_print_image_infos(NULL);
374
375         return CMD_RET_SUCCESS;
376 }
377
378 static const char * const efi_mem_type_string[] = {
379         [EFI_RESERVED_MEMORY_TYPE] = "RESERVED",
380         [EFI_LOADER_CODE] = "LOADER CODE",
381         [EFI_LOADER_DATA] = "LOADER DATA",
382         [EFI_BOOT_SERVICES_CODE] = "BOOT CODE",
383         [EFI_BOOT_SERVICES_DATA] = "BOOT DATA",
384         [EFI_RUNTIME_SERVICES_CODE] = "RUNTIME CODE",
385         [EFI_RUNTIME_SERVICES_DATA] = "RUNTIME DATA",
386         [EFI_CONVENTIONAL_MEMORY] = "CONVENTIONAL",
387         [EFI_UNUSABLE_MEMORY] = "UNUSABLE MEM",
388         [EFI_ACPI_RECLAIM_MEMORY] = "ACPI RECLAIM MEM",
389         [EFI_ACPI_MEMORY_NVS] = "ACPI NVS",
390         [EFI_MMAP_IO] = "IO",
391         [EFI_MMAP_IO_PORT] = "IO PORT",
392         [EFI_PAL_CODE] = "PAL",
393 };
394
395 static const struct efi_mem_attrs {
396         const u64 bit;
397         const char *text;
398 } efi_mem_attrs[] = {
399         {EFI_MEMORY_UC, "UC"},
400         {EFI_MEMORY_UC, "UC"},
401         {EFI_MEMORY_WC, "WC"},
402         {EFI_MEMORY_WT, "WT"},
403         {EFI_MEMORY_WB, "WB"},
404         {EFI_MEMORY_UCE, "UCE"},
405         {EFI_MEMORY_WP, "WP"},
406         {EFI_MEMORY_RP, "RP"},
407         {EFI_MEMORY_XP, "WP"},
408         {EFI_MEMORY_NV, "NV"},
409         {EFI_MEMORY_MORE_RELIABLE, "REL"},
410         {EFI_MEMORY_RO, "RO"},
411         {EFI_MEMORY_RUNTIME, "RT"},
412 };
413
414 /**
415  * print_memory_attributes() - print memory map attributes
416  *
417  * @attributes: Attribute value
418  *
419  * Print memory map attributes
420  */
421 static void print_memory_attributes(u64 attributes)
422 {
423         int sep, i;
424
425         for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++)
426                 if (attributes & efi_mem_attrs[i].bit) {
427                         if (sep) {
428                                 putc('|');
429                         } else {
430                                 putc(' ');
431                                 sep = 1;
432                         }
433                         puts(efi_mem_attrs[i].text);
434                 }
435 }
436
437 #define EFI_PHYS_ADDR_WIDTH (int)(sizeof(efi_physical_addr_t) * 2)
438
439 /**
440  * do_efi_show_memmap() - show UEFI memory map
441  *
442  * @cmdtp:      Command table
443  * @flag:       Command flag
444  * @argc:       Number of arguments
445  * @argv:       Argument array
446  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
447  *
448  * Implement efidebug "memmap" sub-command.
449  * Show UEFI memory map.
450  */
451 static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag,
452                               int argc, char * const argv[])
453 {
454         struct efi_mem_desc *memmap = NULL, *map;
455         efi_uintn_t map_size = 0;
456         const char *type;
457         int i;
458         efi_status_t ret;
459
460         ret = EFI_CALL(BS->get_memory_map(&map_size, memmap, NULL, NULL, NULL));
461         if (ret == EFI_BUFFER_TOO_SMALL) {
462                 map_size += sizeof(struct efi_mem_desc); /* for my own */
463                 ret = EFI_CALL(BS->allocate_pool(EFI_LOADER_DATA,
464                                                  map_size, (void *)&memmap));
465                 if (ret != EFI_SUCCESS)
466                         return CMD_RET_FAILURE;
467                 ret = EFI_CALL(BS->get_memory_map(&map_size, memmap,
468                                                   NULL, NULL, NULL));
469         }
470         if (ret != EFI_SUCCESS) {
471                 EFI_CALL(BS->free_pool(memmap));
472                 return CMD_RET_FAILURE;
473         }
474
475         printf("Type             Start%.*s End%.*s Attributes\n",
476                EFI_PHYS_ADDR_WIDTH - 5, spc, EFI_PHYS_ADDR_WIDTH - 3, spc);
477         printf("================ %.*s %.*s ==========\n",
478                EFI_PHYS_ADDR_WIDTH, sep, EFI_PHYS_ADDR_WIDTH, sep);
479         for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) {
480                 if (map->type < EFI_MAX_MEMORY_TYPE)
481                         type = efi_mem_type_string[map->type];
482                 else
483                         type = "(unknown)";
484
485                 printf("%-16s %.*llx-%.*llx", type,
486                        EFI_PHYS_ADDR_WIDTH,
487                        map->physical_start,
488                        EFI_PHYS_ADDR_WIDTH,
489                        map->physical_start + map->num_pages * EFI_PAGE_SIZE);
490
491                 print_memory_attributes(map->attribute);
492                 putc('\n');
493         }
494
495         EFI_CALL(BS->free_pool(memmap));
496
497         return CMD_RET_SUCCESS;
498 }
499
500 /**
501  * do_efi_show_tables() - show UEFI configuration tables
502  *
503  * @cmdtp:      Command table
504  * @flag:       Command flag
505  * @argc:       Number of arguments
506  * @argv:       Argument array
507  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
508  *
509  * Implement efidebug "tables" sub-command.
510  * Show UEFI configuration tables.
511  */
512 static int do_efi_show_tables(cmd_tbl_t *cmdtp, int flag,
513                               int argc, char * const argv[])
514 {
515         efi_uintn_t i;
516         const char *guid_str;
517
518         for (i = 0; i < systab.nr_tables; ++i) {
519                 guid_str = get_guid_text(&systab.tables[i].guid);
520                 if (!guid_str)
521                         guid_str = "";
522                 printf("%pUl %s\n", &systab.tables[i].guid, guid_str);
523         }
524
525         return CMD_RET_SUCCESS;
526 }
527
528 /**
529  * do_efi_boot_add() - set UEFI load option
530  *
531  * @cmdtp:      Command table
532  * @flag:       Command flag
533  * @argc:       Number of arguments
534  * @argv:       Argument array
535  * Return:      CMD_RET_SUCCESS on success,
536  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
537  *
538  * Implement efidebug "boot add" sub-command. Create or change UEFI load option.
539  *
540  *     efidebug boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
541  */
542 static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag,
543                            int argc, char * const argv[])
544 {
545         int id;
546         char *endp;
547         char var_name[9];
548         u16 var_name16[9], *p;
549         efi_guid_t guid;
550         size_t label_len, label_len16;
551         u16 *label;
552         struct efi_device_path *device_path = NULL, *file_path = NULL;
553         struct efi_load_option lo;
554         void *data = NULL;
555         efi_uintn_t size;
556         efi_status_t ret;
557         int r = CMD_RET_SUCCESS;
558
559         if (argc < 6 || argc > 7)
560                 return CMD_RET_USAGE;
561
562         id = (int)simple_strtoul(argv[1], &endp, 16);
563         if (*endp != '\0' || id > 0xffff)
564                 return CMD_RET_USAGE;
565
566         sprintf(var_name, "Boot%04X", id);
567         p = var_name16;
568         utf8_utf16_strncpy(&p, var_name, 9);
569
570         guid = efi_global_variable_guid;
571
572         /* attributes */
573         lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */
574
575         /* label */
576         label_len = strlen(argv[2]);
577         label_len16 = utf8_utf16_strnlen(argv[2], label_len);
578         label = malloc((label_len16 + 1) * sizeof(u16));
579         if (!label)
580                 return CMD_RET_FAILURE;
581         lo.label = label; /* label will be changed below */
582         utf8_utf16_strncpy(&label, argv[2], label_len);
583
584         /* file path */
585         ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path,
586                                &file_path);
587         if (ret != EFI_SUCCESS) {
588                 printf("Cannot create device path for \"%s %s\"\n",
589                        argv[3], argv[4]);
590                 r = CMD_RET_FAILURE;
591                 goto out;
592         }
593         lo.file_path = file_path;
594         lo.file_path_length = efi_dp_size(file_path)
595                                 + sizeof(struct efi_device_path); /* for END */
596
597         /* optional data */
598         if (argc < 6)
599                 lo.optional_data = NULL;
600         else
601                 lo.optional_data = (const u8 *)argv[6];
602
603         size = efi_serialize_load_option(&lo, (u8 **)&data);
604         if (!size) {
605                 r = CMD_RET_FAILURE;
606                 goto out;
607         }
608
609         ret = EFI_CALL(RT->set_variable(var_name16, &guid,
610                                         EFI_VARIABLE_NON_VOLATILE |
611                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
612                                         EFI_VARIABLE_RUNTIME_ACCESS,
613                                         size, data));
614         if (ret != EFI_SUCCESS) {
615                 printf("Cannot set %ls\n", var_name16);
616                 r = CMD_RET_FAILURE;
617         }
618 out:
619         free(data);
620         efi_free_pool(device_path);
621         efi_free_pool(file_path);
622         free(lo.label);
623
624         return r;
625 }
626
627 /**
628  * do_efi_boot_rm() - delete UEFI load options
629  *
630  * @cmdtp:      Command table
631  * @flag:       Command flag
632  * @argc:       Number of arguments
633  * @argv:       Argument array
634  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
635  *
636  * Implement efidebug "boot rm" sub-command.
637  * Delete UEFI load options.
638  *
639  *     efidebug boot rm <id> ...
640  */
641 static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag,
642                           int argc, char * const argv[])
643 {
644         efi_guid_t guid;
645         int id, i;
646         char *endp;
647         char var_name[9];
648         u16 var_name16[9];
649         efi_status_t ret;
650
651         if (argc == 1)
652                 return CMD_RET_USAGE;
653
654         guid = efi_global_variable_guid;
655         for (i = 1; i < argc; i++, argv++) {
656                 id = (int)simple_strtoul(argv[1], &endp, 16);
657                 if (*endp != '\0' || id > 0xffff)
658                         return CMD_RET_FAILURE;
659
660                 sprintf(var_name, "Boot%04X", id);
661                 utf8_utf16_strncpy((u16 **)&var_name16, var_name, 9);
662
663                 ret = EFI_CALL(RT->set_variable(var_name16, &guid, 0, 0, NULL));
664                 if (ret) {
665                         printf("Cannot remove Boot%04X", id);
666                         return CMD_RET_FAILURE;
667                 }
668         }
669
670         return CMD_RET_SUCCESS;
671 }
672
673 /**
674  * show_efi_boot_opt_data() - dump UEFI load option
675  *
676  * @id:         load option number
677  * @data:       value of UEFI load option variable
678  * @size:       size of the boot option
679  *
680  * Decode the value of UEFI load option variable and print information.
681  */
682 static void show_efi_boot_opt_data(int id, void *data, size_t size)
683 {
684         struct efi_load_option lo;
685         char *label, *p;
686         size_t label_len16, label_len;
687         u16 *dp_str;
688
689         efi_deserialize_load_option(&lo, data);
690
691         label_len16 = u16_strlen(lo.label);
692         label_len = utf16_utf8_strnlen(lo.label, label_len16);
693         label = malloc(label_len + 1);
694         if (!label)
695                 return;
696         p = label;
697         utf16_utf8_strncpy(&p, lo.label, label_len16);
698
699         printf("Boot%04X:\n", id);
700         printf("  attributes: %c%c%c (0x%08x)\n",
701                /* ACTIVE */
702                lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-',
703                /* FORCE RECONNECT */
704                lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-',
705                /* HIDDEN */
706                lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-',
707                lo.attributes);
708         printf("  label: %s\n", label);
709
710         dp_str = efi_dp_str(lo.file_path);
711         printf("  file_path: %ls\n", dp_str);
712         efi_free_pool(dp_str);
713
714         printf("  data:\n");
715         print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
716                        lo.optional_data, size + (u8 *)data -
717                        (u8 *)lo.optional_data, true);
718         free(label);
719 }
720
721 /**
722  * show_efi_boot_opt() - dump UEFI load option
723  *
724  * @id:         Load option number
725  *
726  * Dump information defined by UEFI load option.
727  */
728 static void show_efi_boot_opt(int id)
729 {
730         char var_name[9];
731         u16 var_name16[9], *p;
732         efi_guid_t guid;
733         void *data = NULL;
734         efi_uintn_t size;
735         efi_status_t ret;
736
737         sprintf(var_name, "Boot%04X", id);
738         p = var_name16;
739         utf8_utf16_strncpy(&p, var_name, 9);
740         guid = efi_global_variable_guid;
741
742         size = 0;
743         ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, NULL));
744         if (ret == EFI_BUFFER_TOO_SMALL) {
745                 data = malloc(size);
746                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
747                                                 data));
748         }
749         if (ret == EFI_SUCCESS)
750                 show_efi_boot_opt_data(id, data, size);
751         else if (ret == EFI_NOT_FOUND)
752                 printf("Boot%04X: not found\n", id);
753
754         free(data);
755 }
756
757 static int u16_tohex(u16 c)
758 {
759         if (c >= '0' && c <= '9')
760                 return c - '0';
761         if (c >= 'A' && c <= 'F')
762                 return c - 'A' + 10;
763
764         /* not hexadecimal */
765         return -1;
766 }
767
768 /**
769  * show_efi_boot_dump() - dump all UEFI load options
770  *
771  * @cmdtp:      Command table
772  * @flag:       Command flag
773  * @argc:       Number of arguments
774  * @argv:       Argument array
775  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
776  *
777  * Implement efidebug "boot dump" sub-command.
778  * Dump information of all UEFI load options defined.
779  *
780  *     efidebug boot dump
781  */
782 static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag,
783                             int argc, char * const argv[])
784 {
785         u16 *var_name16, *p;
786         efi_uintn_t buf_size, size;
787         efi_guid_t guid;
788         int id, i, digit;
789         efi_status_t ret;
790
791         if (argc > 1)
792                 return CMD_RET_USAGE;
793
794         buf_size = 128;
795         var_name16 = malloc(buf_size);
796         if (!var_name16)
797                 return CMD_RET_FAILURE;
798
799         var_name16[0] = 0;
800         for (;;) {
801                 size = buf_size;
802                 ret = EFI_CALL(efi_get_next_variable_name(&size, var_name16,
803                                                           &guid));
804                 if (ret == EFI_NOT_FOUND)
805                         break;
806                 if (ret == EFI_BUFFER_TOO_SMALL) {
807                         buf_size = size;
808                         p = realloc(var_name16, buf_size);
809                         if (!p) {
810                                 free(var_name16);
811                                 return CMD_RET_FAILURE;
812                         }
813                         var_name16 = p;
814                         ret = EFI_CALL(efi_get_next_variable_name(&size,
815                                                                   var_name16,
816                                                                   &guid));
817                 }
818                 if (ret != EFI_SUCCESS) {
819                         free(var_name16);
820                         return CMD_RET_FAILURE;
821                 }
822
823                 if (memcmp(var_name16, L"Boot", 8))
824                         continue;
825
826                 for (id = 0, i = 0; i < 4; i++) {
827                         digit = u16_tohex(var_name16[4 + i]);
828                         if (digit < 0)
829                                 break;
830                         id = (id << 4) + digit;
831                 }
832                 if (i == 4 && !var_name16[8])
833                         show_efi_boot_opt(id);
834         }
835
836         free(var_name16);
837
838         return CMD_RET_SUCCESS;
839 }
840
841 /**
842  * show_efi_boot_order() - show order of UEFI load options
843  *
844  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
845  *
846  * Show order of UEFI load options defined by BootOrder variable.
847  */
848 static int show_efi_boot_order(void)
849 {
850         efi_guid_t guid;
851         u16 *bootorder = NULL;
852         efi_uintn_t size;
853         int num, i;
854         char var_name[9];
855         u16 var_name16[9], *p16;
856         void *data;
857         struct efi_load_option lo;
858         char *label, *p;
859         size_t label_len16, label_len;
860         efi_status_t ret;
861
862         guid = efi_global_variable_guid;
863         size = 0;
864         ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL, &size,
865                                         NULL));
866         if (ret == EFI_BUFFER_TOO_SMALL) {
867                 bootorder = malloc(size);
868                 ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL,
869                                                 &size, bootorder));
870         }
871         if (ret == EFI_NOT_FOUND) {
872                 printf("BootOrder not defined\n");
873                 ret = CMD_RET_SUCCESS;
874                 goto out;
875         } else if (ret != EFI_SUCCESS) {
876                 ret = CMD_RET_FAILURE;
877                 goto out;
878         }
879
880         num = size / sizeof(u16);
881         for (i = 0; i < num; i++) {
882                 sprintf(var_name, "Boot%04X", bootorder[i]);
883                 p16 = var_name16;
884                 utf8_utf16_strncpy(&p16, var_name, 9);
885
886                 size = 0;
887                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
888                                                 NULL));
889                 if (ret != EFI_BUFFER_TOO_SMALL) {
890                         printf("%2d: Boot%04X: (not defined)\n",
891                                i + 1, bootorder[i]);
892                         continue;
893                 }
894
895                 data = malloc(size);
896                 if (!data) {
897                         ret = CMD_RET_FAILURE;
898                         goto out;
899                 }
900                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
901                                                 data));
902                 if (ret != EFI_SUCCESS) {
903                         free(data);
904                         ret = CMD_RET_FAILURE;
905                         goto out;
906                 }
907
908                 efi_deserialize_load_option(&lo, data);
909
910                 label_len16 = u16_strlen(lo.label);
911                 label_len = utf16_utf8_strnlen(lo.label, label_len16);
912                 label = malloc(label_len + 1);
913                 if (!label) {
914                         free(data);
915                         ret = CMD_RET_FAILURE;
916                         goto out;
917                 }
918                 p = label;
919                 utf16_utf8_strncpy(&p, lo.label, label_len16);
920                 printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label);
921                 free(label);
922
923                 free(data);
924         }
925 out:
926         free(bootorder);
927
928         return ret;
929 }
930
931 /**
932  * do_efi_boot_next() - manage UEFI BootNext variable
933  *
934  * @cmdtp:      Command table
935  * @flag:       Command flag
936  * @argc:       Number of arguments
937  * @argv:       Argument array
938  * Return:      CMD_RET_SUCCESS on success,
939  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
940  *
941  * Implement efidebug "boot next" sub-command.
942  * Set BootNext variable.
943  *
944  *     efidebug boot next <id>
945  */
946 static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag,
947                             int argc, char * const argv[])
948 {
949         u16 bootnext;
950         efi_uintn_t size;
951         char *endp;
952         efi_guid_t guid;
953         efi_status_t ret;
954         int r = CMD_RET_SUCCESS;
955
956         if (argc != 2)
957                 return CMD_RET_USAGE;
958
959         bootnext = (u16)simple_strtoul(argv[1], &endp, 16);
960         if (*endp != '\0' || bootnext > 0xffff) {
961                 printf("invalid value: %s\n", argv[1]);
962                 r = CMD_RET_FAILURE;
963                 goto out;
964         }
965
966         guid = efi_global_variable_guid;
967         size = sizeof(u16);
968         ret = EFI_CALL(RT->set_variable(L"BootNext", &guid,
969                                         EFI_VARIABLE_NON_VOLATILE |
970                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
971                                         EFI_VARIABLE_RUNTIME_ACCESS,
972                                         size, &bootnext));
973         if (ret != EFI_SUCCESS) {
974                 printf("Cannot set BootNext\n");
975                 r = CMD_RET_FAILURE;
976         }
977 out:
978         return r;
979 }
980
981 /**
982  * do_efi_boot_order() - manage UEFI BootOrder variable
983  *
984  * @cmdtp:      Command table
985  * @flag:       Command flag
986  * @argc:       Number of arguments
987  * @argv:       Argument array
988  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
989  *
990  * Implement efidebug "boot order" sub-command.
991  * Show order of UEFI load options, or change it in BootOrder variable.
992  *
993  *     efidebug boot order [<id> ...]
994  */
995 static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag,
996                              int argc, char * const argv[])
997 {
998         u16 *bootorder = NULL;
999         efi_uintn_t size;
1000         int id, i;
1001         char *endp;
1002         efi_guid_t guid;
1003         efi_status_t ret;
1004         int r = CMD_RET_SUCCESS;
1005
1006         if (argc == 1)
1007                 return show_efi_boot_order();
1008
1009         argc--;
1010         argv++;
1011
1012         size = argc * sizeof(u16);
1013         bootorder = malloc(size);
1014         if (!bootorder)
1015                 return CMD_RET_FAILURE;
1016
1017         for (i = 0; i < argc; i++) {
1018                 id = (int)simple_strtoul(argv[i], &endp, 16);
1019                 if (*endp != '\0' || id > 0xffff) {
1020                         printf("invalid value: %s\n", argv[i]);
1021                         r = CMD_RET_FAILURE;
1022                         goto out;
1023                 }
1024
1025                 bootorder[i] = (u16)id;
1026         }
1027
1028         guid = efi_global_variable_guid;
1029         ret = EFI_CALL(RT->set_variable(L"BootOrder", &guid,
1030                                         EFI_VARIABLE_NON_VOLATILE |
1031                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
1032                                         EFI_VARIABLE_RUNTIME_ACCESS,
1033                                         size, bootorder));
1034         if (ret != EFI_SUCCESS) {
1035                 printf("Cannot set BootOrder\n");
1036                 r = CMD_RET_FAILURE;
1037         }
1038 out:
1039         free(bootorder);
1040
1041         return r;
1042 }
1043
1044 static cmd_tbl_t cmd_efidebug_boot_sub[] = {
1045         U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""),
1046         U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""),
1047         U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""),
1048         U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""),
1049         U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order,
1050                          "", ""),
1051 };
1052
1053 /**
1054  * do_efi_boot_opt() - manage UEFI load options
1055  *
1056  * @cmdtp:      Command table
1057  * @flag:       Command flag
1058  * @argc:       Number of arguments
1059  * @argv:       Argument array
1060  * Return:      CMD_RET_SUCCESS on success,
1061  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1062  *
1063  * Implement efidebug "boot" sub-command.
1064  */
1065 static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag,
1066                            int argc, char * const argv[])
1067 {
1068         cmd_tbl_t *cp;
1069
1070         if (argc < 2)
1071                 return CMD_RET_USAGE;
1072
1073         argc--; argv++;
1074
1075         cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub,
1076                           ARRAY_SIZE(cmd_efidebug_boot_sub));
1077         if (!cp)
1078                 return CMD_RET_USAGE;
1079
1080         return cp->cmd(cmdtp, flag, argc, argv);
1081 }
1082
1083 static cmd_tbl_t cmd_efidebug_sub[] = {
1084         U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
1085         U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices,
1086                          "", ""),
1087         U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers,
1088                          "", ""),
1089         U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles,
1090                          "", ""),
1091         U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images,
1092                          "", ""),
1093         U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap,
1094                          "", ""),
1095         U_BOOT_CMD_MKENT(tables, CONFIG_SYS_MAXARGS, 1, do_efi_show_tables,
1096                          "", ""),
1097 };
1098
1099 /**
1100  * do_efidebug() - display and configure UEFI environment
1101  *
1102  * @cmdtp:      Command table
1103  * @flag:       Command flag
1104  * @argc:       Number of arguments
1105  * @argv:       Argument array
1106  * Return:      CMD_RET_SUCCESS on success,
1107  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1108  *
1109  * Implement efidebug command which allows us to display and
1110  * configure UEFI environment.
1111  */
1112 static int do_efidebug(cmd_tbl_t *cmdtp, int flag,
1113                        int argc, char * const argv[])
1114 {
1115         cmd_tbl_t *cp;
1116         efi_status_t r;
1117
1118         if (argc < 2)
1119                 return CMD_RET_USAGE;
1120
1121         argc--; argv++;
1122
1123         /* Initialize UEFI drivers */
1124         r = efi_init_obj_list();
1125         if (r != EFI_SUCCESS) {
1126                 printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
1127                        r & ~EFI_ERROR_MASK);
1128                 return CMD_RET_FAILURE;
1129         }
1130
1131         cp = find_cmd_tbl(argv[0], cmd_efidebug_sub,
1132                           ARRAY_SIZE(cmd_efidebug_sub));
1133         if (!cp)
1134                 return CMD_RET_USAGE;
1135
1136         return cp->cmd(cmdtp, flag, argc, argv);
1137 }
1138
1139 #ifdef CONFIG_SYS_LONGHELP
1140 static char efidebug_help_text[] =
1141         "  - UEFI Shell-like interface to configure UEFI environment\n"
1142         "\n"
1143         "efidebug boot add <bootid> <label> <interface> <devnum>[:<part>] <file path> [<load options>]\n"
1144         "  - set UEFI BootXXXX variable\n"
1145         "    <load options> will be passed to UEFI application\n"
1146         "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
1147         "  - delete UEFI BootXXXX variables\n"
1148         "efidebug boot dump\n"
1149         "  - dump all UEFI BootXXXX variables\n"
1150         "efidebug boot next <bootid>\n"
1151         "  - set UEFI BootNext variable\n"
1152         "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
1153         "  - set/show UEFI boot order\n"
1154         "\n"
1155         "efidebug devices\n"
1156         "  - show UEFI devices\n"
1157         "efidebug drivers\n"
1158         "  - show UEFI drivers\n"
1159         "efidebug dh\n"
1160         "  - show UEFI handles\n"
1161         "efidebug images\n"
1162         "  - show loaded images\n"
1163         "efidebug memmap\n"
1164         "  - show UEFI memory map\n"
1165         "efidebug tables\n"
1166         "  - show UEFI configuration tables\n";
1167 #endif
1168
1169 U_BOOT_CMD(
1170         efidebug, 10, 0, do_efidebug,
1171         "Configure UEFI environment",
1172         efidebug_help_text
1173 );