efi: Add ESRT to the EFI system table
[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                 "EFI System Resource Table",
523                 EFI_SYSTEM_RESOURCE_TABLE_GUID,
524         },
525         {
526                 "device tree",
527                 EFI_FDT_GUID,
528         },
529         {
530                 "SMBIOS table",
531                 SMBIOS_TABLE_GUID,
532         },
533         {
534                 "Runtime properties",
535                 EFI_RT_PROPERTIES_TABLE_GUID,
536         },
537         {
538                 "TCG2 Final Events Table",
539                 EFI_TCG2_FINAL_EVENTS_TABLE_GUID,
540         },
541 };
542
543 /**
544  * get_guid_text - get string of GUID
545  *
546  * Return description of GUID.
547  *
548  * @guid:       GUID
549  * Return:      description of GUID or NULL
550  */
551 static const char *get_guid_text(const void *guid)
552 {
553         int i;
554
555         for (i = 0; i < ARRAY_SIZE(guid_list); i++) {
556                 /*
557                  * As guidcmp uses memcmp() we can safely accept unaligned
558                  * GUIDs.
559                  */
560                 if (!guidcmp(&guid_list[i].guid, guid))
561                         return guid_list[i].text;
562         }
563
564         return NULL;
565 }
566
567 /**
568  * do_efi_show_handles() - show UEFI handles
569  *
570  * @cmdtp:      Command table
571  * @flag:       Command flag
572  * @argc:       Number of arguments
573  * @argv:       Argument array
574  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
575  *
576  * Implement efidebug "dh" sub-command.
577  * Show all UEFI handles and their information, currently all protocols
578  * added to handle.
579  */
580 static int do_efi_show_handles(struct cmd_tbl *cmdtp, int flag,
581                                int argc, char *const argv[])
582 {
583         efi_handle_t *handles;
584         efi_guid_t **guid;
585         efi_uintn_t num, count, i, j;
586         const char *guid_text;
587         efi_status_t ret;
588
589         ret = EFI_CALL(efi_locate_handle_buffer(ALL_HANDLES, NULL, NULL,
590                                                 &num, &handles));
591         if (ret != EFI_SUCCESS)
592                 return CMD_RET_FAILURE;
593
594         if (!num)
595                 return CMD_RET_SUCCESS;
596
597         printf("Handle%.*s Protocols\n", EFI_HANDLE_WIDTH - 6, spc);
598         printf("%.*s ====================\n", EFI_HANDLE_WIDTH, sep);
599         for (i = 0; i < num; i++) {
600                 printf("%p", handles[i]);
601                 ret = EFI_CALL(BS->protocols_per_handle(handles[i], &guid,
602                                                         &count));
603                 if (ret || !count) {
604                         putc('\n');
605                         continue;
606                 }
607
608                 for (j = 0; j < count; j++) {
609                         if (j)
610                                 printf(", ");
611                         else
612                                 putc(' ');
613
614                         guid_text = get_guid_text(guid[j]);
615                         if (guid_text)
616                                 puts(guid_text);
617                         else
618                                 printf("%pUl", guid[j]);
619                 }
620                 putc('\n');
621         }
622
623         efi_free_pool(handles);
624
625         return CMD_RET_SUCCESS;
626 }
627
628 /**
629  * do_efi_show_images() - show UEFI images
630  *
631  * @cmdtp:      Command table
632  * @flag:       Command flag
633  * @argc:       Number of arguments
634  * @argv:       Argument array
635  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
636  *
637  * Implement efidebug "images" sub-command.
638  * Show all UEFI loaded images and their information.
639  */
640 static int do_efi_show_images(struct cmd_tbl *cmdtp, int flag,
641                               int argc, char *const argv[])
642 {
643         efi_print_image_infos(NULL);
644
645         return CMD_RET_SUCCESS;
646 }
647
648 static const char * const efi_mem_type_string[] = {
649         [EFI_RESERVED_MEMORY_TYPE] = "RESERVED",
650         [EFI_LOADER_CODE] = "LOADER CODE",
651         [EFI_LOADER_DATA] = "LOADER DATA",
652         [EFI_BOOT_SERVICES_CODE] = "BOOT CODE",
653         [EFI_BOOT_SERVICES_DATA] = "BOOT DATA",
654         [EFI_RUNTIME_SERVICES_CODE] = "RUNTIME CODE",
655         [EFI_RUNTIME_SERVICES_DATA] = "RUNTIME DATA",
656         [EFI_CONVENTIONAL_MEMORY] = "CONVENTIONAL",
657         [EFI_UNUSABLE_MEMORY] = "UNUSABLE MEM",
658         [EFI_ACPI_RECLAIM_MEMORY] = "ACPI RECLAIM MEM",
659         [EFI_ACPI_MEMORY_NVS] = "ACPI NVS",
660         [EFI_MMAP_IO] = "IO",
661         [EFI_MMAP_IO_PORT] = "IO PORT",
662         [EFI_PAL_CODE] = "PAL",
663         [EFI_PERSISTENT_MEMORY_TYPE] = "PERSISTENT",
664 };
665
666 static const struct efi_mem_attrs {
667         const u64 bit;
668         const char *text;
669 } efi_mem_attrs[] = {
670         {EFI_MEMORY_UC, "UC"},
671         {EFI_MEMORY_UC, "UC"},
672         {EFI_MEMORY_WC, "WC"},
673         {EFI_MEMORY_WT, "WT"},
674         {EFI_MEMORY_WB, "WB"},
675         {EFI_MEMORY_UCE, "UCE"},
676         {EFI_MEMORY_WP, "WP"},
677         {EFI_MEMORY_RP, "RP"},
678         {EFI_MEMORY_XP, "WP"},
679         {EFI_MEMORY_NV, "NV"},
680         {EFI_MEMORY_MORE_RELIABLE, "REL"},
681         {EFI_MEMORY_RO, "RO"},
682         {EFI_MEMORY_SP, "SP"},
683         {EFI_MEMORY_RUNTIME, "RT"},
684 };
685
686 /**
687  * print_memory_attributes() - print memory map attributes
688  *
689  * @attributes: Attribute value
690  *
691  * Print memory map attributes
692  */
693 static void print_memory_attributes(u64 attributes)
694 {
695         int sep, i;
696
697         for (sep = 0, i = 0; i < ARRAY_SIZE(efi_mem_attrs); i++)
698                 if (attributes & efi_mem_attrs[i].bit) {
699                         if (sep) {
700                                 putc('|');
701                         } else {
702                                 putc(' ');
703                                 sep = 1;
704                         }
705                         puts(efi_mem_attrs[i].text);
706                 }
707 }
708
709 #define EFI_PHYS_ADDR_WIDTH (int)(sizeof(efi_physical_addr_t) * 2)
710
711 /**
712  * do_efi_show_memmap() - show UEFI memory map
713  *
714  * @cmdtp:      Command table
715  * @flag:       Command flag
716  * @argc:       Number of arguments
717  * @argv:       Argument array
718  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
719  *
720  * Implement efidebug "memmap" sub-command.
721  * Show UEFI memory map.
722  */
723 static int do_efi_show_memmap(struct cmd_tbl *cmdtp, int flag,
724                               int argc, char *const argv[])
725 {
726         struct efi_mem_desc *memmap = NULL, *map;
727         efi_uintn_t map_size = 0;
728         const char *type;
729         int i;
730         efi_status_t ret;
731
732         ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL);
733         if (ret == EFI_BUFFER_TOO_SMALL) {
734                 map_size += sizeof(struct efi_mem_desc); /* for my own */
735                 ret = efi_allocate_pool(EFI_LOADER_DATA, map_size,
736                                         (void *)&memmap);
737                 if (ret != EFI_SUCCESS)
738                         return CMD_RET_FAILURE;
739                 ret = efi_get_memory_map(&map_size, memmap, NULL, NULL, NULL);
740         }
741         if (ret != EFI_SUCCESS) {
742                 efi_free_pool(memmap);
743                 return CMD_RET_FAILURE;
744         }
745
746         printf("Type             Start%.*s End%.*s Attributes\n",
747                EFI_PHYS_ADDR_WIDTH - 5, spc, EFI_PHYS_ADDR_WIDTH - 3, spc);
748         printf("================ %.*s %.*s ==========\n",
749                EFI_PHYS_ADDR_WIDTH, sep, EFI_PHYS_ADDR_WIDTH, sep);
750         /*
751          * Coverity check: dereferencing null pointer "map."
752          * This is a false positive as memmap will always be
753          * populated by allocate_pool() above.
754          */
755         for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) {
756                 if (map->type < ARRAY_SIZE(efi_mem_type_string))
757                         type = efi_mem_type_string[map->type];
758                 else
759                         type = "(unknown)";
760
761                 printf("%-16s %.*llx-%.*llx", type,
762                        EFI_PHYS_ADDR_WIDTH,
763                        (u64)map_to_sysmem((void *)(uintptr_t)
764                                           map->physical_start),
765                        EFI_PHYS_ADDR_WIDTH,
766                        (u64)map_to_sysmem((void *)(uintptr_t)
767                                           (map->physical_start +
768                                            map->num_pages * EFI_PAGE_SIZE)));
769
770                 print_memory_attributes(map->attribute);
771                 putc('\n');
772         }
773
774         efi_free_pool(memmap);
775
776         return CMD_RET_SUCCESS;
777 }
778
779 /**
780  * do_efi_show_tables() - show UEFI configuration tables
781  *
782  * @cmdtp:      Command table
783  * @flag:       Command flag
784  * @argc:       Number of arguments
785  * @argv:       Argument array
786  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
787  *
788  * Implement efidebug "tables" sub-command.
789  * Show UEFI configuration tables.
790  */
791 static int do_efi_show_tables(struct cmd_tbl *cmdtp, int flag,
792                               int argc, char *const argv[])
793 {
794         efi_uintn_t i;
795         const char *guid_str;
796
797         for (i = 0; i < systab.nr_tables; ++i) {
798                 guid_str = get_guid_text(&systab.tables[i].guid);
799                 if (!guid_str)
800                         guid_str = "";
801                 printf("%pUl %s\n", &systab.tables[i].guid, guid_str);
802         }
803
804         return CMD_RET_SUCCESS;
805 }
806
807 /**
808  * create_initrd_dp() - Create a special device for our Boot### option
809  *
810  * @dev:        Device
811  * @part:       Disk partition
812  * @file:       Filename
813  * Return:      Pointer to the device path or ERR_PTR
814  *
815  */
816 static
817 struct efi_device_path *create_initrd_dp(const char *dev, const char *part,
818                                          const char *file)
819
820 {
821         struct efi_device_path *tmp_dp = NULL, *tmp_fp = NULL;
822         struct efi_device_path *initrd_dp = NULL;
823         efi_status_t ret;
824         const struct efi_initrd_dp id_dp = {
825                 .vendor = {
826                         {
827                         DEVICE_PATH_TYPE_MEDIA_DEVICE,
828                         DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
829                         sizeof(id_dp.vendor),
830                         },
831                         EFI_INITRD_MEDIA_GUID,
832                 },
833                 .end = {
834                         DEVICE_PATH_TYPE_END,
835                         DEVICE_PATH_SUB_TYPE_END,
836                         sizeof(id_dp.end),
837                 }
838         };
839
840         ret = efi_dp_from_name(dev, part, file, &tmp_dp, &tmp_fp);
841         if (ret != EFI_SUCCESS) {
842                 printf("Cannot create device path for \"%s %s\"\n", part, file);
843                 goto out;
844         }
845
846         initrd_dp = efi_dp_append((const struct efi_device_path *)&id_dp,
847                                   tmp_fp);
848
849 out:
850         efi_free_pool(tmp_dp);
851         efi_free_pool(tmp_fp);
852         return initrd_dp;
853 }
854
855 /**
856  * do_efi_boot_add() - set UEFI load option
857  *
858  * @cmdtp:      Command table
859  * @flag:       Command flag
860  * @argc:       Number of arguments
861  * @argv:       Argument array
862  * Return:      CMD_RET_SUCCESS on success,
863  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
864  *
865  * Implement efidebug "boot add" sub-command. Create or change UEFI load option.
866  *
867  * efidebug boot add -b <id> <label> <interface> <devnum>[:<part>] <file>
868  *                   -i <file> <interface2> <devnum2>[:<part>] <initrd>
869  *                   -s '<options>'
870  */
871 static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag,
872                            int argc, char *const argv[])
873 {
874         int id;
875         char *endp;
876         char var_name[9];
877         u16 var_name16[9], *p;
878         efi_guid_t guid;
879         size_t label_len, label_len16;
880         u16 *label;
881         struct efi_device_path *device_path = NULL, *file_path = NULL;
882         struct efi_device_path *final_fp = NULL;
883         struct efi_device_path *initrd_dp = NULL;
884         struct efi_load_option lo;
885         void *data = NULL;
886         efi_uintn_t size;
887         efi_uintn_t fp_size = 0;
888         efi_status_t ret;
889         int r = CMD_RET_SUCCESS;
890
891         guid = efi_global_variable_guid;
892
893         /* attributes */
894         lo.attributes = LOAD_OPTION_ACTIVE; /* always ACTIVE */
895         lo.optional_data = NULL;
896         lo.label = NULL;
897
898         argc--;
899         argv++; /* 'add' */
900         for (; argc > 0; argc--, argv++) {
901                 if (!strcmp(argv[0], "-b")) {
902                         if (argc <  5 || lo.label) {
903                                 r = CMD_RET_USAGE;
904                                 goto out;
905                         }
906                         id = (int)simple_strtoul(argv[1], &endp, 16);
907                         if (*endp != '\0' || id > 0xffff)
908                                 return CMD_RET_USAGE;
909
910                         sprintf(var_name, "Boot%04X", id);
911                         p = var_name16;
912                         utf8_utf16_strncpy(&p, var_name, 9);
913
914                         /* label */
915                         label_len = strlen(argv[2]);
916                         label_len16 = utf8_utf16_strnlen(argv[2], label_len);
917                         label = malloc((label_len16 + 1) * sizeof(u16));
918                         if (!label)
919                                 return CMD_RET_FAILURE;
920                         lo.label = label; /* label will be changed below */
921                         utf8_utf16_strncpy(&label, argv[2], label_len);
922
923                         /* file path */
924                         ret = efi_dp_from_name(argv[3], argv[4], argv[5],
925                                                &device_path, &file_path);
926                         if (ret != EFI_SUCCESS) {
927                                 printf("Cannot create device path for \"%s %s\"\n",
928                                        argv[3], argv[4]);
929                                 r = CMD_RET_FAILURE;
930                                 goto out;
931                         }
932                         fp_size += efi_dp_size(file_path) +
933                                 sizeof(struct efi_device_path);
934                         argc -= 5;
935                         argv += 5;
936                 } else if (!strcmp(argv[0], "-i")) {
937                         if (argc < 3 || initrd_dp) {
938                                 r = CMD_RET_USAGE;
939                                 goto out;
940                         }
941
942                         initrd_dp = create_initrd_dp(argv[1], argv[2], argv[3]);
943                         if (!initrd_dp) {
944                                 printf("Cannot add an initrd\n");
945                                 r = CMD_RET_FAILURE;
946                                 goto out;
947                         }
948                         argc -= 3;
949                         argv += 3;
950                         fp_size += efi_dp_size(initrd_dp) +
951                                 sizeof(struct efi_device_path);
952                 } else if (!strcmp(argv[0], "-s")) {
953                         if (argc < 1 || lo.optional_data) {
954                                 r = CMD_RET_USAGE;
955                                 goto out;
956                         }
957                         lo.optional_data = (const u8 *)argv[1];
958                         argc -= 1;
959                         argv += 1;
960                 } else {
961                         r = CMD_RET_USAGE;
962                         goto out;
963                 }
964         }
965
966         if (!file_path) {
967                 printf("Missing binary\n");
968                 r = CMD_RET_USAGE;
969                 goto out;
970         }
971
972         final_fp = efi_dp_concat(file_path, initrd_dp);
973         if (!final_fp) {
974                 printf("Cannot create final device path\n");
975                 r = CMD_RET_FAILURE;
976                 goto out;
977         }
978
979         lo.file_path = final_fp;
980         lo.file_path_length = fp_size;
981
982         size = efi_serialize_load_option(&lo, (u8 **)&data);
983         if (!size) {
984                 r = CMD_RET_FAILURE;
985                 goto out;
986         }
987
988         ret = EFI_CALL(efi_set_variable(var_name16, &guid,
989                                         EFI_VARIABLE_NON_VOLATILE |
990                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
991                                         EFI_VARIABLE_RUNTIME_ACCESS,
992                                         size, data));
993         if (ret != EFI_SUCCESS) {
994                 printf("Cannot set %ls\n", var_name16);
995                 r = CMD_RET_FAILURE;
996         }
997
998 out:
999         free(data);
1000         efi_free_pool(final_fp);
1001         efi_free_pool(initrd_dp);
1002         efi_free_pool(device_path);
1003         efi_free_pool(file_path);
1004         free(lo.label);
1005
1006         return r;
1007 }
1008
1009 /**
1010  * do_efi_boot_rm() - delete UEFI load options
1011  *
1012  * @cmdtp:      Command table
1013  * @flag:       Command flag
1014  * @argc:       Number of arguments
1015  * @argv:       Argument array
1016  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1017  *
1018  * Implement efidebug "boot rm" sub-command.
1019  * Delete UEFI load options.
1020  *
1021  *     efidebug boot rm <id> ...
1022  */
1023 static int do_efi_boot_rm(struct cmd_tbl *cmdtp, int flag,
1024                           int argc, char *const argv[])
1025 {
1026         efi_guid_t guid;
1027         int id, i;
1028         char *endp;
1029         char var_name[9];
1030         u16 var_name16[9], *p;
1031         efi_status_t ret;
1032
1033         if (argc == 1)
1034                 return CMD_RET_USAGE;
1035
1036         guid = efi_global_variable_guid;
1037         for (i = 1; i < argc; i++, argv++) {
1038                 id = (int)simple_strtoul(argv[1], &endp, 16);
1039                 if (*endp != '\0' || id > 0xffff)
1040                         return CMD_RET_FAILURE;
1041
1042                 sprintf(var_name, "Boot%04X", id);
1043                 p = var_name16;
1044                 utf8_utf16_strncpy(&p, var_name, 9);
1045
1046                 ret = EFI_CALL(efi_set_variable(var_name16, &guid, 0, 0, NULL));
1047                 if (ret) {
1048                         printf("Cannot remove %ls\n", var_name16);
1049                         return CMD_RET_FAILURE;
1050                 }
1051         }
1052
1053         return CMD_RET_SUCCESS;
1054 }
1055
1056 /**
1057  * show_efi_boot_opt_data() - dump UEFI load option
1058  *
1059  * @varname16:  variable name
1060  * @data:       value of UEFI load option variable
1061  * @size:       size of the boot option
1062  *
1063  * Decode the value of UEFI load option variable and print information.
1064  */
1065 static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size)
1066 {
1067         struct efi_device_path *initrd_path = NULL;
1068         struct efi_load_option lo;
1069         char *label, *p;
1070         size_t label_len16, label_len;
1071         u16 *dp_str;
1072         efi_status_t ret;
1073         efi_uintn_t initrd_dp_size;
1074         const efi_guid_t lf2_initrd_guid = EFI_INITRD_MEDIA_GUID;
1075
1076         ret = efi_deserialize_load_option(&lo, data, size);
1077         if (ret != EFI_SUCCESS) {
1078                 printf("%ls: invalid load option\n", varname16);
1079                 return;
1080         }
1081
1082         label_len16 = u16_strlen(lo.label);
1083         label_len = utf16_utf8_strnlen(lo.label, label_len16);
1084         label = malloc(label_len + 1);
1085         if (!label)
1086                 return;
1087         p = label;
1088         utf16_utf8_strncpy(&p, lo.label, label_len16);
1089
1090         printf("%ls:\nattributes: %c%c%c (0x%08x)\n",
1091                varname16,
1092                /* ACTIVE */
1093                lo.attributes & LOAD_OPTION_ACTIVE ? 'A' : '-',
1094                /* FORCE RECONNECT */
1095                lo.attributes & LOAD_OPTION_FORCE_RECONNECT ? 'R' : '-',
1096                /* HIDDEN */
1097                lo.attributes & LOAD_OPTION_HIDDEN ? 'H' : '-',
1098                lo.attributes);
1099         printf("  label: %s\n", label);
1100
1101         dp_str = efi_dp_str(lo.file_path);
1102         printf("  file_path: %ls\n", dp_str);
1103         efi_free_pool(dp_str);
1104
1105         initrd_path = efi_dp_from_lo(&lo, &initrd_dp_size, lf2_initrd_guid);
1106         if (initrd_path) {
1107                 dp_str = efi_dp_str(initrd_path);
1108                 printf("  initrd_path: %ls\n", dp_str);
1109                 efi_free_pool(dp_str);
1110                 efi_free_pool(initrd_path);
1111         }
1112
1113         printf("  data:\n");
1114         print_hex_dump("    ", DUMP_PREFIX_OFFSET, 16, 1,
1115                        lo.optional_data, *size, true);
1116         free(label);
1117 }
1118
1119 /**
1120  * show_efi_boot_opt() - dump UEFI load option
1121  *
1122  * @varname16:  variable name
1123  *
1124  * Dump information defined by UEFI load option.
1125  */
1126 static void show_efi_boot_opt(u16 *varname16)
1127 {
1128         void *data;
1129         efi_uintn_t size;
1130         efi_status_t ret;
1131
1132         size = 0;
1133         ret = EFI_CALL(efi_get_variable(varname16, &efi_global_variable_guid,
1134                                         NULL, &size, NULL));
1135         if (ret == EFI_BUFFER_TOO_SMALL) {
1136                 data = malloc(size);
1137                 if (!data) {
1138                         printf("ERROR: Out of memory\n");
1139                         return;
1140                 }
1141                 ret = EFI_CALL(efi_get_variable(varname16,
1142                                                 &efi_global_variable_guid,
1143                                                 NULL, &size, data));
1144                 if (ret == EFI_SUCCESS)
1145                         show_efi_boot_opt_data(varname16, data, &size);
1146                 free(data);
1147         }
1148 }
1149
1150 static int u16_tohex(u16 c)
1151 {
1152         if (c >= '0' && c <= '9')
1153                 return c - '0';
1154         if (c >= 'A' && c <= 'F')
1155                 return c - 'A' + 10;
1156
1157         /* not hexadecimal */
1158         return -1;
1159 }
1160
1161 /**
1162  * show_efi_boot_dump() - dump all UEFI load options
1163  *
1164  * @cmdtp:      Command table
1165  * @flag:       Command flag
1166  * @argc:       Number of arguments
1167  * @argv:       Argument array
1168  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1169  *
1170  * Implement efidebug "boot dump" sub-command.
1171  * Dump information of all UEFI load options defined.
1172  *
1173  *     efidebug boot dump
1174  */
1175 static int do_efi_boot_dump(struct cmd_tbl *cmdtp, int flag,
1176                             int argc, char *const argv[])
1177 {
1178         u16 *var_name16, *p;
1179         efi_uintn_t buf_size, size;
1180         efi_guid_t guid;
1181         int id, i, digit;
1182         efi_status_t ret;
1183
1184         if (argc > 1)
1185                 return CMD_RET_USAGE;
1186
1187         buf_size = 128;
1188         var_name16 = malloc(buf_size);
1189         if (!var_name16)
1190                 return CMD_RET_FAILURE;
1191
1192         var_name16[0] = 0;
1193         for (;;) {
1194                 size = buf_size;
1195                 ret = EFI_CALL(efi_get_next_variable_name(&size, var_name16,
1196                                                           &guid));
1197                 if (ret == EFI_NOT_FOUND)
1198                         break;
1199                 if (ret == EFI_BUFFER_TOO_SMALL) {
1200                         buf_size = size;
1201                         p = realloc(var_name16, buf_size);
1202                         if (!p) {
1203                                 free(var_name16);
1204                                 return CMD_RET_FAILURE;
1205                         }
1206                         var_name16 = p;
1207                         ret = EFI_CALL(efi_get_next_variable_name(&size,
1208                                                                   var_name16,
1209                                                                   &guid));
1210                 }
1211                 if (ret != EFI_SUCCESS) {
1212                         free(var_name16);
1213                         return CMD_RET_FAILURE;
1214                 }
1215
1216                 if (memcmp(var_name16, L"Boot", 8))
1217                         continue;
1218
1219                 for (id = 0, i = 0; i < 4; i++) {
1220                         digit = u16_tohex(var_name16[4 + i]);
1221                         if (digit < 0)
1222                                 break;
1223                         id = (id << 4) + digit;
1224                 }
1225                 if (i == 4 && !var_name16[8])
1226                         show_efi_boot_opt(var_name16);
1227         }
1228
1229         free(var_name16);
1230
1231         return CMD_RET_SUCCESS;
1232 }
1233
1234 /**
1235  * show_efi_boot_order() - show order of UEFI load options
1236  *
1237  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1238  *
1239  * Show order of UEFI load options defined by BootOrder variable.
1240  */
1241 static int show_efi_boot_order(void)
1242 {
1243         u16 *bootorder;
1244         efi_uintn_t size;
1245         int num, i;
1246         char var_name[9];
1247         u16 var_name16[9], *p16;
1248         void *data;
1249         struct efi_load_option lo;
1250         char *label, *p;
1251         size_t label_len16, label_len;
1252         efi_status_t ret;
1253
1254         size = 0;
1255         ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid,
1256                                         NULL, &size, NULL));
1257         if (ret != EFI_BUFFER_TOO_SMALL) {
1258                 if (ret == EFI_NOT_FOUND) {
1259                         printf("BootOrder not defined\n");
1260                         return CMD_RET_SUCCESS;
1261                 } else {
1262                         return CMD_RET_FAILURE;
1263                 }
1264         }
1265         bootorder = malloc(size);
1266         if (!bootorder) {
1267                 printf("ERROR: Out of memory\n");
1268                 return CMD_RET_FAILURE;
1269         }
1270         ret = EFI_CALL(efi_get_variable(L"BootOrder", &efi_global_variable_guid,
1271                                         NULL, &size, bootorder));
1272         if (ret != EFI_SUCCESS) {
1273                 ret = CMD_RET_FAILURE;
1274                 goto out;
1275         }
1276
1277         num = size / sizeof(u16);
1278         for (i = 0; i < num; i++) {
1279                 sprintf(var_name, "Boot%04X", bootorder[i]);
1280                 p16 = var_name16;
1281                 utf8_utf16_strncpy(&p16, var_name, 9);
1282
1283                 size = 0;
1284                 ret = EFI_CALL(efi_get_variable(var_name16,
1285                                                 &efi_global_variable_guid, NULL,
1286                                                 &size, NULL));
1287                 if (ret != EFI_BUFFER_TOO_SMALL) {
1288                         printf("%2d: %s: (not defined)\n", i + 1, var_name);
1289                         continue;
1290                 }
1291
1292                 data = malloc(size);
1293                 if (!data) {
1294                         ret = CMD_RET_FAILURE;
1295                         goto out;
1296                 }
1297                 ret = EFI_CALL(efi_get_variable(var_name16,
1298                                                 &efi_global_variable_guid, NULL,
1299                                                 &size, data));
1300                 if (ret != EFI_SUCCESS) {
1301                         free(data);
1302                         ret = CMD_RET_FAILURE;
1303                         goto out;
1304                 }
1305
1306                 ret = efi_deserialize_load_option(&lo, data, &size);
1307                 if (ret != EFI_SUCCESS) {
1308                         printf("%ls: invalid load option\n", var_name16);
1309                         ret = CMD_RET_FAILURE;
1310                         goto out;
1311                 }
1312
1313                 label_len16 = u16_strlen(lo.label);
1314                 label_len = utf16_utf8_strnlen(lo.label, label_len16);
1315                 label = malloc(label_len + 1);
1316                 if (!label) {
1317                         free(data);
1318                         ret = CMD_RET_FAILURE;
1319                         goto out;
1320                 }
1321                 p = label;
1322                 utf16_utf8_strncpy(&p, lo.label, label_len16);
1323                 printf("%2d: %s: %s\n", i + 1, var_name, label);
1324                 free(label);
1325
1326                 free(data);
1327         }
1328 out:
1329         free(bootorder);
1330
1331         return ret;
1332 }
1333
1334 /**
1335  * do_efi_boot_next() - manage UEFI BootNext variable
1336  *
1337  * @cmdtp:      Command table
1338  * @flag:       Command flag
1339  * @argc:       Number of arguments
1340  * @argv:       Argument array
1341  * Return:      CMD_RET_SUCCESS on success,
1342  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1343  *
1344  * Implement efidebug "boot next" sub-command.
1345  * Set BootNext variable.
1346  *
1347  *     efidebug boot next <id>
1348  */
1349 static int do_efi_boot_next(struct cmd_tbl *cmdtp, int flag,
1350                             int argc, char *const argv[])
1351 {
1352         u16 bootnext;
1353         efi_uintn_t size;
1354         char *endp;
1355         efi_guid_t guid;
1356         efi_status_t ret;
1357         int r = CMD_RET_SUCCESS;
1358
1359         if (argc != 2)
1360                 return CMD_RET_USAGE;
1361
1362         bootnext = (u16)simple_strtoul(argv[1], &endp, 16);
1363         if (*endp) {
1364                 printf("invalid value: %s\n", argv[1]);
1365                 r = CMD_RET_FAILURE;
1366                 goto out;
1367         }
1368
1369         guid = efi_global_variable_guid;
1370         size = sizeof(u16);
1371         ret = EFI_CALL(efi_set_variable(L"BootNext", &guid,
1372                                         EFI_VARIABLE_NON_VOLATILE |
1373                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
1374                                         EFI_VARIABLE_RUNTIME_ACCESS,
1375                                         size, &bootnext));
1376         if (ret != EFI_SUCCESS) {
1377                 printf("Cannot set BootNext\n");
1378                 r = CMD_RET_FAILURE;
1379         }
1380 out:
1381         return r;
1382 }
1383
1384 /**
1385  * do_efi_boot_order() - manage UEFI BootOrder variable
1386  *
1387  * @cmdtp:      Command table
1388  * @flag:       Command flag
1389  * @argc:       Number of arguments
1390  * @argv:       Argument array
1391  * Return:      CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure
1392  *
1393  * Implement efidebug "boot order" sub-command.
1394  * Show order of UEFI load options, or change it in BootOrder variable.
1395  *
1396  *     efidebug boot order [<id> ...]
1397  */
1398 static int do_efi_boot_order(struct cmd_tbl *cmdtp, int flag,
1399                              int argc, char *const argv[])
1400 {
1401         u16 *bootorder = NULL;
1402         efi_uintn_t size;
1403         int id, i;
1404         char *endp;
1405         efi_guid_t guid;
1406         efi_status_t ret;
1407         int r = CMD_RET_SUCCESS;
1408
1409         if (argc == 1)
1410                 return show_efi_boot_order();
1411
1412         argc--;
1413         argv++;
1414
1415         size = argc * sizeof(u16);
1416         bootorder = malloc(size);
1417         if (!bootorder)
1418                 return CMD_RET_FAILURE;
1419
1420         for (i = 0; i < argc; i++) {
1421                 id = (int)simple_strtoul(argv[i], &endp, 16);
1422                 if (*endp != '\0' || id > 0xffff) {
1423                         printf("invalid value: %s\n", argv[i]);
1424                         r = CMD_RET_FAILURE;
1425                         goto out;
1426                 }
1427
1428                 bootorder[i] = (u16)id;
1429         }
1430
1431         guid = efi_global_variable_guid;
1432         ret = EFI_CALL(efi_set_variable(L"BootOrder", &guid,
1433                                         EFI_VARIABLE_NON_VOLATILE |
1434                                         EFI_VARIABLE_BOOTSERVICE_ACCESS |
1435                                         EFI_VARIABLE_RUNTIME_ACCESS,
1436                                         size, bootorder));
1437         if (ret != EFI_SUCCESS) {
1438                 printf("Cannot set BootOrder\n");
1439                 r = CMD_RET_FAILURE;
1440         }
1441 out:
1442         free(bootorder);
1443
1444         return r;
1445 }
1446
1447 static struct cmd_tbl cmd_efidebug_boot_sub[] = {
1448         U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""),
1449         U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""),
1450         U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""),
1451         U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""),
1452         U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order,
1453                          "", ""),
1454 };
1455
1456 /**
1457  * do_efi_boot_opt() - manage UEFI load options
1458  *
1459  * @cmdtp:      Command table
1460  * @flag:       Command flag
1461  * @argc:       Number of arguments
1462  * @argv:       Argument array
1463  * Return:      CMD_RET_SUCCESS on success,
1464  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1465  *
1466  * Implement efidebug "boot" sub-command.
1467  */
1468 static int do_efi_boot_opt(struct cmd_tbl *cmdtp, int flag,
1469                            int argc, char *const argv[])
1470 {
1471         struct cmd_tbl *cp;
1472
1473         if (argc < 2)
1474                 return CMD_RET_USAGE;
1475
1476         argc--; argv++;
1477
1478         cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub,
1479                           ARRAY_SIZE(cmd_efidebug_boot_sub));
1480         if (!cp)
1481                 return CMD_RET_USAGE;
1482
1483         return cp->cmd(cmdtp, flag, argc, argv);
1484 }
1485
1486 /**
1487  * do_efi_test_bootmgr() - run simple bootmgr for test
1488  *
1489  * @cmdtp:      Command table
1490  * @flag:       Command flag
1491  * @argc:       Number of arguments
1492  * @argv:       Argument array
1493  * Return:      CMD_RET_SUCCESS on success,
1494  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1495  *
1496  * Implement efidebug "test bootmgr" sub-command.
1497  * Run simple bootmgr for test.
1498  *
1499  *     efidebug test bootmgr
1500  */
1501 static __maybe_unused int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag,
1502                                               int argc, char * const argv[])
1503 {
1504         efi_handle_t image;
1505         efi_uintn_t exit_data_size = 0;
1506         u16 *exit_data = NULL;
1507         efi_status_t ret;
1508         void *load_options = NULL;
1509
1510         ret = efi_bootmgr_load(&image, &load_options);
1511         printf("efi_bootmgr_load() returned: %ld\n", ret & ~EFI_ERROR_MASK);
1512
1513         /* We call efi_start_image() even if error for test purpose. */
1514         ret = EFI_CALL(efi_start_image(image, &exit_data_size, &exit_data));
1515         printf("efi_start_image() returned: %ld\n", ret & ~EFI_ERROR_MASK);
1516         if (ret && exit_data)
1517                 efi_free_pool(exit_data);
1518
1519         efi_restore_gd();
1520
1521         free(load_options);
1522         return CMD_RET_SUCCESS;
1523 }
1524
1525 static struct cmd_tbl cmd_efidebug_test_sub[] = {
1526 #ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
1527         U_BOOT_CMD_MKENT(bootmgr, CONFIG_SYS_MAXARGS, 1, do_efi_test_bootmgr,
1528                          "", ""),
1529 #endif
1530 };
1531
1532 /**
1533  * do_efi_test() - manage UEFI load options
1534  *
1535  * @cmdtp:      Command table
1536  * @flag:       Command flag
1537  * @argc:       Number of arguments
1538  * @argv:       Argument array
1539  * Return:      CMD_RET_SUCCESS on success,
1540  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1541  *
1542  * Implement efidebug "test" sub-command.
1543  */
1544 static int do_efi_test(struct cmd_tbl *cmdtp, int flag,
1545                        int argc, char * const argv[])
1546 {
1547         struct cmd_tbl *cp;
1548
1549         if (argc < 2)
1550                 return CMD_RET_USAGE;
1551
1552         argc--; argv++;
1553
1554         cp = find_cmd_tbl(argv[0], cmd_efidebug_test_sub,
1555                           ARRAY_SIZE(cmd_efidebug_test_sub));
1556         if (!cp)
1557                 return CMD_RET_USAGE;
1558
1559         return cp->cmd(cmdtp, flag, argc, argv);
1560 }
1561
1562 /**
1563  * do_efi_query_info() - QueryVariableInfo EFI service
1564  *
1565  * @cmdtp:      Command table
1566  * @flag:       Command flag
1567  * @argc:       Number of arguments
1568  * @argv:       Argument array
1569  * Return:      CMD_RET_SUCCESS on success,
1570  *              CMD_RET_USAGE or CMD_RET_FAILURE on failure
1571  *
1572  * Implement efidebug "test" sub-command.
1573  */
1574
1575 static int do_efi_query_info(struct cmd_tbl *cmdtp, int flag,
1576                              int argc, char * const argv[])
1577 {
1578         efi_status_t ret;
1579         u32 attr = 0;
1580         u64 max_variable_storage_size;
1581         u64 remain_variable_storage_size;
1582         u64 max_variable_size;
1583         int i;
1584
1585         for (i = 1; i < argc; i++) {
1586                 if (!strcmp(argv[i], "-bs"))
1587                         attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
1588                 else if (!strcmp(argv[i], "-rt"))
1589                         attr |= EFI_VARIABLE_RUNTIME_ACCESS;
1590                 else if (!strcmp(argv[i], "-nv"))
1591                         attr |= EFI_VARIABLE_NON_VOLATILE;
1592                 else if (!strcmp(argv[i], "-at"))
1593                         attr |=
1594                                 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1595         }
1596
1597         ret = EFI_CALL(efi_query_variable_info(attr,
1598                                                &max_variable_storage_size,
1599                                                &remain_variable_storage_size,
1600                                                &max_variable_size));
1601         if (ret != EFI_SUCCESS) {
1602                 printf("Error: Cannot query UEFI variables, r = %lu\n",
1603                        ret & ~EFI_ERROR_MASK);
1604                 return CMD_RET_FAILURE;
1605         }
1606
1607         printf("Max storage size %llu\n", max_variable_storage_size);
1608         printf("Remaining storage size %llu\n", remain_variable_storage_size);
1609         printf("Max variable size %llu\n", max_variable_size);
1610
1611         return CMD_RET_SUCCESS;
1612 }
1613
1614 static struct cmd_tbl cmd_efidebug_sub[] = {
1615         U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""),
1616 #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
1617         U_BOOT_CMD_MKENT(capsule, CONFIG_SYS_MAXARGS, 1, do_efi_capsule,
1618                          "", ""),
1619 #endif
1620         U_BOOT_CMD_MKENT(devices, CONFIG_SYS_MAXARGS, 1, do_efi_show_devices,
1621                          "", ""),
1622         U_BOOT_CMD_MKENT(drivers, CONFIG_SYS_MAXARGS, 1, do_efi_show_drivers,
1623                          "", ""),
1624         U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles,
1625                          "", ""),
1626         U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images,
1627                          "", ""),
1628         U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap,
1629                          "", ""),
1630         U_BOOT_CMD_MKENT(tables, CONFIG_SYS_MAXARGS, 1, do_efi_show_tables,
1631                          "", ""),
1632         U_BOOT_CMD_MKENT(test, CONFIG_SYS_MAXARGS, 1, do_efi_test,
1633                          "", ""),
1634         U_BOOT_CMD_MKENT(query, CONFIG_SYS_MAXARGS, 1, do_efi_query_info,
1635                          "", ""),
1636 };
1637
1638 /**
1639  * do_efidebug() - display and configure UEFI environment
1640  *
1641  * @cmdtp:      Command table
1642  * @flag:       Command flag
1643  * @argc:       Number of arguments
1644  * @argv:       Argument array
1645  * Return:      CMD_RET_SUCCESS on success,
1646  *              CMD_RET_USAGE or CMD_RET_RET_FAILURE on failure
1647  *
1648  * Implement efidebug command which allows us to display and
1649  * configure UEFI environment.
1650  */
1651 static int do_efidebug(struct cmd_tbl *cmdtp, int flag,
1652                        int argc, char *const argv[])
1653 {
1654         struct cmd_tbl *cp;
1655         efi_status_t r;
1656
1657         if (argc < 2)
1658                 return CMD_RET_USAGE;
1659
1660         argc--; argv++;
1661
1662         /* Initialize UEFI drivers */
1663         r = efi_init_obj_list();
1664         if (r != EFI_SUCCESS) {
1665                 printf("Error: Cannot initialize UEFI sub-system, r = %lu\n",
1666                        r & ~EFI_ERROR_MASK);
1667                 return CMD_RET_FAILURE;
1668         }
1669
1670         cp = find_cmd_tbl(argv[0], cmd_efidebug_sub,
1671                           ARRAY_SIZE(cmd_efidebug_sub));
1672         if (!cp)
1673                 return CMD_RET_USAGE;
1674
1675         return cp->cmd(cmdtp, flag, argc, argv);
1676 }
1677
1678 #ifdef CONFIG_SYS_LONGHELP
1679 static char efidebug_help_text[] =
1680         "  - UEFI Shell-like interface to configure UEFI environment\n"
1681         "\n"
1682         "efidebug boot add "
1683         "-b <bootid> <label> <interface> <devnum>[:<part>] <file path> "
1684         "-i <interface> <devnum>[:<part>] <initrd file path> "
1685         "-s '<optional data>'\n"
1686         "  - set UEFI BootXXXX variable\n"
1687         "    <load options> will be passed to UEFI application\n"
1688         "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n"
1689         "  - delete UEFI BootXXXX variables\n"
1690         "efidebug boot dump\n"
1691         "  - dump all UEFI BootXXXX variables\n"
1692         "efidebug boot next <bootid>\n"
1693         "  - set UEFI BootNext variable\n"
1694         "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n"
1695         "  - set/show UEFI boot order\n"
1696         "\n"
1697 #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
1698         "efidebug capsule update [-v] <capsule address>\n"
1699         "  - process a capsule\n"
1700         "efidebug capsule disk-update\n"
1701         "  - update a capsule from disk\n"
1702         "efidebug capsule show <capsule address>\n"
1703         "  - show capsule information\n"
1704         "efidebug capsule result [<capsule result var>]\n"
1705         "  - show a capsule update result\n"
1706         "\n"
1707 #endif
1708         "efidebug devices\n"
1709         "  - show UEFI devices\n"
1710         "efidebug drivers\n"
1711         "  - show UEFI drivers\n"
1712         "efidebug dh\n"
1713         "  - show UEFI handles\n"
1714         "efidebug images\n"
1715         "  - show loaded images\n"
1716         "efidebug memmap\n"
1717         "  - show UEFI memory map\n"
1718         "efidebug tables\n"
1719         "  - show UEFI configuration tables\n"
1720 #ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
1721         "efidebug test bootmgr\n"
1722         "  - run simple bootmgr for test\n"
1723 #endif
1724         "efidebug query [-nv][-bs][-rt][-at]\n"
1725         "  - show size of UEFI variables store\n";
1726 #endif
1727
1728 U_BOOT_CMD(
1729         efidebug, CONFIG_SYS_MAXARGS, 0, do_efidebug,
1730         "Configure UEFI environment",
1731         efidebug_help_text
1732 );