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