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