Merge tag 'pull-24apr19' of git://git.denx.de/u-boot-dm
[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 <environment.h>
13 #include <exports.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  * @attributes: Attribute value
397  *
398  * Print memory map attributes
399  */
400 static void print_memory_attributes(u64 attributes)
401 {
402         int sep, i;
403
404         for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++)
405                 if (attributes & efi_mem_attrs[i].bit) {
406                         if (sep) {
407                                 putc('|');
408                         } else {
409                                 putc(' ');
410                                 sep = 1;
411                         }
412                         puts(efi_mem_attrs[i].text);
413                 }
414 }
415
416 #define EFI_PHYS_ADDR_WIDTH (int)(sizeof(efi_physical_addr_t) * 2)
417
418 /**
419  * do_efi_show_memmap() - show UEFI memory map
420  *
421  * @cmdtp:      Command table
422  * @flag:       Command flag
423  * @argc:       Number of arguments
424  * @argv:       Argument array
425  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
426  *
427  * Implement efidebug "memmap" sub-command.
428  * Show UEFI memory map.
429  */
430 static int do_efi_show_memmap(cmd_tbl_t *cmdtp, int flag,
431                               int argc, char * const argv[])
432 {
433         struct efi_mem_desc *memmap = NULL, *map;
434         efi_uintn_t map_size = 0;
435         const char *type;
436         int i;
437         efi_status_t ret;
438
439         ret = EFI_CALL(BS->get_memory_map(&map_size, memmap, NULL, NULL, NULL));
440         if (ret == EFI_BUFFER_TOO_SMALL) {
441                 map_size += sizeof(struct efi_mem_desc); /* for my own */
442                 ret = EFI_CALL(BS->allocate_pool(EFI_LOADER_DATA,
443                                                  map_size, (void *)&memmap));
444                 if (ret != EFI_SUCCESS)
445                         return CMD_RET_FAILURE;
446                 ret = EFI_CALL(BS->get_memory_map(&map_size, memmap,
447                                                   NULL, NULL, NULL));
448         }
449         if (ret != EFI_SUCCESS) {
450                 EFI_CALL(BS->free_pool(memmap));
451                 return CMD_RET_FAILURE;
452         }
453
454         printf("Type             Start%.*s End%.*s Attributes\n",
455                EFI_PHYS_ADDR_WIDTH - 5, spc, EFI_PHYS_ADDR_WIDTH - 3, spc);
456         printf("================ %.*s %.*s ==========\n",
457                EFI_PHYS_ADDR_WIDTH, sep, EFI_PHYS_ADDR_WIDTH, sep);
458         for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) {
459                 if (map->type < EFI_MAX_MEMORY_TYPE)
460                         type = efi_mem_type_string[map->type];
461                 else
462                         type = "(unknown)";
463
464                 printf("%-16s %.*llx-%.*llx", type,
465                        EFI_PHYS_ADDR_WIDTH,
466                        map->physical_start,
467                        EFI_PHYS_ADDR_WIDTH,
468                        map->physical_start + map->num_pages * EFI_PAGE_SIZE);
469
470                 print_memory_attributes(map->attribute);
471                 putc('\n');
472         }
473
474         EFI_CALL(BS->free_pool(memmap));
475
476         return CMD_RET_SUCCESS;
477 }
478
479 /**
480  * do_efi_boot_add() - set UEFI load option
481  *
482  * @cmdtp:      Command table
483  * @flag:       Command flag
484  * @argc:       Number of arguments
485  * @argv:       Argument array
486  * Return:      CMD_RET_SUCCESS on success,
487  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
488  *
489  * Implement efidebug "boot add" sub-command.
490  * Create or change UEFI load option.
491  *   - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
492  */
493 static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag,
494                            int argc, char * const argv[])
495 {
496         int id;
497         char *endp;
498         char var_name[9];
499         u16 var_name16[9], *p;
500         efi_guid_t guid;
501         size_t label_len, label_len16;
502         u16 *label;
503         struct efi_device_path *device_path = NULL, *file_path = NULL;
504         struct efi_load_option lo;
505         void *data = NULL;
506         efi_uintn_t size;
507         int ret;
508
509         if (argc < 6 || argc > 7)
510                 return CMD_RET_USAGE;
511
512         id = (int)simple_strtoul(argv[1], &endp, 16);
513         if (*endp != '\0' || id > 0xffff)
514                 return CMD_RET_USAGE;
515
516         sprintf(var_name, "Boot%04X", id);
517         p = var_name16;
518         utf8_utf16_strncpy(&p, var_name, 9);
519
520         guid = efi_global_variable_guid;
521
522         /* attributes */
523         lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */
524
525         /* label */
526         label_len = strlen(argv[2]);
527         label_len16 = utf8_utf16_strnlen(argv[2], label_len);
528         label = malloc((label_len16 + 1) * sizeof(u16));
529         if (!label)
530                 return CMD_RET_FAILURE;
531         lo.label = label; /* label will be changed below */
532         utf8_utf16_strncpy(&label, argv[2], label_len);
533
534         /* file path */
535         ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path,
536                                &file_path);
537         if (ret != EFI_SUCCESS) {
538                 printf("Cannot create device path for \"%s %s\"\n",
539                        argv[3], argv[4]);
540                 ret = CMD_RET_FAILURE;
541                 goto out;
542         }
543         lo.file_path = file_path;
544         lo.file_path_length = efi_dp_size(file_path)
545                                 + sizeof(struct efi_device_path); /* for END */
546
547         /* optional data */
548         lo.optional_data = (u8 *)(argc == 6 ? "" : argv[6]);
549
550         size = efi_serialize_load_option(&lo, (u8 **)&data);
551         if (!size) {
552                 ret = CMD_RET_FAILURE;
553                 goto out;
554         }
555
556         ret = EFI_CALL(RT->set_variable(var_name16, &guid,
557                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
558                                         EFI_VARIABLE_RUNTIME_ACCESS,
559                                         size, data));
560         ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
561 out:
562         free(data);
563         efi_free_pool(device_path);
564         efi_free_pool(file_path);
565         free(lo.label);
566
567         return ret;
568 }
569
570 /**
571  * do_efi_boot_rm() - delete UEFI load options
572  *
573  * @cmdtp:      Command table
574  * @flag:       Command flag
575  * @argc:       Number of arguments
576  * @argv:       Argument array
577  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
578  *
579  * Implement efidebug "boot rm" sub-command.
580  * Delete UEFI load options.
581  *   - boot rm <id> ...
582  */
583 static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag,
584                           int argc, char * const argv[])
585 {
586         efi_guid_t guid;
587         int id, i;
588         char *endp;
589         char var_name[9];
590         u16 var_name16[9];
591         efi_status_t ret;
592
593         if (argc == 1)
594                 return CMD_RET_USAGE;
595
596         guid = efi_global_variable_guid;
597         for (i = 1; i < argc; i++, argv++) {
598                 id = (int)simple_strtoul(argv[1], &endp, 16);
599                 if (*endp != '\0' || id > 0xffff)
600                         return CMD_RET_FAILURE;
601
602                 sprintf(var_name, "Boot%04X", id);
603                 utf8_utf16_strncpy((u16 **)&var_name16, var_name, 9);
604
605                 ret = EFI_CALL(RT->set_variable(var_name16, &guid, 0, 0, NULL));
606                 if (ret) {
607                         printf("cannot remove Boot%04X", id);
608                         return CMD_RET_FAILURE;
609                 }
610         }
611
612         return CMD_RET_SUCCESS;
613 }
614
615 /**
616  * show_efi_boot_opt_data() - dump UEFI load option
617  *
618  * @id:         Load option number
619  * @data:       Value of UEFI load option variable
620  *
621  * Decode the value of UEFI load option variable and print information.
622  */
623 static void show_efi_boot_opt_data(int id, void *data)
624 {
625         struct efi_load_option lo;
626         char *label, *p;
627         size_t label_len16, label_len;
628         u16 *dp_str;
629
630         efi_deserialize_load_option(&lo, data);
631
632         label_len16 = u16_strlen(lo.label);
633         label_len = utf16_utf8_strnlen(lo.label, label_len16);
634         label = malloc(label_len + 1);
635         if (!label)
636                 return;
637         p = label;
638         utf16_utf8_strncpy(&p, lo.label, label_len16);
639
640         printf("Boot%04X:\n", id);
641         printf("\tattributes: %c%c%c (0x%08x)\n",
642                /* ACTIVE */
643                lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-',
644                /* FORCE RECONNECT */
645                lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-',
646                /* HIDDEN */
647                lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-',
648                lo.attributes);
649         printf("\tlabel: %s\n", label);
650
651         dp_str = efi_dp_str(lo.file_path);
652         printf("\tfile_path: %ls\n", dp_str);
653         efi_free_pool(dp_str);
654
655         printf("\tdata: %s\n", lo.optional_data);
656
657         free(label);
658 }
659
660 /**
661  * show_efi_boot_opt() - dump UEFI load option
662  *
663  * @id:         Load option number
664  *
665  * Dump information defined by UEFI load option.
666  */
667 static void show_efi_boot_opt(int id)
668 {
669         char var_name[9];
670         u16 var_name16[9], *p;
671         efi_guid_t guid;
672         void *data = NULL;
673         efi_uintn_t size;
674         int ret;
675
676         sprintf(var_name, "Boot%04X", id);
677         p = var_name16;
678         utf8_utf16_strncpy(&p, var_name, 9);
679         guid = efi_global_variable_guid;
680
681         size = 0;
682         ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, NULL));
683         if (ret == (int)EFI_BUFFER_TOO_SMALL) {
684                 data = malloc(size);
685                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
686                                                 data));
687         }
688         if (ret == EFI_SUCCESS)
689                 show_efi_boot_opt_data(id, data);
690         else if (ret == EFI_NOT_FOUND)
691                 printf("Boot%04X: not found\n", id);
692
693         free(data);
694 }
695
696 /**
697  * show_efi_boot_dump() - dump all UEFI load options
698  *
699  * @cmdtp:      Command table
700  * @flag:       Command flag
701  * @argc:       Number of arguments
702  * @argv:       Argument array
703  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
704  *
705  * Implement efidebug "boot dump" sub-command.
706  * Dump information of all UEFI load options defined.
707  *   - boot dump
708  */
709 static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag,
710                             int argc, char * const argv[])
711 {
712         char regex[256];
713         char * const regexlist[] = {regex};
714         char *variables = NULL, *boot, *value;
715         int len;
716         int id;
717
718         if (argc > 1)
719                 return CMD_RET_USAGE;
720
721         snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_Boot[0-9A-F]+");
722
723         /* TODO: use GetNextVariableName? */
724         len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY,
725                         &variables, 0, 1, regexlist);
726
727         if (!len)
728                 return CMD_RET_SUCCESS;
729
730         if (len < 0)
731                 return CMD_RET_FAILURE;
732
733         boot = variables;
734         while (*boot) {
735                 value = strstr(boot, "Boot") + 4;
736                 id = (int)simple_strtoul(value, NULL, 16);
737                 show_efi_boot_opt(id);
738                 boot = strchr(boot, '\n');
739                 if (!*boot)
740                         break;
741                 boot++;
742         }
743         free(variables);
744
745         return CMD_RET_SUCCESS;
746 }
747
748 /**
749  * show_efi_boot_order() - show order of UEFI load options
750  *
751  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
752  *
753  * Show order of UEFI load options defined by BootOrder variable.
754  */
755 static int show_efi_boot_order(void)
756 {
757         efi_guid_t guid;
758         u16 *bootorder = NULL;
759         efi_uintn_t size;
760         int num, i;
761         char var_name[9];
762         u16 var_name16[9], *p16;
763         void *data;
764         struct efi_load_option lo;
765         char *label, *p;
766         size_t label_len16, label_len;
767         efi_status_t ret;
768
769         guid = efi_global_variable_guid;
770         size = 0;
771         ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL, &size,
772                                         NULL));
773         if (ret == EFI_BUFFER_TOO_SMALL) {
774                 bootorder = malloc(size);
775                 ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL,
776                                                 &size, bootorder));
777         }
778         if (ret == EFI_NOT_FOUND) {
779                 printf("BootOrder not defined\n");
780                 ret = CMD_RET_SUCCESS;
781                 goto out;
782         } else if (ret != EFI_SUCCESS) {
783                 ret = CMD_RET_FAILURE;
784                 goto out;
785         }
786
787         num = size / sizeof(u16);
788         for (i = 0; i < num; i++) {
789                 sprintf(var_name, "Boot%04X", bootorder[i]);
790                 p16 = var_name16;
791                 utf8_utf16_strncpy(&p16, var_name, 9);
792
793                 size = 0;
794                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
795                                                 NULL));
796                 if (ret != EFI_BUFFER_TOO_SMALL) {
797                         printf("%2d: Boot%04X: (not defined)\n",
798                                i + 1, bootorder[i]);
799                         continue;
800                 }
801
802                 data = malloc(size);
803                 if (!data) {
804                         ret = CMD_RET_FAILURE;
805                         goto out;
806                 }
807                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
808                                                 data));
809                 if (ret != EFI_SUCCESS) {
810                         free(data);
811                         ret = CMD_RET_FAILURE;
812                         goto out;
813                 }
814
815                 efi_deserialize_load_option(&lo, data);
816
817                 label_len16 = u16_strlen(lo.label);
818                 label_len = utf16_utf8_strnlen(lo.label, label_len16);
819                 label = malloc(label_len + 1);
820                 if (!label) {
821                         free(data);
822                         ret = CMD_RET_FAILURE;
823                         goto out;
824                 }
825                 p = label;
826                 utf16_utf8_strncpy(&p, lo.label, label_len16);
827                 printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label);
828                 free(label);
829
830                 free(data);
831         }
832 out:
833         free(bootorder);
834
835         return ret;
836 }
837
838 /**
839  * do_efi_boot_next() - manage UEFI BootNext variable
840  *
841  * @cmdtp:      Command table
842  * @flag:       Command flag
843  * @argc:       Number of arguments
844  * @argv:       Argument array
845  * Return:      CMD_RET_SUCCESS on success,
846  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
847  *
848  * Implement efidebug "boot next" sub-command.
849  * Set BootNext variable.
850  *   - boot next <id>
851  */
852 static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag,
853                             int argc, char * const argv[])
854 {
855         u16 bootnext;
856         efi_uintn_t size;
857         char *endp;
858         efi_guid_t guid;
859         efi_status_t ret;
860
861         if (argc != 2)
862                 return CMD_RET_USAGE;
863
864         bootnext = (u16)simple_strtoul(argv[1], &endp, 16);
865         if (*endp != '\0' || bootnext > 0xffff) {
866                 printf("invalid value: %s\n", argv[1]);
867                 ret = CMD_RET_FAILURE;
868                 goto out;
869         }
870
871         guid = efi_global_variable_guid;
872         size = sizeof(u16);
873         ret = EFI_CALL(RT->set_variable(L"BootNext", &guid,
874                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
875                                         EFI_VARIABLE_RUNTIME_ACCESS,
876                                         size, &bootnext));
877         ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
878 out:
879         return ret;
880 }
881
882 /**
883  * do_efi_boot_order() - manage UEFI BootOrder variable
884  *
885  * @cmdtp:      Command table
886  * @flag:       Command flag
887  * @argc:       Number of arguments
888  * @argv:       Argument array
889  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
890  *
891  * Implement efidebug "boot order" sub-command.
892  * Show order of UEFI load options, or change it in BootOrder variable.
893  *   - boot order [<id> ...]
894  */
895 static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag,
896                              int argc, char * const argv[])
897 {
898         u16 *bootorder = NULL;
899         efi_uintn_t size;
900         int id, i;
901         char *endp;
902         efi_guid_t guid;
903         efi_status_t ret;
904
905         if (argc == 1)
906                 return show_efi_boot_order();
907
908         argc--;
909         argv++;
910
911         size = argc * sizeof(u16);
912         bootorder = malloc(size);
913         if (!bootorder)
914                 return CMD_RET_FAILURE;
915
916         for (i = 0; i < argc; i++) {
917                 id = (int)simple_strtoul(argv[i], &endp, 16);
918                 if (*endp != '\0' || id > 0xffff) {
919                         printf("invalid value: %s\n", argv[i]);
920                         ret = CMD_RET_FAILURE;
921                         goto out;
922                 }
923
924                 bootorder[i] = (u16)id;
925         }
926
927         guid = efi_global_variable_guid;
928         ret = EFI_CALL(RT->set_variable(L"BootOrder", &guid,
929                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
930                                         EFI_VARIABLE_RUNTIME_ACCESS,
931                                         size, bootorder));
932         ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
933 out:
934         free(bootorder);
935
936         return ret;
937 }
938
939 static cmd_tbl_t cmd_efidebug_boot_sub[] = {
940         U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""),
941         U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""),
942         U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""),
943         U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""),
944         U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order,
945                          "", ""),
946 };
947
948 /**
949  * do_efi_boot_opt() - manage UEFI load options
950  *
951  * @cmdtp:      Command table
952  * @flag:       Command flag
953  * @argc:       Number of arguments
954  * @argv:       Argument array
955  * Return:      CMD_RET_SUCCESS on success,
956  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
957  *
958  * Implement efidebug "boot" sub-command.
959  * See above for details of sub-commands.
960  */
961 static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag,
962                            int argc, char * const argv[])
963 {
964         cmd_tbl_t *cp;
965
966         if (argc < 2)
967                 return CMD_RET_USAGE;
968
969         argc--; argv++;
970
971         cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub,
972                           ARRAY_SIZE(cmd_efidebug_boot_sub));
973         if (!cp)
974                 return CMD_RET_USAGE;
975
976         return cp->cmd(cmdtp, flag, argc, argv);
977 }
978
979 static cmd_tbl_t cmd_efidebug_sub[] = {
980         U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
981         U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices,
982                          "", ""),
983         U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers,
984                          "", ""),
985         U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles,
986                          "", ""),
987         U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images,
988                          "", ""),
989         U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap,
990                          "", ""),
991 };
992
993 /**
994  * do_efidebug() - display and configure UEFI environment
995  *
996  * @cmdtp:      Command table
997  * @flag:       Command flag
998  * @argc:       Number of arguments
999  * @argv:       Argument array
1000  * Return:      CMD_RET_SUCCESS on success,
1001  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1002  *
1003  * Implement efidebug command which allows us to display and
1004  * configure UEFI environment.
1005  * See above for details of sub-commands.
1006  */
1007 static int do_efidebug(cmd_tbl_t *cmdtp, int flag,
1008                        int argc, char * const argv[])
1009 {
1010         cmd_tbl_t *cp;
1011         efi_status_t r;
1012
1013         if (argc < 2)
1014                 return CMD_RET_USAGE;
1015
1016         argc--; argv++;
1017
1018         /* Initialize UEFI drivers */
1019         r = efi_init_obj_list();
1020         if (r != EFI_SUCCESS) {
1021                 printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
1022                        r & ~EFI_ERROR_MASK);
1023                 return CMD_RET_FAILURE;
1024         }
1025
1026         cp = find_cmd_tbl(argv[0], cmd_efidebug_sub,
1027                           ARRAY_SIZE(cmd_efidebug_sub));
1028         if (!cp)
1029                 return CMD_RET_USAGE;
1030
1031         return cp->cmd(cmdtp, flag, argc, argv);
1032 }
1033
1034 #ifdef CONFIG_SYS_LONGHELP
1035 static char efidebug_help_text[] =
1036         "  - UEFI Shell-like interface to configure UEFI environment\n"
1037         "\n"
1038         "efidebug boot add <bootid> <label> <interface> <devnum>[:<part>] <file path> [<load options>]\n"
1039         "  - set UEFI BootXXXX variable\n"
1040         "    <load options> will be passed to UEFI application\n"
1041         "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
1042         "  - delete UEFI BootXXXX variables\n"
1043         "efidebug boot dump\n"
1044         "  - dump all UEFI BootXXXX variables\n"
1045         "efidebug boot next <bootid>\n"
1046         "  - set UEFI BootNext variable\n"
1047         "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
1048         "  - set/show UEFI boot order\n"
1049         "\n"
1050         "efidebug devices\n"
1051         "  - show uefi devices\n"
1052         "efidebug drivers\n"
1053         "  - show uefi drivers\n"
1054         "efidebug dh\n"
1055         "  - show uefi handles\n"
1056         "efidebug images\n"
1057         "  - show loaded images\n"
1058         "efidebug memmap\n"
1059         "  - show uefi memory map\n";
1060 #endif
1061
1062 U_BOOT_CMD(
1063         efidebug, 10, 0, do_efidebug,
1064         "Configure UEFI environment",
1065         efidebug_help_text
1066 );