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