cmd: efidebug: add images command
[platform/kernel/u-boot.git] / cmd / efidebug.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  UEFI Shell-like command
4  *
5  *  Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
6  */
7
8 #include <charset.h>
9 #include <common.h>
10 #include <command.h>
11 #include <efi_loader.h>
12 #include <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                 DEVICE_PATH_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                 BLOCK_IO_GUID,
221         },
222         {
223                 "Simple File System",
224                 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID,
225         },
226         {
227                 "Loaded Image",
228                 LOADED_IMAGE_PROTOCOL_GUID,
229         },
230         {
231                 "GOP",
232                 EFI_GOP_GUID,
233         },
234 };
235
236 /**
237  * get_guid_text - get string of protocol guid
238  * @guid:       Protocol guid
239  * Return:      String
240  *
241  * Return string for display to represent the protocol.
242  */
243 static const char *get_guid_text(const efi_guid_t *guid)
244 {
245         int i;
246
247         for (i = 0; i < ARRAY_SIZE(guid_list); i++)
248                 if (!guidcmp(&guid_list[i].guid, guid))
249                         break;
250
251         if (i != ARRAY_SIZE(guid_list))
252                 return guid_list[i].text;
253         else
254                 return NULL;
255 }
256
257 /**
258  * do_efi_show_handles() - show UEFI handles
259  *
260  * @cmdtp:      Command table
261  * @flag:       Command flag
262  * @argc:       Number of arguments
263  * @argv:       Argument array
264  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
265  *
266  * Implement efidebug "dh" sub-command.
267  * Show all UEFI handles and their information, currently all protocols
268  * added to handle.
269  */
270 static int do_efi_show_handles(cmd_tbl_t *cmdtp, int flag,
271                                int argc, char * const argv[])
272 {
273         efi_handle_t *handles;
274         efi_guid_t **guid;
275         efi_uintn_t num, count, i, j;
276         const char *guid_text;
277         efi_status_t ret;
278
279         ret = EFI_CALL(BS->locate_handle_buffer(ALL_HANDLES, NULL, NULL,
280                                                 &num, &handles));
281         if (ret != EFI_SUCCESS)
282                 return CMD_RET_FAILURE;
283
284         if (!num)
285                 return CMD_RET_SUCCESS;
286
287         printf("Handle%.*s Protocols\n", EFI_HANDLE_WIDTH - 6, spc);
288         printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
289         for (i = 0; i < num; i++) {
290                 printf("%p", handles[i]);
291                 ret = EFI_CALL(BS->protocols_per_handle(handles[i], &guid,
292                                                         &count));
293                 if (ret || !count) {
294                         putc('\n');
295                         continue;
296                 }
297
298                 for (j = 0; j < count; j++) {
299                         if (j)
300                                 printf(", ");
301                         else
302                                 putc(' ');
303
304                         guid_text = get_guid_text(guid[j]);
305                         if (guid_text)
306                                 puts(guid_text);
307                         else
308                                 printf("%pUl", guid[j]);
309                 }
310                 putc('\n');
311         }
312
313         EFI_CALL(BS->free_pool(handles));
314
315         return CMD_RET_SUCCESS;
316 }
317
318 /**
319  * do_efi_show_images() - show UEFI images
320  *
321  * @cmdtp:      Command table
322  * @flag:       Command flag
323  * @argc:       Number of arguments
324  * @argv:       Argument array
325  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
326  *
327  * Implement efidebug "images" sub-command.
328  * Show all UEFI loaded images and their information.
329  */
330 static int do_efi_show_images(cmd_tbl_t *cmdtp, int flag,
331                               int argc, char * const argv[])
332 {
333         efi_print_image_infos(NULL);
334
335         return CMD_RET_SUCCESS;
336 }
337
338 /**
339  * do_efi_boot_add() - set UEFI load option
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,
346  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
347  *
348  * Implement efidebug "boot add" sub-command.
349  * Create or change UEFI load option.
350  *   - boot add <id> <label> <interface> <devnum>[:<part>] <file> <options>
351  */
352 static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag,
353                            int argc, char * const argv[])
354 {
355         int id;
356         char *endp;
357         char var_name[9];
358         u16 var_name16[9], *p;
359         efi_guid_t guid;
360         size_t label_len, label_len16;
361         u16 *label;
362         struct efi_device_path *device_path = NULL, *file_path = NULL;
363         struct efi_load_option lo;
364         void *data = NULL;
365         efi_uintn_t size;
366         int ret;
367
368         if (argc < 6 || argc > 7)
369                 return CMD_RET_USAGE;
370
371         id = (int)simple_strtoul(argv[1], &endp, 16);
372         if (*endp != '\0' || id > 0xffff)
373                 return CMD_RET_FAILURE;
374
375         sprintf(var_name, "Boot%04X", id);
376         p = var_name16;
377         utf8_utf16_strncpy(&p, var_name, 9);
378
379         guid = efi_global_variable_guid;
380
381         /* attributes */
382         lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */
383
384         /* label */
385         label_len = strlen(argv[2]);
386         label_len16 = utf8_utf16_strnlen(argv[2], label_len);
387         label = malloc((label_len16 + 1) * sizeof(u16));
388         if (!label)
389                 return CMD_RET_FAILURE;
390         lo.label = label; /* label will be changed below */
391         utf8_utf16_strncpy(&label, argv[2], label_len);
392
393         /* file path */
394         ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path,
395                                &file_path);
396         if (ret != EFI_SUCCESS) {
397                 printf("Cannot create device path for \"%s %s\"\n",
398                        argv[3], argv[4]);
399                 ret = CMD_RET_FAILURE;
400                 goto out;
401         }
402         lo.file_path = file_path;
403         lo.file_path_length = efi_dp_size(file_path)
404                                 + sizeof(struct efi_device_path); /* for END */
405
406         /* optional data */
407         lo.optional_data = (u8 *)(argc == 6 ? "" : argv[6]);
408
409         size = efi_serialize_load_option(&lo, (u8 **)&data);
410         if (!size) {
411                 ret = CMD_RET_FAILURE;
412                 goto out;
413         }
414
415         ret = EFI_CALL(RT->set_variable(var_name16, &guid,
416                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
417                                         EFI_VARIABLE_RUNTIME_ACCESS,
418                                         size, data));
419         ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
420 out:
421         free(data);
422         efi_free_pool(device_path);
423         efi_free_pool(file_path);
424         free(lo.label);
425
426         return ret;
427 }
428
429 /**
430  * do_efi_boot_rm() - delete UEFI load options
431  *
432  * @cmdtp:      Command table
433  * @flag:       Command flag
434  * @argc:       Number of arguments
435  * @argv:       Argument array
436  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
437  *
438  * Implement efidebug "boot rm" sub-command.
439  * Delete UEFI load options.
440  *   - boot rm <id> ...
441  */
442 static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag,
443                           int argc, char * const argv[])
444 {
445         efi_guid_t guid;
446         int id, i;
447         char *endp;
448         char var_name[9];
449         u16 var_name16[9];
450         efi_status_t ret;
451
452         if (argc == 1)
453                 return CMD_RET_USAGE;
454
455         guid = efi_global_variable_guid;
456         for (i = 1; i < argc; i++, argv++) {
457                 id = (int)simple_strtoul(argv[1], &endp, 16);
458                 if (*endp != '\0' || id > 0xffff)
459                         return CMD_RET_FAILURE;
460
461                 sprintf(var_name, "Boot%04X", id);
462                 utf8_utf16_strncpy((u16 **)&var_name16, var_name, 9);
463
464                 ret = EFI_CALL(RT->set_variable(var_name16, &guid, 0, 0, NULL));
465                 if (ret) {
466                         printf("cannot remove Boot%04X", id);
467                         return CMD_RET_FAILURE;
468                 }
469         }
470
471         return CMD_RET_SUCCESS;
472 }
473
474 /**
475  * show_efi_boot_opt_data() - dump UEFI load option
476  *
477  * @id:         Load option number
478  * @data:       Value of UEFI load option variable
479  *
480  * Decode the value of UEFI load option variable and print information.
481  */
482 static void show_efi_boot_opt_data(int id, void *data)
483 {
484         struct efi_load_option lo;
485         char *label, *p;
486         size_t label_len16, label_len;
487         u16 *dp_str;
488
489         efi_deserialize_load_option(&lo, data);
490
491         label_len16 = u16_strlen(lo.label);
492         label_len = utf16_utf8_strnlen(lo.label, label_len16);
493         label = malloc(label_len + 1);
494         if (!label)
495                 return;
496         p = label;
497         utf16_utf8_strncpy(&p, lo.label, label_len16);
498
499         printf("Boot%04X:\n", id);
500         printf("\tattributes: %c%c%c (0x%08x)\n",
501                /* ACTIVE */
502                lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-',
503                /* FORCE RECONNECT */
504                lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-',
505                /* HIDDEN */
506                lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-',
507                lo.attributes);
508         printf("\tlabel: %s\n", label);
509
510         dp_str = efi_dp_str(lo.file_path);
511         printf("\tfile_path: %ls\n", dp_str);
512         efi_free_pool(dp_str);
513
514         printf("\tdata: %s\n", lo.optional_data);
515
516         free(label);
517 }
518
519 /**
520  * show_efi_boot_opt() - dump UEFI load option
521  *
522  * @id:         Load option number
523  *
524  * Dump information defined by UEFI load option.
525  */
526 static void show_efi_boot_opt(int id)
527 {
528         char var_name[9];
529         u16 var_name16[9], *p;
530         efi_guid_t guid;
531         void *data = NULL;
532         efi_uintn_t size;
533         int ret;
534
535         sprintf(var_name, "Boot%04X", id);
536         p = var_name16;
537         utf8_utf16_strncpy(&p, var_name, 9);
538         guid = efi_global_variable_guid;
539
540         size = 0;
541         ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, NULL));
542         if (ret == (int)EFI_BUFFER_TOO_SMALL) {
543                 data = malloc(size);
544                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
545                                                 data));
546         }
547         if (ret == EFI_SUCCESS)
548                 show_efi_boot_opt_data(id, data);
549         else if (ret == EFI_NOT_FOUND)
550                 printf("Boot%04X: not found\n", id);
551
552         free(data);
553 }
554
555 /**
556  * show_efi_boot_dump() - dump all UEFI load options
557  *
558  * @cmdtp:      Command table
559  * @flag:       Command flag
560  * @argc:       Number of arguments
561  * @argv:       Argument array
562  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
563  *
564  * Implement efidebug "boot dump" sub-command.
565  * Dump information of all UEFI load options defined.
566  *   - boot dump
567  */
568 static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag,
569                             int argc, char * const argv[])
570 {
571         char regex[256];
572         char * const regexlist[] = {regex};
573         char *variables = NULL, *boot, *value;
574         int len;
575         int id;
576
577         if (argc > 1)
578                 return CMD_RET_USAGE;
579
580         snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_Boot[0-9A-F]+");
581
582         /* TODO: use GetNextVariableName? */
583         len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY,
584                         &variables, 0, 1, regexlist);
585
586         if (!len)
587                 return CMD_RET_SUCCESS;
588
589         if (len < 0)
590                 return CMD_RET_FAILURE;
591
592         boot = variables;
593         while (*boot) {
594                 value = strstr(boot, "Boot") + 4;
595                 id = (int)simple_strtoul(value, NULL, 16);
596                 show_efi_boot_opt(id);
597                 boot = strchr(boot, '\n');
598                 if (!*boot)
599                         break;
600                 boot++;
601         }
602         free(variables);
603
604         return CMD_RET_SUCCESS;
605 }
606
607 /**
608  * show_efi_boot_order() - show order of UEFI load options
609  *
610  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
611  *
612  * Show order of UEFI load options defined by BootOrder variable.
613  */
614 static int show_efi_boot_order(void)
615 {
616         efi_guid_t guid;
617         u16 *bootorder = NULL;
618         efi_uintn_t size;
619         int num, i;
620         char var_name[9];
621         u16 var_name16[9], *p16;
622         void *data;
623         struct efi_load_option lo;
624         char *label, *p;
625         size_t label_len16, label_len;
626         efi_status_t ret;
627
628         guid = efi_global_variable_guid;
629         size = 0;
630         ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL, &size,
631                                         NULL));
632         if (ret == EFI_BUFFER_TOO_SMALL) {
633                 bootorder = malloc(size);
634                 ret = EFI_CALL(RT->get_variable(L"BootOrder", &guid, NULL,
635                                                 &size, bootorder));
636         }
637         if (ret == EFI_NOT_FOUND) {
638                 printf("BootOrder not defined\n");
639                 ret = CMD_RET_SUCCESS;
640                 goto out;
641         } else if (ret != EFI_SUCCESS) {
642                 ret = CMD_RET_FAILURE;
643                 goto out;
644         }
645
646         num = size / sizeof(u16);
647         for (i = 0; i < num; i++) {
648                 sprintf(var_name, "Boot%04X", bootorder[i]);
649                 p16 = var_name16;
650                 utf8_utf16_strncpy(&p16, var_name, 9);
651
652                 size = 0;
653                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
654                                                 NULL));
655                 if (ret != EFI_BUFFER_TOO_SMALL) {
656                         printf("%2d: Boot%04X: (not defined)\n",
657                                i + 1, bootorder[i]);
658                         continue;
659                 }
660
661                 data = malloc(size);
662                 if (!data) {
663                         ret = CMD_RET_FAILURE;
664                         goto out;
665                 }
666                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
667                                                 data));
668                 if (ret != EFI_SUCCESS) {
669                         free(data);
670                         ret = CMD_RET_FAILURE;
671                         goto out;
672                 }
673
674                 efi_deserialize_load_option(&lo, data);
675
676                 label_len16 = u16_strlen(lo.label);
677                 label_len = utf16_utf8_strnlen(lo.label, label_len16);
678                 label = malloc(label_len + 1);
679                 if (!label) {
680                         free(data);
681                         ret = CMD_RET_FAILURE;
682                         goto out;
683                 }
684                 p = label;
685                 utf16_utf8_strncpy(&p, lo.label, label_len16);
686                 printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label);
687                 free(label);
688
689                 free(data);
690         }
691 out:
692         free(bootorder);
693
694         return ret;
695 }
696
697 /**
698  * do_efi_boot_next() - manage UEFI BootNext variable
699  *
700  * @cmdtp:      Command table
701  * @flag:       Command flag
702  * @argc:       Number of arguments
703  * @argv:       Argument array
704  * Return:      CMD_RET_SUCCESS on success,
705  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
706  *
707  * Implement efidebug "boot next" sub-command.
708  * Set BootNext variable.
709  *   - boot next <id>
710  */
711 static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag,
712                             int argc, char * const argv[])
713 {
714         u16 bootnext;
715         efi_uintn_t size;
716         char *endp;
717         efi_guid_t guid;
718         efi_status_t ret;
719
720         if (argc != 2)
721                 return CMD_RET_USAGE;
722
723         bootnext = (u16)simple_strtoul(argv[1], &endp, 16);
724         if (*endp != '\0' || bootnext > 0xffff) {
725                 printf("invalid value: %s\n", argv[1]);
726                 ret = CMD_RET_FAILURE;
727                 goto out;
728         }
729
730         guid = efi_global_variable_guid;
731         size = sizeof(u16);
732         ret = EFI_CALL(RT->set_variable(L"BootNext", &guid,
733                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
734                                         EFI_VARIABLE_RUNTIME_ACCESS,
735                                         size, &bootnext));
736         ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
737 out:
738         return ret;
739 }
740
741 /**
742  * do_efi_boot_order() - manage UEFI BootOrder variable
743  *
744  * @cmdtp:      Command table
745  * @flag:       Command flag
746  * @argc:       Number of arguments
747  * @argv:       Argument array
748  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
749  *
750  * Implement efidebug "boot order" sub-command.
751  * Show order of UEFI load options, or change it in BootOrder variable.
752  *   - boot order [<id> ...]
753  */
754 static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag,
755                              int argc, char * const argv[])
756 {
757         u16 *bootorder = NULL;
758         efi_uintn_t size;
759         int id, i;
760         char *endp;
761         efi_guid_t guid;
762         efi_status_t ret;
763
764         if (argc == 1)
765                 return show_efi_boot_order();
766
767         argc--;
768         argv++;
769
770         size = argc * sizeof(u16);
771         bootorder = malloc(size);
772         if (!bootorder)
773                 return CMD_RET_FAILURE;
774
775         for (i = 0; i < argc; i++) {
776                 id = (int)simple_strtoul(argv[i], &endp, 16);
777                 if (*endp != '\0' || id > 0xffff) {
778                         printf("invalid value: %s\n", argv[i]);
779                         ret = CMD_RET_FAILURE;
780                         goto out;
781                 }
782
783                 bootorder[i] = (u16)id;
784         }
785
786         guid = efi_global_variable_guid;
787         ret = EFI_CALL(RT->set_variable(L"BootOrder", &guid,
788                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
789                                         EFI_VARIABLE_RUNTIME_ACCESS,
790                                         size, bootorder));
791         ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE);
792 out:
793         free(bootorder);
794
795         return ret;
796 }
797
798 static cmd_tbl_t cmd_efidebug_boot_sub[] = {
799         U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""),
800         U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""),
801         U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""),
802         U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""),
803         U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order,
804                          "", ""),
805 };
806
807 /**
808  * do_efi_boot_opt() - manage UEFI load options
809  *
810  * @cmdtp:      Command table
811  * @flag:       Command flag
812  * @argc:       Number of arguments
813  * @argv:       Argument array
814  * Return:      CMD_RET_SUCCESS on success,
815  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
816  *
817  * Implement efidebug "boot" sub-command.
818  * See above for details of sub-commands.
819  */
820 static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag,
821                            int argc, char * const argv[])
822 {
823         cmd_tbl_t *cp;
824
825         if (argc < 2)
826                 return CMD_RET_USAGE;
827
828         argc--; argv++;
829
830         cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub,
831                           ARRAY_SIZE(cmd_efidebug_boot_sub));
832         if (!cp)
833                 return CMD_RET_USAGE;
834
835         return cp->cmd(cmdtp, flag, argc, argv);
836 }
837
838 static cmd_tbl_t cmd_efidebug_sub[] = {
839         U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
840         U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices,
841                          "", ""),
842         U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers,
843                          "", ""),
844         U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles,
845                          "", ""),
846         U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images,
847                          "", ""),
848 };
849
850 /**
851  * do_efidebug() - display and configure UEFI environment
852  *
853  * @cmdtp:      Command table
854  * @flag:       Command flag
855  * @argc:       Number of arguments
856  * @argv:       Argument array
857  * Return:      CMD_RET_SUCCESS on success,
858  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
859  *
860  * Implement efidebug command which allows us to display and
861  * configure UEFI environment.
862  * See above for details of sub-commands.
863  */
864 static int do_efidebug(cmd_tbl_t *cmdtp, int flag,
865                        int argc, char * const argv[])
866 {
867         cmd_tbl_t *cp;
868         efi_status_t r;
869
870         if (argc < 2)
871                 return CMD_RET_USAGE;
872
873         argc--; argv++;
874
875         /* Initialize UEFI drivers */
876         r = efi_init_obj_list();
877         if (r != EFI_SUCCESS) {
878                 printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
879                        r & ~EFI_ERROR_MASK);
880                 return CMD_RET_FAILURE;
881         }
882
883         cp = find_cmd_tbl(argv[0], cmd_efidebug_sub,
884                           ARRAY_SIZE(cmd_efidebug_sub));
885         if (!cp)
886                 return CMD_RET_USAGE;
887
888         return cp->cmd(cmdtp, flag, argc, argv);
889 }
890
891 #ifdef CONFIG_SYS_LONGHELP
892 static char efidebug_help_text[] =
893         "  - UEFI Shell-like interface to configure UEFI environment\n"
894         "\n"
895         "efidebug boot add <bootid> <label> <interface> <devnum>[:<part>] <file path> [<load options>]\n"
896         "  - set UEFI BootXXXX variable\n"
897         "    <load options> will be passed to UEFI application\n"
898         "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
899         "  - delete UEFI BootXXXX variables\n"
900         "efidebug boot dump\n"
901         "  - dump all UEFI BootXXXX variables\n"
902         "efidebug boot next <bootid>\n"
903         "  - set UEFI BootNext variable\n"
904         "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
905         "  - set/show UEFI boot order\n"
906         "\n"
907         "efidebug devices\n"
908         "  - show uefi devices\n"
909         "efidebug drivers\n"
910         "  - show uefi drivers\n"
911         "efidebug dh\n"
912         "  - show uefi handles\n"
913         "efidebug images\n"
914         "  - show loaded images\n";
915 #endif
916
917 U_BOOT_CMD(
918         efidebug, 10, 0, do_efidebug,
919         "Configure UEFI environment",
920         efidebug_help_text
921 );