efidebug: add multiple device path instances on Boot####
[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_dt_fixup.h>
12 #include <efi_load_initrd.h>
13 #include <efi_loader.h>
14 #include <efi_rng.h>
15 #include <exports.h>
16 #include <hexdump.h>
17 #include <log.h>
18 #include <malloc.h>
19 #include <mapmem.h>
20 #include <part.h>
21 #include <search.h>
22 #include <linux/ctype.h>
23 #include <linux/err.h>
24
25 #define BS systab.boottime
26 #define RT systab.runtime
27
28 #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
29 /**
30  * do_efi_capsule_update() - process a capsule update
31  *
32  * @cmdtp:      Command table
33  * @flag:       Command flag
34  * @argc:       Number of arguments
35  * @argv:       Argument array
36  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
37  *
38  * Implement efidebug "capsule update" sub-command.
39  * process a capsule update.
40  *
41  *     efidebug capsule update [-v] <capsule address>
42  */
43 static int do_efi_capsule_update(struct cmd_tbl *cmdtp, int flag,
44                                  int argc, char * const argv[])
45 {
46         struct efi_capsule_header *capsule;
47         int verbose = 0;
48         char *endp;
49         efi_status_t ret;
50
51         if (argc != 2 && argc != 3)
52                 return CMD_RET_USAGE;
53
54         if (argc == 3) {
55                 if (strcmp(argv[1], "-v"))
56                         return CMD_RET_USAGE;
57
58                 verbose = 1;
59                 argc--;
60                 argv++;
61         }
62
63         capsule = (typeof(capsule))simple_strtoul(argv[1], &endp, 16);
64         if (endp == argv[1]) {
65                 printf("Invalid address: %s", argv[1]);
66                 return CMD_RET_FAILURE;
67         }
68
69         if (verbose) {
70                 printf("Capsule guid: %pUl\n", &capsule->capsule_guid);
71                 printf("Capsule flags: 0x%x\n", capsule->flags);
72                 printf("Capsule header size: 0x%x\n", capsule->header_size);
73                 printf("Capsule image size: 0x%x\n",
74                        capsule->capsule_image_size);
75         }
76
77         ret = EFI_CALL(RT->update_capsule(&capsule, 1, 0));
78         if (ret) {
79                 printf("Cannot handle a capsule at %p", capsule);
80                 return CMD_RET_FAILURE;
81         }
82
83         return CMD_RET_SUCCESS;
84 }
85
86 static int do_efi_capsule_on_disk_update(struct cmd_tbl *cmdtp, int flag,
87                                          int argc, char * const argv[])
88 {
89         efi_status_t ret;
90
91         ret = efi_launch_capsules();
92
93         return ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
94 }
95
96 /**
97  * do_efi_capsule_show() - show capsule information
98  *
99  * @cmdtp:      Command table
100  * @flag:       Command flag
101  * @argc:       Number of arguments
102  * @argv:       Argument array
103  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
104  *
105  * Implement efidebug "capsule show" sub-command.
106  * show capsule information.
107  *
108  *     efidebug capsule show <capsule address>
109  */
110 static int do_efi_capsule_show(struct cmd_tbl *cmdtp, int flag,
111                                int argc, char * const argv[])
112 {
113         struct efi_capsule_header *capsule;
114         char *endp;
115
116         if (argc != 2)
117                 return CMD_RET_USAGE;
118
119         capsule = (typeof(capsule))simple_strtoul(argv[1], &endp, 16);
120         if (endp == argv[1]) {
121                 printf("Invalid address: %s", argv[1]);
122                 return CMD_RET_FAILURE;
123         }
124
125         printf("Capsule guid: %pUl\n", &capsule->capsule_guid);
126         printf("Capsule flags: 0x%x\n", capsule->flags);
127         printf("Capsule header size: 0x%x\n", capsule->header_size);
128         printf("Capsule image size: 0x%x\n",
129                capsule->capsule_image_size);
130
131         return CMD_RET_SUCCESS;
132 }
133
134 /**
135  * do_efi_capsule_res() - show a capsule update result
136  *
137  * @cmdtp:      Command table
138  * @flag:       Command flag
139  * @argc:       Number of arguments
140  * @argv:       Argument array
141  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
142  *
143  * Implement efidebug "capsule result" sub-command.
144  * show a capsule update result.
145  * If result number is not specified, CapsuleLast will be shown.
146  *
147  *     efidebug capsule result [<capsule result number>]
148  */
149 static int do_efi_capsule_res(struct cmd_tbl *cmdtp, int flag,
150                               int argc, char * const argv[])
151 {
152         int capsule_id;
153         char *endp;
154         char var_name[12];
155         u16 var_name16[12], *p;
156         efi_guid_t guid;
157         struct efi_capsule_result_variable_header *result = NULL;
158         efi_uintn_t size;
159         efi_status_t ret;
160
161         if (argc != 1 && argc != 2)
162                 return CMD_RET_USAGE;
163
164         guid = efi_guid_capsule_report;
165         if (argc == 1) {
166                 size = sizeof(var_name16);
167                 ret = EFI_CALL(RT->get_variable(L"CapsuleLast", &guid, NULL,
168                                                 &size, var_name16));
169                 if (ret != EFI_SUCCESS) {
170                         if (ret == EFI_NOT_FOUND)
171                                 printf("CapsuleLast doesn't exist\n");
172                         else
173                                 printf("Failed to get CapsuleLast\n");
174
175                         return CMD_RET_FAILURE;
176                 }
177                 printf("CapsuleLast is %ls\n", var_name16);
178         } else {
179                 argc--;
180                 argv++;
181
182                 capsule_id = simple_strtoul(argv[0], &endp, 16);
183                 if (capsule_id < 0 || capsule_id > 0xffff)
184                         return CMD_RET_USAGE;
185
186                 sprintf(var_name, "Capsule%04X", capsule_id);
187                 p = var_name16;
188                 utf8_utf16_strncpy(&p, var_name, 9);
189         }
190
191         size = 0;
192         ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size, NULL));
193         if (ret == EFI_BUFFER_TOO_SMALL) {
194                 result = malloc(size);
195                 if (!result)
196                         return CMD_RET_FAILURE;
197                 ret = EFI_CALL(RT->get_variable(var_name16, &guid, NULL, &size,
198                                                 result));
199         }
200         if (ret != EFI_SUCCESS) {
201                 free(result);
202                 printf("Failed to get %ls\n", var_name16);
203
204                 return CMD_RET_FAILURE;
205         }
206
207         printf("Result total size: 0x%x\n", result->variable_total_size);
208         printf("Capsule guid: %pUl\n", &result->capsule_guid);
209         printf("Time processed: %04d-%02d-%02d %02d:%02d:%02d\n",
210                result->capsule_processed.year, result->capsule_processed.month,
211                result->capsule_processed.day, result->capsule_processed.hour,
212                result->capsule_processed.minute,
213                result->capsule_processed.second);
214         printf("Capsule status: 0x%lx\n", result->capsule_status);
215
216         free(result);
217
218         return CMD_RET_SUCCESS;
219 }
220
221 static struct cmd_tbl cmd_efidebug_capsule_sub[] = {
222         U_BOOT_CMD_MKENT(update, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_update,
223                          "", ""),
224         U_BOOT_CMD_MKENT(show, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_show,
225                          "", ""),
226         U_BOOT_CMD_MKENT(disk-update, 0, 0, do_efi_capsule_on_disk_update,
227                          "", ""),
228         U_BOOT_CMD_MKENT(result, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_res,
229                          "", ""),
230 };
231
232 /**
233  * do_efi_capsule() - manage UEFI capsules
234  *
235  * @cmdtp:      Command table
236  * @flag:       Command flag
237  * @argc:       Number of arguments
238  * @argv:       Argument array
239  * Return:      CMD_RET_SUCCESS on success,
240  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
241  *
242  * Implement efidebug "capsule" sub-command.
243  */
244 static int do_efi_capsule(struct cmd_tbl *cmdtp, int flag,
245                           int argc, char * const argv[])
246 {
247         struct cmd_tbl *cp;
248
249         if (argc < 2)
250                 return CMD_RET_USAGE;
251
252         argc--; argv++;
253
254         cp = find_cmd_tbl(argv[0], cmd_efidebug_capsule_sub,
255                           ARRAY_SIZE(cmd_efidebug_capsule_sub));
256         if (!cp)
257                 return CMD_RET_USAGE;
258
259         return cp->cmd(cmdtp, flag, argc, argv);
260 }
261 #endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */
262
263 /**
264  * efi_get_device_handle_info() - get information of UEFI device
265  *
266  * @handle:             Handle of UEFI device
267  * @dev_path_text:      Pointer to text of device path
268  * Return:              0 on success, -1 on failure
269  *
270  * Currently return a formatted text of device path.
271  */
272 static int efi_get_device_handle_info(efi_handle_t handle, u16 **dev_path_text)
273 {
274         struct efi_device_path *dp;
275         efi_status_t ret;
276
277         ret = EFI_CALL(BS->open_protocol(handle, &efi_guid_device_path,
278                                          (void **)&dp, NULL /* FIXME */, NULL,
279                                          EFI_OPEN_PROTOCOL_GET_PROTOCOL));
280         if (ret == EFI_SUCCESS) {
281                 *dev_path_text = efi_dp_str(dp);
282                 return 0;
283         } else {
284                 return -1;
285         }
286 }
287
288 #define EFI_HANDLE_WIDTH ((int)sizeof(efi_handle_t) * 2)
289
290 static const char spc[] = "                ";
291 static const char sep[] = "================";
292
293 /**
294  * do_efi_show_devices() - show UEFI devices
295  *
296  * @cmdtp:      Command table
297  * @flag:       Command flag
298  * @argc:       Number of arguments
299  * @argv:       Argument array
300  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
301  *
302  * Implement efidebug "devices" sub-command.
303  * Show all UEFI devices and their information.
304  */
305 static int do_efi_show_devices(struct cmd_tbl *cmdtp, int flag,
306                                int argc, char *const argv[])
307 {
308         efi_handle_t *handles;
309         efi_uintn_t num, i;
310         u16 *dev_path_text;
311         efi_status_t ret;
312
313         ret = EFI_CALL(efi_locate_handle_buffer(ALL_HANDLES, NULL, NULL,
314                                                 &num, &handles));
315         if (ret != EFI_SUCCESS)
316                 return CMD_RET_FAILURE;
317
318         if (!num)
319                 return CMD_RET_SUCCESS;
320
321         printf("Device%.*s Device Path\n", EFI_HANDLE_WIDTH - 6, spc);
322         printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
323         for (i = 0; i < num; i++) {
324                 if (!efi_get_device_handle_info(handles[i], &dev_path_text)) {
325                         printf("%p %ls\n", handles[i], dev_path_text);
326                         efi_free_pool(dev_path_text);
327                 }
328         }
329
330         efi_free_pool(handles);
331
332         return CMD_RET_SUCCESS;
333 }
334
335 /**
336  * efi_get_driver_handle_info() - get information of UEFI driver
337  *
338  * @handle:             Handle of UEFI device
339  * @driver_name:        Driver name
340  * @image_path:         Pointer to text of device path
341  * Return:              0 on success, -1 on failure
342  *
343  * Currently return no useful information as all UEFI drivers are
344  * built-in..
345  */
346 static int efi_get_driver_handle_info(efi_handle_t handle, u16 **driver_name,
347                                       u16 **image_path)
348 {
349         struct efi_handler *handler;
350         struct efi_loaded_image *image;
351         efi_status_t ret;
352
353         /*
354          * driver name
355          * TODO: support EFI_COMPONENT_NAME2_PROTOCOL
356          */
357         *driver_name = NULL;
358
359         /* image name */
360         ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler);
361         if (ret != EFI_SUCCESS) {
362                 *image_path = NULL;
363                 return 0;
364         }
365
366         image = handler->protocol_interface;
367         *image_path = efi_dp_str(image->file_path);
368
369         return 0;
370 }
371
372 /**
373  * do_efi_show_drivers() - show UEFI drivers
374  *
375  * @cmdtp:      Command table
376  * @flag:       Command flag
377  * @argc:       Number of arguments
378  * @argv:       Argument array
379  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
380  *
381  * Implement efidebug "drivers" sub-command.
382  * Show all UEFI drivers and their information.
383  */
384 static int do_efi_show_drivers(struct cmd_tbl *cmdtp, int flag,
385                                int argc, char *const argv[])
386 {
387         efi_handle_t *handles;
388         efi_uintn_t num, i;
389         u16 *driver_name, *image_path_text;
390         efi_status_t ret;
391
392         ret = EFI_CALL(efi_locate_handle_buffer(
393                                 BY_PROTOCOL, &efi_guid_driver_binding_protocol,
394                                 NULL, &num, &handles));
395         if (ret != EFI_SUCCESS)
396                 return CMD_RET_FAILURE;
397
398         if (!num)
399                 return CMD_RET_SUCCESS;
400
401         printf("Driver%.*s Name                 Image Path\n",
402                EFI_HANDLE_WIDTH - 6, spc);
403         printf("%.*s ==================== ====================\n",
404                EFI_HANDLE_WIDTH, sep);
405         for (i = 0; i < num; i++) {
406                 if (!efi_get_driver_handle_info(handles[i], &driver_name,
407                                                 &image_path_text)) {
408                         if (image_path_text)
409                                 printf("%p %-20ls %ls\n", handles[i],
410                                        driver_name, image_path_text);
411                         else
412                                 printf("%p %-20ls <built-in>\n",
413                                        handles[i], driver_name);
414                         efi_free_pool(driver_name);
415                         efi_free_pool(image_path_text);
416                 }
417         }
418
419         efi_free_pool(handles);
420
421         return CMD_RET_SUCCESS;
422 }
423
424 static const struct {
425         const char *text;
426         const efi_guid_t guid;
427 } guid_list[] = {
428         {
429                 "Device Path",
430                 EFI_DEVICE_PATH_PROTOCOL_GUID,
431         },
432         {
433                 "Device Path To Text",
434                 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID,
435         },
436         {
437                 "Device Path Utilities",
438                 EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID,
439         },
440         {
441                 "Unicode Collation 2",
442                 EFI_UNICODE_COLLATION_PROTOCOL2_GUID,
443         },
444         {
445                 "Driver Binding",
446                 EFI_DRIVER_BINDING_PROTOCOL_GUID,
447         },
448         {
449                 "Simple Text Input",
450                 EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID,
451         },
452         {
453                 "Simple Text Input Ex",
454                 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID,
455         },
456         {
457                 "Simple Text Output",
458                 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID,
459         },
460         {
461                 "Block IO",
462                 EFI_BLOCK_IO_PROTOCOL_GUID,
463         },
464         {
465                 "Simple File System",
466                 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID,
467         },
468         {
469                 "Loaded Image",
470                 EFI_LOADED_IMAGE_PROTOCOL_GUID,
471         },
472         {
473                 "Graphics Output",
474                 EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID,
475         },
476         {
477                 "HII String",
478                 EFI_HII_STRING_PROTOCOL_GUID,
479         },
480         {
481                 "HII Database",
482                 EFI_HII_DATABASE_PROTOCOL_GUID,
483         },
484         {
485                 "HII Config Routing",
486                 EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID,
487         },
488         {
489                 "Load File2",
490                 EFI_LOAD_FILE2_PROTOCOL_GUID,
491         },
492         {
493                 "Random Number Generator",
494                 EFI_RNG_PROTOCOL_GUID,
495         },
496         {
497                 "Simple Network",
498                 EFI_SIMPLE_NETWORK_PROTOCOL_GUID,
499         },
500         {
501                 "PXE Base Code",
502                 EFI_PXE_BASE_CODE_PROTOCOL_GUID,
503         },
504         {
505                 "Device-Tree Fixup",
506                 EFI_DT_FIXUP_PROTOCOL_GUID,
507         },
508         {
509                 "System Partition",
510                 PARTITION_SYSTEM_GUID
511         },
512         {
513                 "Firmware Management",
514                 EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID
515         },
516         /* Configuration table GUIDs */
517         {
518                 "ACPI table",
519                 EFI_ACPI_TABLE_GUID,
520         },
521         {
522                 "device tree",
523                 EFI_FDT_GUID,
524         },
525         {
526                 "SMBIOS table",
527                 SMBIOS_TABLE_GUID,
528         },
529         {
530                 "Runtime properties",
531                 EFI_RT_PROPERTIES_TABLE_GUID,
532         },
533         {
534                 "TCG2 Final Events Table",
535                 EFI_TCG2_FINAL_EVENTS_TABLE_GUID,
536         },
537 };
538
539 /**
540  * get_guid_text - get string of GUID
541  *
542  * Return description of GUID.
543  *
544  * @guid:       GUID
545  * Return:      description of GUID or NULL
546  */
547 static const char *get_guid_text(const void *guid)
548 {
549         int i;
550
551         for (i = 0; i < ARRAY_SIZE(guid_list); i++) {
552                 /*
553                  * As guidcmp uses memcmp() we can safely accept unaligned
554                  * GUIDs.
555                  */
556                 if (!guidcmp(&guid_list[i].guid, guid))
557                         return guid_list[i].text;
558         }
559
560         return NULL;
561 }
562
563 /**
564  * do_efi_show_handles() - show UEFI handles
565  *
566  * @cmdtp:      Command table
567  * @flag:       Command flag
568  * @argc:       Number of arguments
569  * @argv:       Argument array
570  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
571  *
572  * Implement efidebug "dh" sub-command.
573  * Show all UEFI handles and their information, currently all protocols
574  * added to handle.
575  */
576 static int do_efi_show_handles(struct cmd_tbl *cmdtp, int flag,
577                                int argc, char *const argv[])
578 {
579         efi_handle_t *handles;
580         efi_guid_t **guid;
581         efi_uintn_t num, count, i, j;
582         const char *guid_text;
583         efi_status_t ret;
584
585         ret = EFI_CALL(efi_locate_handle_buffer(ALL_HANDLES, NULL, NULL,
586                                                 &num, &handles));
587         if (ret != EFI_SUCCESS)
588                 return CMD_RET_FAILURE;
589
590         if (!num)
591                 return CMD_RET_SUCCESS;
592
593         printf("Handle%.*s Protocols\n", EFI_HANDLE_WIDTH - 6, spc);
594         printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
595         for (i = 0; i < num; i++) {
596                 printf("%p", handles[i]);
597                 ret = EFI_CALL(BS->protocols_per_handle(handles[i], &guid,
598                                                         &count));
599                 if (ret || !count) {
600                         putc('\n');
601                         continue;
602                 }
603
604                 for (j = 0; j < count; j++) {
605                         if (j)
606                                 printf(", ");
607                         else
608                                 putc(' ');
609
610                         guid_text = get_guid_text(guid[j]);
611                         if (guid_text)
612                                 puts(guid_text);
613                         else
614                                 printf("%pUl", guid[j]);
615                 }
616                 putc('\n');
617         }
618
619         efi_free_pool(handles);
620
621         return CMD_RET_SUCCESS;
622 }
623
624 /**
625  * do_efi_show_images() - show UEFI images
626  *
627  * @cmdtp:      Command table
628  * @flag:       Command flag
629  * @argc:       Number of arguments
630  * @argv:       Argument array
631  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
632  *
633  * Implement efidebug "images" sub-command.
634  * Show all UEFI loaded images and their information.
635  */
636 static int do_efi_show_images(struct cmd_tbl *cmdtp, int flag,
637                               int argc, char *const argv[])
638 {
639         efi_print_image_infos(NULL);
640
641         return CMD_RET_SUCCESS;
642 }
643
644 static const char * const efi_mem_type_string[] = {
645         [EFI_RESERVED_MEMORY_TYPE] = "RESERVED",
646         [EFI_LOADER_CODE] = "LOADER CODE",
647         [EFI_LOADER_DATA] = "LOADER DATA",
648         [EFI_BOOT_SERVICES_CODE] = "BOOT CODE",
649         [EFI_BOOT_SERVICES_DATA] = "BOOT DATA",
650         [EFI_RUNTIME_SERVICES_CODE] = "RUNTIME CODE",
651         [EFI_RUNTIME_SERVICES_DATA] = "RUNTIME DATA",
652         [EFI_CONVENTIONAL_MEMORY] = "CONVENTIONAL",
653         [EFI_UNUSABLE_MEMORY] = "UNUSABLE MEM",
654         [EFI_ACPI_RECLAIM_MEMORY] = "ACPI RECLAIM MEM",
655         [EFI_ACPI_MEMORY_NVS] = "ACPI NVS",
656         [EFI_MMAP_IO] = "IO",
657         [EFI_MMAP_IO_PORT] = "IO PORT",
658         [EFI_PAL_CODE] = "PAL",
659         [EFI_PERSISTENT_MEMORY_TYPE] = "PERSISTENT",
660 };
661
662 static const struct efi_mem_attrs {
663         const u64 bit;
664         const char *text;
665 } efi_mem_attrs[] = {
666         {EFI_MEMORY_UC, "UC"},
667         {EFI_MEMORY_UC, "UC"},
668         {EFI_MEMORY_WC, "WC"},
669         {EFI_MEMORY_WT, "WT"},
670         {EFI_MEMORY_WB, "WB"},
671         {EFI_MEMORY_UCE, "UCE"},
672         {EFI_MEMORY_WP, "WP"},
673         {EFI_MEMORY_RP, "RP"},
674         {EFI_MEMORY_XP, "WP"},
675         {EFI_MEMORY_NV, "NV"},
676         {EFI_MEMORY_MORE_RELIABLE, "REL"},
677         {EFI_MEMORY_RO, "RO"},
678         {EFI_MEMORY_SP, "SP"},
679         {EFI_MEMORY_RUNTIME, "RT"},
680 };
681
682 /**
683  * print_memory_attributes() - print memory map attributes
684  *
685  * @attributes: Attribute value
686  *
687  * Print memory map attributes
688  */
689 static void print_memory_attributes(u64 attributes)
690 {
691         int sep, i;
692
693         for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++)
694                 if (attributes & efi_mem_attrs[i].bit) {
695                         if (sep) {
696                                 putc('|');
697                         } else {
698                                 putc(' ');
699                                 sep = 1;
700                         }
701                         puts(efi_mem_attrs[i].text);
702                 }
703 }
704
705 #define EFI_PHYS_ADDR_WIDTH (int)(sizeof(efi_physical_addr_t) * 2)
706
707 /**
708  * do_efi_show_memmap() - show UEFI memory map
709  *
710  * @cmdtp:      Command table
711  * @flag:       Command flag
712  * @argc:       Number of arguments
713  * @argv:       Argument array
714  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
715  *
716  * Implement efidebug "memmap" sub-command.
717  * Show UEFI memory map.
718  */
719 static int do_efi_show_memmap(struct cmd_tbl *cmdtp, int flag,
720                               int argc, char *const argv[])
721 {
722         struct efi_mem_desc *memmap = NULL, *map;
723         efi_uintn_t map_size = 0;
724         const char *type;
725         int i;
726         efi_status_t ret;
727
728         ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL);
729         if (ret == EFI_BUFFER_TOO_SMALL) {
730                 map_size += sizeof(struct efi_mem_desc); /* for my own */
731                 ret = efi_allocate_pool(EFI_LOADER_DATA, map_size,
732                                         (void *)&memmap);
733                 if (ret != EFI_SUCCESS)
734                         return CMD_RET_FAILURE;
735                 ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL);
736         }
737         if (ret != EFI_SUCCESS) {
738                 efi_free_pool(memmap);
739                 return CMD_RET_FAILURE;
740         }
741
742         printf("Type             Start%.*s End%.*s Attributes\n",
743                EFI_PHYS_ADDR_WIDTH - 5, spc, EFI_PHYS_ADDR_WIDTH - 3, spc);
744         printf("================ %.*s %.*s ==========\n",
745                EFI_PHYS_ADDR_WIDTH, sep, EFI_PHYS_ADDR_WIDTH, sep);
746         /*
747          * Coverity check: dereferencing null pointer "map."
748          * This is a false positive as memmap will always be
749          * populated by allocate_pool() above.
750          */
751         for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) {
752                 if (map->type < ARRAY_SIZE(efi_mem_type_string))
753                         type = efi_mem_type_string[map->type];
754                 else
755                         type = "(unknown)";
756
757                 printf("%-16s %.*llx-%.*llx", type,
758                        EFI_PHYS_ADDR_WIDTH,
759                        (u64)map_to_sysmem((void *)(uintptr_t)
760                                           map->physical_start),
761                        EFI_PHYS_ADDR_WIDTH,
762                        (u64)map_to_sysmem((void *)(uintptr_t)
763                                           (map->physical_start +
764                                            map->num_pages * EFI_PAGE_SIZE)));
765
766                 print_memory_attributes(map->attribute);
767                 putc('\n');
768         }
769
770         efi_free_pool(memmap);
771
772         return CMD_RET_SUCCESS;
773 }
774
775 /**
776  * do_efi_show_tables() - show UEFI configuration tables
777  *
778  * @cmdtp:      Command table
779  * @flag:       Command flag
780  * @argc:       Number of arguments
781  * @argv:       Argument array
782  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
783  *
784  * Implement efidebug "tables" sub-command.
785  * Show UEFI configuration tables.
786  */
787 static int do_efi_show_tables(struct cmd_tbl *cmdtp, int flag,
788                               int argc, char *const argv[])
789 {
790         efi_uintn_t i;
791         const char *guid_str;
792
793         for (i = 0; i < systab.nr_tables; ++i) {
794                 guid_str = get_guid_text(&systab.tables[i].guid);
795                 if (!guid_str)
796                         guid_str = "";
797                 printf("%pUl %s\n", &systab.tables[i].guid, guid_str);
798         }
799
800         return CMD_RET_SUCCESS;
801 }
802
803 /**
804  * create_initrd_dp() - Create a special device for our Boot### option
805  *
806  * @dev:        Device
807  * @part:       Disk partition
808  * @file:       Filename
809  * Return:      Pointer to the device path or ERR_PTR
810  *
811  */
812 static
813 struct efi_device_path *create_initrd_dp(const char *dev, const char *part,
814                                          const char *file)
815
816 {
817         struct efi_device_path *tmp_dp = NULL, *tmp_fp = NULL;
818         struct efi_device_path *initrd_dp = NULL;
819         efi_status_t ret;
820         const struct efi_initrd_dp id_dp = {
821                 .vendor = {
822                         {
823                         DEVICE_PATH_TYPE_MEDIA_DEVICE,
824                         DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
825                         sizeof(id_dp.vendor),
826                         },
827                         EFI_INITRD_MEDIA_GUID,
828                 },
829                 .end = {
830                         DEVICE_PATH_TYPE_END,
831                         DEVICE_PATH_SUB_TYPE_END,
832                         sizeof(id_dp.end),
833                 }
834         };
835
836         ret = efi_dp_from_name(dev, part, file, &tmp_dp, &tmp_fp);
837         if (ret != EFI_SUCCESS) {
838                 printf("Cannot create device path for \"%s %s\"\n", part, file);
839                 goto out;
840         }
841
842         initrd_dp = efi_dp_append((const struct efi_device_path *)&id_dp,
843                                   tmp_fp);
844
845 out:
846         efi_free_pool(tmp_dp);
847         efi_free_pool(tmp_fp);
848         return initrd_dp;
849 }
850
851 /**
852  * do_efi_boot_add() - set UEFI load option
853  *
854  * @cmdtp:      Command table
855  * @flag:       Command flag
856  * @argc:       Number of arguments
857  * @argv:       Argument array
858  * Return:      CMD_RET_SUCCESS on success,
859  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
860  *
861  * Implement efidebug "boot add" sub-command. Create or change UEFI load option.
862  *
863  * efidebug boot add -b <id> <label> <interface> <devnum>[:<part>] <file>
864  *                   -i <file> <interface2> <devnum2>[:<part>] <initrd>
865  *                   -s '<options>'
866  */
867 static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
868                            int argc, char *const argv[])
869 {
870         int id;
871         char *endp;
872         char var_name[9];
873         u16 var_name16[9], *p;
874         efi_guid_t guid;
875         size_t label_len, label_len16;
876         u16 *label;
877         struct efi_device_path *device_path = NULL, *file_path = NULL;
878         struct efi_device_path *final_fp = NULL;
879         struct efi_device_path *initrd_dp = NULL;
880         struct efi_load_option lo;
881         void *data = NULL;
882         efi_uintn_t size;
883         efi_uintn_t fp_size = 0;
884         efi_status_t ret;
885         int r = CMD_RET_SUCCESS;
886
887         guid = efi_global_variable_guid;
888
889         /* attributes */
890         lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */
891         lo.optional_data = NULL;
892         lo.label = NULL;
893
894         argc--;
895         argv++; /* 'add' */
896         for (; argc > 0; argc--, argv++) {
897                 if (!strcmp(argv[0], "-b")) {
898                         if (argc <  5 || lo.label) {
899                                 r = CMD_RET_USAGE;
900                                 goto out;
901                         }
902                         id = (int)simple_strtoul(argv[1], &endp, 16);
903                         if (*endp != '\0' || id > 0xffff)
904                                 return CMD_RET_USAGE;
905
906                         sprintf(var_name, "Boot%04X", id);
907                         p = var_name16;
908                         utf8_utf16_strncpy(&p, var_name, 9);
909
910                         /* label */
911                         label_len = strlen(argv[2]);
912                         label_len16 = utf8_utf16_strnlen(argv[2], label_len);
913                         label = malloc((label_len16 + 1) * sizeof(u16));
914                         if (!label)
915                                 return CMD_RET_FAILURE;
916                         lo.label = label; /* label will be changed below */
917                         utf8_utf16_strncpy(&label, argv[2], label_len);
918
919                         /* file path */
920                         ret = efi_dp_from_name(argv[3], argv[4], argv[5],
921                                                &device_path, &file_path);
922                         if (ret != EFI_SUCCESS) {
923                                 printf("Cannot create device path for \"%s %s\"\n",
924                                        argv[3], argv[4]);
925                                 r = CMD_RET_FAILURE;
926                                 goto out;
927                         }
928                         fp_size += efi_dp_size(file_path) +
929                                 sizeof(struct efi_device_path);
930                         argc -= 5;
931                         argv += 5;
932                 } else if (!strcmp(argv[0], "-i")) {
933                         if (argc < 3 || initrd_dp) {
934                                 r = CMD_RET_USAGE;
935                                 goto out;
936                         }
937
938                         initrd_dp = create_initrd_dp(argv[1], argv[2], argv[3]);
939                         if (!initrd_dp) {
940                                 printf("Cannot add an initrd\n");
941                                 r = CMD_RET_FAILURE;
942                                 goto out;
943                         }
944                         argc -= 3;
945                         argv += 3;
946                         fp_size += efi_dp_size(initrd_dp) +
947                                 sizeof(struct efi_device_path);
948                 } else if (!strcmp(argv[0], "-s")) {
949                         if (argc < 1 || lo.optional_data) {
950                                 r = CMD_RET_USAGE;
951                                 goto out;
952                         }
953                         lo.optional_data = (const u8 *)argv[1];
954                         argc -= 1;
955                         argv += 1;
956                 } else {
957                         r = CMD_RET_USAGE;
958                         goto out;
959                 }
960         }
961
962         if (!file_path) {
963                 printf("Missing binary\n");
964                 r = CMD_RET_USAGE;
965                 goto out;
966         }
967
968         final_fp = efi_dp_concat(file_path, initrd_dp);
969         if (!final_fp) {
970                 printf("Cannot create final device path\n");
971                 r = CMD_RET_FAILURE;
972                 goto out;
973         }
974
975         lo.file_path = final_fp;
976         lo.file_path_length = fp_size;
977
978         size = efi_serialize_load_option(&lo, (u8 **)&data);
979         if (!size) {
980                 r = CMD_RET_FAILURE;
981                 goto out;
982         }
983
984         ret = EFI_CALL(efi_set_variable(var_name16, &guid,
985                                         EFI_VARIABLE_NON_VOLATILE |
986                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
987                                         EFI_VARIABLE_RUNTIME_ACCESS,
988                                         size, data));
989         if (ret != EFI_SUCCESS) {
990                 printf("Cannot set %ls\n", var_name16);
991                 r = CMD_RET_FAILURE;
992         }
993
994 out:
995         free(data);
996         efi_free_pool(final_fp);
997         efi_free_pool(initrd_dp);
998         efi_free_pool(device_path);
999         efi_free_pool(file_path);
1000         free(lo.label);
1001
1002         return r;
1003 }
1004
1005 /**
1006  * do_efi_boot_rm() - delete UEFI load options
1007  *
1008  * @cmdtp:      Command table
1009  * @flag:       Command flag
1010  * @argc:       Number of arguments
1011  * @argv:       Argument array
1012  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1013  *
1014  * Implement efidebug "boot rm" sub-command.
1015  * Delete UEFI load options.
1016  *
1017  *     efidebug boot rm <id> ...
1018  */
1019 static int do_efi_boot_rm(struct cmd_tbl *cmdtp, int flag,
1020                           int argc, char *const argv[])
1021 {
1022         efi_guid_t guid;
1023         int id, i;
1024         char *endp;
1025         char var_name[9];
1026         u16 var_name16[9], *p;
1027         efi_status_t ret;
1028
1029         if (argc == 1)
1030                 return CMD_RET_USAGE;
1031
1032         guid = efi_global_variable_guid;
1033         for (i = 1; i < argc; i++, argv++) {
1034                 id = (int)simple_strtoul(argv[1], &endp, 16);
1035                 if (*endp != '\0' || id > 0xffff)
1036                         return CMD_RET_FAILURE;
1037
1038                 sprintf(var_name, "Boot%04X", id);
1039                 p = var_name16;
1040                 utf8_utf16_strncpy(&p, var_name, 9);
1041
1042                 ret = EFI_CALL(efi_set_variable(var_name16, &guid, 0, 0, NULL));
1043                 if (ret) {
1044                         printf("Cannot remove %ls\n", var_name16);
1045                         return CMD_RET_FAILURE;
1046                 }
1047         }
1048
1049         return CMD_RET_SUCCESS;
1050 }
1051
1052 /**
1053  * show_efi_boot_opt_data() - dump UEFI load option
1054  *
1055  * @varname16:  variable name
1056  * @data:       value of UEFI load option variable
1057  * @size:       size of the boot option
1058  *
1059  * Decode the value of UEFI load option variable and print information.
1060  */
1061 static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size)
1062 {
1063         struct efi_device_path *initrd_path = NULL;
1064         struct efi_load_option lo;
1065         char *label, *p;
1066         size_t label_len16, label_len;
1067         u16 *dp_str;
1068         efi_status_t ret;
1069         efi_uintn_t initrd_dp_size;
1070         const efi_guid_t lf2_initrd_guid = EFI_INITRD_MEDIA_GUID;
1071
1072         ret = efi_deserialize_load_option(&lo, data, size);
1073         if (ret != EFI_SUCCESS) {
1074                 printf("%ls: invalid load option\n", varname16);
1075                 return;
1076         }
1077
1078         label_len16 = u16_strlen(lo.label);
1079         label_len = utf16_utf8_strnlen(lo.label, label_len16);
1080         label = malloc(label_len + 1);
1081         if (!label)
1082                 return;
1083         p = label;
1084         utf16_utf8_strncpy(&p, lo.label, label_len16);
1085
1086         printf("%ls:\nattributes: %c%c%c (0x%08x)\n",
1087                varname16,
1088                /* ACTIVE */
1089                lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-',
1090                /* FORCE RECONNECT */
1091                lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-',
1092                /* HIDDEN */
1093                lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-',
1094                lo.attributes);
1095         printf("  label: %s\n", label);
1096
1097         dp_str = efi_dp_str(lo.file_path);
1098         printf("  file_path: %ls\n", dp_str);
1099         efi_free_pool(dp_str);
1100
1101         initrd_path = efi_dp_from_lo(&lo, &initrd_dp_size, lf2_initrd_guid);
1102         if (initrd_path) {
1103                 dp_str = efi_dp_str(initrd_path);
1104                 printf("  initrd_path: %ls\n", dp_str);
1105                 efi_free_pool(dp_str);
1106                 efi_free_pool(initrd_path);
1107         }
1108
1109         printf("  data:\n");
1110         print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
1111                        lo.optional_data, *size, true);
1112         free(label);
1113 }
1114
1115 /**
1116  * show_efi_boot_opt() - dump UEFI load option
1117  *
1118  * @varname16:  variable name
1119  *
1120  * Dump information defined by UEFI load option.
1121  */
1122 static void show_efi_boot_opt(u16 *varname16)
1123 {
1124         void *data;
1125         efi_uintn_t size;
1126         efi_status_t ret;
1127
1128         size = 0;
1129         ret = EFI_CALL(efi_get_variable(varname16, &efi_global_variable_guid,
1130                                         NULL, &size, NULL));
1131         if (ret == EFI_BUFFER_TOO_SMALL) {
1132                 data = malloc(size);
1133                 if (!data) {
1134                         printf("ERROR: Out of memory\n");
1135                         return;
1136                 }
1137                 ret = EFI_CALL(efi_get_variable(varname16,
1138                                                 &efi_global_variable_guid,
1139                                                 NULL, &size, data));
1140                 if (ret == EFI_SUCCESS)
1141                         show_efi_boot_opt_data(varname16, data, &size);
1142                 free(data);
1143         }
1144 }
1145
1146 static int u16_tohex(u16 c)
1147 {
1148         if (c >= '0' && c <= '9')
1149                 return c - '0';
1150         if (c >= 'A' && c <= 'F')
1151                 return c - 'A' + 10;
1152
1153         /* not hexadecimal */
1154         return -1;
1155 }
1156
1157 /**
1158  * show_efi_boot_dump() - dump all UEFI load options
1159  *
1160  * @cmdtp:      Command table
1161  * @flag:       Command flag
1162  * @argc:       Number of arguments
1163  * @argv:       Argument array
1164  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1165  *
1166  * Implement efidebug "boot dump" sub-command.
1167  * Dump information of all UEFI load options defined.
1168  *
1169  *     efidebug boot dump
1170  */
1171 static int do_efi_boot_dump(struct cmd_tbl *cmdtp, int flag,
1172                             int argc, char *const argv[])
1173 {
1174         u16 *var_name16, *p;
1175         efi_uintn_t buf_size, size;
1176         efi_guid_t guid;
1177         int id, i, digit;
1178         efi_status_t ret;
1179
1180         if (argc > 1)
1181                 return CMD_RET_USAGE;
1182
1183         buf_size = 128;
1184         var_name16 = malloc(buf_size);
1185         if (!var_name16)
1186                 return CMD_RET_FAILURE;
1187
1188         var_name16[0] = 0;
1189         for (;;) {
1190                 size = buf_size;
1191                 ret = EFI_CALL(efi_get_next_variable_name(&size, var_name16,
1192                                                           &guid));
1193                 if (ret == EFI_NOT_FOUND)
1194                         break;
1195                 if (ret == EFI_BUFFER_TOO_SMALL) {
1196                         buf_size = size;
1197                         p = realloc(var_name16, buf_size);
1198                         if (!p) {
1199                                 free(var_name16);
1200                                 return CMD_RET_FAILURE;
1201                         }
1202                         var_name16 = p;
1203                         ret = EFI_CALL(efi_get_next_variable_name(&size,
1204                                                                   var_name16,
1205                                                                   &guid));
1206                 }
1207                 if (ret != EFI_SUCCESS) {
1208                         free(var_name16);
1209                         return CMD_RET_FAILURE;
1210                 }
1211
1212                 if (memcmp(var_name16, L"Boot", 8))
1213                         continue;
1214
1215                 for (id = 0, i = 0; i < 4; i++) {
1216                         digit = u16_tohex(var_name16[4 + i]);
1217                         if (digit < 0)
1218                                 break;
1219                         id = (id << 4) + digit;
1220                 }
1221                 if (i == 4 && !var_name16[8])
1222                         show_efi_boot_opt(var_name16);
1223         }
1224
1225         free(var_name16);
1226
1227         return CMD_RET_SUCCESS;
1228 }
1229
1230 /**
1231  * show_efi_boot_order() - show order of UEFI load options
1232  *
1233  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1234  *
1235  * Show order of UEFI load options defined by BootOrder variable.
1236  */
1237 static int show_efi_boot_order(void)
1238 {
1239         u16 *bootorder;
1240         efi_uintn_t size;
1241         int num, i;
1242         char var_name[9];
1243         u16 var_name16[9], *p16;
1244         void *data;
1245         struct efi_load_option lo;
1246         char *label, *p;
1247         size_t label_len16, label_len;
1248         efi_status_t ret;
1249
1250         size = 0;
1251         ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid,
1252                                         NULL, &size, NULL));
1253         if (ret != EFI_BUFFER_TOO_SMALL) {
1254                 if (ret == EFI_NOT_FOUND) {
1255                         printf("BootOrder not defined\n");
1256                         return CMD_RET_SUCCESS;
1257                 } else {
1258                         return CMD_RET_FAILURE;
1259                 }
1260         }
1261         bootorder = malloc(size);
1262         if (!bootorder) {
1263                 printf("ERROR: Out of memory\n");
1264                 return CMD_RET_FAILURE;
1265         }
1266         ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid,
1267                                         NULL, &size, bootorder));
1268         if (ret != EFI_SUCCESS) {
1269                 ret = CMD_RET_FAILURE;
1270                 goto out;
1271         }
1272
1273         num = size / sizeof(u16);
1274         for (i = 0; i < num; i++) {
1275                 sprintf(var_name, "Boot%04X", bootorder[i]);
1276                 p16 = var_name16;
1277                 utf8_utf16_strncpy(&p16, var_name, 9);
1278
1279                 size = 0;
1280                 ret = EFI_CALL(efi_get_variable(var_name16,
1281                                                 &efi_global_variable_guid, NULL,
1282                                                 &size, NULL));
1283                 if (ret != EFI_BUFFER_TOO_SMALL) {
1284                         printf("%2d: %s: (not defined)\n", i + 1, var_name);
1285                         continue;
1286                 }
1287
1288                 data = malloc(size);
1289                 if (!data) {
1290                         ret = CMD_RET_FAILURE;
1291                         goto out;
1292                 }
1293                 ret = EFI_CALL(efi_get_variable(var_name16,
1294                                                 &efi_global_variable_guid, NULL,
1295                                                 &size, data));
1296                 if (ret != EFI_SUCCESS) {
1297                         free(data);
1298                         ret = CMD_RET_FAILURE;
1299                         goto out;
1300                 }
1301
1302                 ret = efi_deserialize_load_option(&lo, data, &size);
1303                 if (ret != EFI_SUCCESS) {
1304                         printf("%ls: invalid load option\n", var_name16);
1305                         ret = CMD_RET_FAILURE;
1306                         goto out;
1307                 }
1308
1309                 label_len16 = u16_strlen(lo.label);
1310                 label_len = utf16_utf8_strnlen(lo.label, label_len16);
1311                 label = malloc(label_len + 1);
1312                 if (!label) {
1313                         free(data);
1314                         ret = CMD_RET_FAILURE;
1315                         goto out;
1316                 }
1317                 p = label;
1318                 utf16_utf8_strncpy(&p, lo.label, label_len16);
1319                 printf("%2d: %s: %s\n", i + 1, var_name, label);
1320                 free(label);
1321
1322                 free(data);
1323         }
1324 out:
1325         free(bootorder);
1326
1327         return ret;
1328 }
1329
1330 /**
1331  * do_efi_boot_next() - manage UEFI BootNext variable
1332  *
1333  * @cmdtp:      Command table
1334  * @flag:       Command flag
1335  * @argc:       Number of arguments
1336  * @argv:       Argument array
1337  * Return:      CMD_RET_SUCCESS on success,
1338  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1339  *
1340  * Implement efidebug "boot next" sub-command.
1341  * Set BootNext variable.
1342  *
1343  *     efidebug boot next <id>
1344  */
1345 static int do_efi_boot_next(struct cmd_tbl *cmdtp, int flag,
1346                             int argc, char *const argv[])
1347 {
1348         u16 bootnext;
1349         efi_uintn_t size;
1350         char *endp;
1351         efi_guid_t guid;
1352         efi_status_t ret;
1353         int r = CMD_RET_SUCCESS;
1354
1355         if (argc != 2)
1356                 return CMD_RET_USAGE;
1357
1358         bootnext = (u16)simple_strtoul(argv[1], &endp, 16);
1359         if (*endp) {
1360                 printf("invalid value: %s\n", argv[1]);
1361                 r = CMD_RET_FAILURE;
1362                 goto out;
1363         }
1364
1365         guid = efi_global_variable_guid;
1366         size = sizeof(u16);
1367         ret = EFI_CALL(efi_set_variable(L"BootNext", &guid,
1368                                         EFI_VARIABLE_NON_VOLATILE |
1369                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
1370                                         EFI_VARIABLE_RUNTIME_ACCESS,
1371                                         size, &bootnext));
1372         if (ret != EFI_SUCCESS) {
1373                 printf("Cannot set BootNext\n");
1374                 r = CMD_RET_FAILURE;
1375         }
1376 out:
1377         return r;
1378 }
1379
1380 /**
1381  * do_efi_boot_order() - manage UEFI BootOrder variable
1382  *
1383  * @cmdtp:      Command table
1384  * @flag:       Command flag
1385  * @argc:       Number of arguments
1386  * @argv:       Argument array
1387  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1388  *
1389  * Implement efidebug "boot order" sub-command.
1390  * Show order of UEFI load options, or change it in BootOrder variable.
1391  *
1392  *     efidebug boot order [<id> ...]
1393  */
1394 static int do_efi_boot_order(struct cmd_tbl *cmdtp, int flag,
1395                              int argc, char *const argv[])
1396 {
1397         u16 *bootorder = NULL;
1398         efi_uintn_t size;
1399         int id, i;
1400         char *endp;
1401         efi_guid_t guid;
1402         efi_status_t ret;
1403         int r = CMD_RET_SUCCESS;
1404
1405         if (argc == 1)
1406                 return show_efi_boot_order();
1407
1408         argc--;
1409         argv++;
1410
1411         size = argc * sizeof(u16);
1412         bootorder = malloc(size);
1413         if (!bootorder)
1414                 return CMD_RET_FAILURE;
1415
1416         for (i = 0; i < argc; i++) {
1417                 id = (int)simple_strtoul(argv[i], &endp, 16);
1418                 if (*endp != '\0' || id > 0xffff) {
1419                         printf("invalid value: %s\n", argv[i]);
1420                         r = CMD_RET_FAILURE;
1421                         goto out;
1422                 }
1423
1424                 bootorder[i] = (u16)id;
1425         }
1426
1427         guid = efi_global_variable_guid;
1428         ret = EFI_CALL(efi_set_variable(L"BootOrder", &guid,
1429                                         EFI_VARIABLE_NON_VOLATILE |
1430                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
1431                                         EFI_VARIABLE_RUNTIME_ACCESS,
1432                                         size, bootorder));
1433         if (ret != EFI_SUCCESS) {
1434                 printf("Cannot set BootOrder\n");
1435                 r = CMD_RET_FAILURE;
1436         }
1437 out:
1438         free(bootorder);
1439
1440         return r;
1441 }
1442
1443 static struct cmd_tbl cmd_efidebug_boot_sub[] = {
1444         U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""),
1445         U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""),
1446         U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""),
1447         U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""),
1448         U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order,
1449                          "", ""),
1450 };
1451
1452 /**
1453  * do_efi_boot_opt() - manage UEFI load options
1454  *
1455  * @cmdtp:      Command table
1456  * @flag:       Command flag
1457  * @argc:       Number of arguments
1458  * @argv:       Argument array
1459  * Return:      CMD_RET_SUCCESS on success,
1460  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1461  *
1462  * Implement efidebug "boot" sub-command.
1463  */
1464 static int do_efi_boot_opt(struct cmd_tbl *cmdtp, int flag,
1465                            int argc, char *const argv[])
1466 {
1467         struct cmd_tbl *cp;
1468
1469         if (argc < 2)
1470                 return CMD_RET_USAGE;
1471
1472         argc--; argv++;
1473
1474         cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub,
1475                           ARRAY_SIZE(cmd_efidebug_boot_sub));
1476         if (!cp)
1477                 return CMD_RET_USAGE;
1478
1479         return cp->cmd(cmdtp, flag, argc, argv);
1480 }
1481
1482 /**
1483  * do_efi_test_bootmgr() - run simple bootmgr for test
1484  *
1485  * @cmdtp:      Command table
1486  * @flag:       Command flag
1487  * @argc:       Number of arguments
1488  * @argv:       Argument array
1489  * Return:      CMD_RET_SUCCESS on success,
1490  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1491  *
1492  * Implement efidebug "test bootmgr" sub-command.
1493  * Run simple bootmgr for test.
1494  *
1495  *     efidebug test bootmgr
1496  */
1497 static __maybe_unused int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag,
1498                                               int argc, char * const argv[])
1499 {
1500         efi_handle_t image;
1501         efi_uintn_t exit_data_size = 0;
1502         u16 *exit_data = NULL;
1503         efi_status_t ret;
1504         void *load_options = NULL;
1505
1506         ret = efi_bootmgr_load(&image, &load_options);
1507         printf("efi_bootmgr_load() returned: %ld\n", ret & ~EFI_ERROR_MASK);
1508
1509         /* We call efi_start_image() even if error for test purpose. */
1510         ret = EFI_CALL(efi_start_image(image, &exit_data_size, &exit_data));
1511         printf("efi_start_image() returned: %ld\n", ret & ~EFI_ERROR_MASK);
1512         if (ret && exit_data)
1513                 efi_free_pool(exit_data);
1514
1515         efi_restore_gd();
1516
1517         free(load_options);
1518         return CMD_RET_SUCCESS;
1519 }
1520
1521 static struct cmd_tbl cmd_efidebug_test_sub[] = {
1522 #ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
1523         U_BOOT_CMD_MKENT(bootmgr, CONFIG_SYS_MAXARGS, 1, do_efi_test_bootmgr,
1524                          "", ""),
1525 #endif
1526 };
1527
1528 /**
1529  * do_efi_test() - manage UEFI load options
1530  *
1531  * @cmdtp:      Command table
1532  * @flag:       Command flag
1533  * @argc:       Number of arguments
1534  * @argv:       Argument array
1535  * Return:      CMD_RET_SUCCESS on success,
1536  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1537  *
1538  * Implement efidebug "test" sub-command.
1539  */
1540 static int do_efi_test(struct cmd_tbl *cmdtp, int flag,
1541                        int argc, char * const argv[])
1542 {
1543         struct cmd_tbl *cp;
1544
1545         if (argc < 2)
1546                 return CMD_RET_USAGE;
1547
1548         argc--; argv++;
1549
1550         cp = find_cmd_tbl(argv[0], cmd_efidebug_test_sub,
1551                           ARRAY_SIZE(cmd_efidebug_test_sub));
1552         if (!cp)
1553                 return CMD_RET_USAGE;
1554
1555         return cp->cmd(cmdtp, flag, argc, argv);
1556 }
1557
1558 /**
1559  * do_efi_query_info() - QueryVariableInfo EFI service
1560  *
1561  * @cmdtp:      Command table
1562  * @flag:       Command flag
1563  * @argc:       Number of arguments
1564  * @argv:       Argument array
1565  * Return:      CMD_RET_SUCCESS on success,
1566  *              CMD_RET_USAGE or CMD_RET_FAILURE on failure
1567  *
1568  * Implement efidebug "test" sub-command.
1569  */
1570
1571 static int do_efi_query_info(struct cmd_tbl *cmdtp, int flag,
1572                              int argc, char * const argv[])
1573 {
1574         efi_status_t ret;
1575         u32 attr = 0;
1576         u64 max_variable_storage_size;
1577         u64 remain_variable_storage_size;
1578         u64 max_variable_size;
1579         int i;
1580
1581         for (i = 1; i < argc; i++) {
1582                 if (!strcmp(argv[i], "-bs"))
1583                         attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
1584                 else if (!strcmp(argv[i], "-rt"))
1585                         attr |= EFI_VARIABLE_RUNTIME_ACCESS;
1586                 else if (!strcmp(argv[i], "-nv"))
1587                         attr |= EFI_VARIABLE_NON_VOLATILE;
1588                 else if (!strcmp(argv[i], "-at"))
1589                         attr |=
1590                                 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1591         }
1592
1593         ret = EFI_CALL(efi_query_variable_info(attr,
1594                                                &max_variable_storage_size,
1595                                                &remain_variable_storage_size,
1596                                                &max_variable_size));
1597         if (ret != EFI_SUCCESS) {
1598                 printf("Error: Cannot query UEFI variables, r = %lu\n",
1599                        ret & ~EFI_ERROR_MASK);
1600                 return CMD_RET_FAILURE;
1601         }
1602
1603         printf("Max storage size %llu\n", max_variable_storage_size);
1604         printf("Remaining storage size %llu\n", remain_variable_storage_size);
1605         printf("Max variable size %llu\n", max_variable_size);
1606
1607         return CMD_RET_SUCCESS;
1608 }
1609
1610 static struct cmd_tbl cmd_efidebug_sub[] = {
1611         U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
1612 #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
1613         U_BOOT_CMD_MKENT(capsule, CONFIG_SYS_MAXARGS, 1, do_efi_capsule,
1614                          "", ""),
1615 #endif
1616         U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices,
1617                          "", ""),
1618         U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers,
1619                          "", ""),
1620         U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles,
1621                          "", ""),
1622         U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images,
1623                          "", ""),
1624         U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap,
1625                          "", ""),
1626         U_BOOT_CMD_MKENT(tables, CONFIG_SYS_MAXARGS, 1, do_efi_show_tables,
1627                          "", ""),
1628         U_BOOT_CMD_MKENT(test, CONFIG_SYS_MAXARGS, 1, do_efi_test,
1629                          "", ""),
1630         U_BOOT_CMD_MKENT(query, CONFIG_SYS_MAXARGS, 1, do_efi_query_info,
1631                          "", ""),
1632 };
1633
1634 /**
1635  * do_efidebug() - display and configure UEFI environment
1636  *
1637  * @cmdtp:      Command table
1638  * @flag:       Command flag
1639  * @argc:       Number of arguments
1640  * @argv:       Argument array
1641  * Return:      CMD_RET_SUCCESS on success,
1642  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1643  *
1644  * Implement efidebug command which allows us to display and
1645  * configure UEFI environment.
1646  */
1647 static int do_efidebug(struct cmd_tbl *cmdtp, int flag,
1648                        int argc, char *const argv[])
1649 {
1650         struct cmd_tbl *cp;
1651         efi_status_t r;
1652
1653         if (argc < 2)
1654                 return CMD_RET_USAGE;
1655
1656         argc--; argv++;
1657
1658         /* Initialize UEFI drivers */
1659         r = efi_init_obj_list();
1660         if (r != EFI_SUCCESS) {
1661                 printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
1662                        r & ~EFI_ERROR_MASK);
1663                 return CMD_RET_FAILURE;
1664         }
1665
1666         cp = find_cmd_tbl(argv[0], cmd_efidebug_sub,
1667                           ARRAY_SIZE(cmd_efidebug_sub));
1668         if (!cp)
1669                 return CMD_RET_USAGE;
1670
1671         return cp->cmd(cmdtp, flag, argc, argv);
1672 }
1673
1674 #ifdef CONFIG_SYS_LONGHELP
1675 static char efidebug_help_text[] =
1676         "  - UEFI Shell-like interface to configure UEFI environment\n"
1677         "\n"
1678         "efidebug boot add "
1679         "-b <bootid> <label> <interface> <devnum>[:<part>] <file path> "
1680         "-i <interface> <devnum>[:<part>] <initrd file path> "
1681         "-s '<optional data>'\n"
1682         "  - set UEFI BootXXXX variable\n"
1683         "    <load options> will be passed to UEFI application\n"
1684         "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
1685         "  - delete UEFI BootXXXX variables\n"
1686         "efidebug boot dump\n"
1687         "  - dump all UEFI BootXXXX variables\n"
1688         "efidebug boot next <bootid>\n"
1689         "  - set UEFI BootNext variable\n"
1690         "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
1691         "  - set/show UEFI boot order\n"
1692         "\n"
1693 #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
1694         "efidebug capsule update [-v] <capsule address>\n"
1695         "  - process a capsule\n"
1696         "efidebug capsule disk-update\n"
1697         "  - update a capsule from disk\n"
1698         "efidebug capsule show <capsule address>\n"
1699         "  - show capsule information\n"
1700         "efidebug capsule result [<capsule result var>]\n"
1701         "  - show a capsule update result\n"
1702         "\n"
1703 #endif
1704         "efidebug devices\n"
1705         "  - show UEFI devices\n"
1706         "efidebug drivers\n"
1707         "  - show UEFI drivers\n"
1708         "efidebug dh\n"
1709         "  - show UEFI handles\n"
1710         "efidebug images\n"
1711         "  - show loaded images\n"
1712         "efidebug memmap\n"
1713         "  - show UEFI memory map\n"
1714         "efidebug tables\n"
1715         "  - show UEFI configuration tables\n"
1716 #ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
1717         "efidebug test bootmgr\n"
1718         "  - run simple bootmgr for test\n"
1719 #endif
1720         "efidebug query [-nv][-bs][-rt][-at]\n"
1721         "  - show size of UEFI variables store\n";
1722 #endif
1723
1724 U_BOOT_CMD(
1725         efidebug, CONFIG_SYS_MAXARGS, 0, do_efidebug,
1726         "Configure UEFI environment",
1727         efidebug_help_text
1728 );