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