xref: /openbmc/u-boot/cmd/bootefi.c (revision f972dc14)
1b9939336SAlexander Graf /*
2b9939336SAlexander Graf  *  EFI application loader
3b9939336SAlexander Graf  *
4b9939336SAlexander Graf  *  Copyright (c) 2016 Alexander Graf
5b9939336SAlexander Graf  *
6b9939336SAlexander Graf  *  SPDX-License-Identifier:     GPL-2.0+
7b9939336SAlexander Graf  */
8b9939336SAlexander Graf 
9b9939336SAlexander Graf #include <common.h>
10b9939336SAlexander Graf #include <command.h>
119d922450SSimon Glass #include <dm.h>
12b9939336SAlexander Graf #include <efi_loader.h>
13b9939336SAlexander Graf #include <errno.h>
14b9939336SAlexander Graf #include <libfdt.h>
15b9939336SAlexander Graf #include <libfdt_env.h>
16ad0c1a3dSAlexander Graf #include <memalign.h>
170d9d501fSAlexander Graf #include <asm/global_data.h>
18e275458cSSimon Glass #include <asm-generic/sections.h>
19e275458cSSimon Glass #include <linux/linkage.h>
200d9d501fSAlexander Graf 
210d9d501fSAlexander Graf DECLARE_GLOBAL_DATA_PTR;
22b9939336SAlexander Graf 
237cbc1241SHeinrich Schuchardt static uint8_t efi_obj_list_initalized;
247cbc1241SHeinrich Schuchardt 
2595c5553eSRob Clark static struct efi_device_path *bootefi_image_path;
2695c5553eSRob Clark static struct efi_device_path *bootefi_device_path;
27b9939336SAlexander Graf 
287cbc1241SHeinrich Schuchardt /* Initialize and populate EFI object list */
297cbc1241SHeinrich Schuchardt static void efi_init_obj_list(void)
307cbc1241SHeinrich Schuchardt {
317cbc1241SHeinrich Schuchardt 	efi_obj_list_initalized = 1;
327cbc1241SHeinrich Schuchardt 
337cbc1241SHeinrich Schuchardt 	efi_console_register();
347cbc1241SHeinrich Schuchardt #ifdef CONFIG_PARTITIONS
357cbc1241SHeinrich Schuchardt 	efi_disk_register();
367cbc1241SHeinrich Schuchardt #endif
377cbc1241SHeinrich Schuchardt #if defined(CONFIG_LCD) || defined(CONFIG_DM_VIDEO)
387cbc1241SHeinrich Schuchardt 	efi_gop_register();
397cbc1241SHeinrich Schuchardt #endif
407cbc1241SHeinrich Schuchardt #ifdef CONFIG_NET
4195c5553eSRob Clark 	efi_net_register();
427cbc1241SHeinrich Schuchardt #endif
437cbc1241SHeinrich Schuchardt #ifdef CONFIG_GENERATE_SMBIOS_TABLE
447cbc1241SHeinrich Schuchardt 	efi_smbios_register();
457cbc1241SHeinrich Schuchardt #endif
46b3d60900SHeinrich Schuchardt 	efi_watchdog_register();
477cbc1241SHeinrich Schuchardt 
487cbc1241SHeinrich Schuchardt 	/* Initialize EFI runtime services */
497cbc1241SHeinrich Schuchardt 	efi_reset_system_init();
507cbc1241SHeinrich Schuchardt 	efi_get_time_init();
517cbc1241SHeinrich Schuchardt }
527cbc1241SHeinrich Schuchardt 
530d9d501fSAlexander Graf static void *copy_fdt(void *fdt)
540d9d501fSAlexander Graf {
550d9d501fSAlexander Graf 	u64 fdt_size = fdt_totalsize(fdt);
56ad0c1a3dSAlexander Graf 	unsigned long fdt_ram_start = -1L, fdt_pages;
57ad0c1a3dSAlexander Graf 	u64 new_fdt_addr;
580d9d501fSAlexander Graf 	void *new_fdt;
59ad0c1a3dSAlexander Graf 	int i;
600d9d501fSAlexander Graf 
61ad0c1a3dSAlexander Graf         for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
62ad0c1a3dSAlexander Graf                 u64 ram_start = gd->bd->bi_dram[i].start;
63ad0c1a3dSAlexander Graf                 u64 ram_size = gd->bd->bi_dram[i].size;
640d9d501fSAlexander Graf 
65ad0c1a3dSAlexander Graf 		if (!ram_size)
66ad0c1a3dSAlexander Graf 			continue;
67ad0c1a3dSAlexander Graf 
68ad0c1a3dSAlexander Graf 		if (ram_start < fdt_ram_start)
69ad0c1a3dSAlexander Graf 			fdt_ram_start = ram_start;
70ad0c1a3dSAlexander Graf 	}
71ad0c1a3dSAlexander Graf 
72ad0c1a3dSAlexander Graf 	/* Give us at least 4kb breathing room */
73a44bffccSxypron.glpk@gmx.de 	fdt_size = ALIGN(fdt_size + 4096, EFI_PAGE_SIZE);
74ad0c1a3dSAlexander Graf 	fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
75ad0c1a3dSAlexander Graf 
76ad0c1a3dSAlexander Graf 	/* Safe fdt location is at 128MB */
77ad0c1a3dSAlexander Graf 	new_fdt_addr = fdt_ram_start + (128 * 1024 * 1024) + fdt_size;
78ad0c1a3dSAlexander Graf 	if (efi_allocate_pages(1, EFI_BOOT_SERVICES_DATA, fdt_pages,
79ad0c1a3dSAlexander Graf 			       &new_fdt_addr) != EFI_SUCCESS) {
80ad0c1a3dSAlexander Graf 		/* If we can't put it there, put it somewhere */
81a44bffccSxypron.glpk@gmx.de 		new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size);
8285a6e9b3SAlexander Graf 		if (efi_allocate_pages(1, EFI_BOOT_SERVICES_DATA, fdt_pages,
8385a6e9b3SAlexander Graf 				       &new_fdt_addr) != EFI_SUCCESS) {
8485a6e9b3SAlexander Graf 			printf("ERROR: Failed to reserve space for FDT\n");
8585a6e9b3SAlexander Graf 			return NULL;
86ad0c1a3dSAlexander Graf 		}
8785a6e9b3SAlexander Graf 	}
8885a6e9b3SAlexander Graf 
89ad0c1a3dSAlexander Graf 	new_fdt = (void*)(ulong)new_fdt_addr;
900d9d501fSAlexander Graf 	memcpy(new_fdt, fdt, fdt_totalsize(fdt));
910d9d501fSAlexander Graf 	fdt_set_totalsize(new_fdt, fdt_size);
920d9d501fSAlexander Graf 
930d9d501fSAlexander Graf 	return new_fdt;
940d9d501fSAlexander Graf }
950d9d501fSAlexander Graf 
963eb0841bSHeinrich Schuchardt static efi_status_t efi_do_enter(
973eb0841bSHeinrich Schuchardt 			void *image_handle, struct efi_system_table *st,
98b06d8ac3Sxypron.glpk@gmx.de 			asmlinkage ulong (*entry)(void *image_handle,
99b06d8ac3Sxypron.glpk@gmx.de 						  struct efi_system_table *st))
100b06d8ac3Sxypron.glpk@gmx.de {
101b06d8ac3Sxypron.glpk@gmx.de 	efi_status_t ret = EFI_LOAD_ERROR;
102b06d8ac3Sxypron.glpk@gmx.de 
103b06d8ac3Sxypron.glpk@gmx.de 	if (entry)
104b06d8ac3Sxypron.glpk@gmx.de 		ret = entry(image_handle, st);
105b06d8ac3Sxypron.glpk@gmx.de 	st->boottime->exit(image_handle, ret, 0, NULL);
106b06d8ac3Sxypron.glpk@gmx.de 	return ret;
107b06d8ac3Sxypron.glpk@gmx.de }
108b06d8ac3Sxypron.glpk@gmx.de 
109ec6617c3SAlison Wang #ifdef CONFIG_ARM64
1103eb0841bSHeinrich Schuchardt static efi_status_t efi_run_in_el2(asmlinkage ulong (*entry)(
111b06d8ac3Sxypron.glpk@gmx.de 			void *image_handle, struct efi_system_table *st),
112b06d8ac3Sxypron.glpk@gmx.de 			void *image_handle, struct efi_system_table *st)
113ec6617c3SAlison Wang {
114ec6617c3SAlison Wang 	/* Enable caches again */
115ec6617c3SAlison Wang 	dcache_enable();
116ec6617c3SAlison Wang 
117b06d8ac3Sxypron.glpk@gmx.de 	return efi_do_enter(image_handle, st, entry);
118ec6617c3SAlison Wang }
119ec6617c3SAlison Wang #endif
120ec6617c3SAlison Wang 
121b9939336SAlexander Graf /*
122b9939336SAlexander Graf  * Load an EFI payload into a newly allocated piece of memory, register all
123b9939336SAlexander Graf  * EFI objects it would want to access and jump to it.
124b9939336SAlexander Graf  */
1253eb0841bSHeinrich Schuchardt static efi_status_t do_bootefi_exec(void *efi, void *fdt,
12695c5553eSRob Clark 				    struct efi_device_path *device_path,
12795c5553eSRob Clark 				    struct efi_device_path *image_path)
128b9939336SAlexander Graf {
12995c5553eSRob Clark 	struct efi_loaded_image loaded_image_info = {};
13095c5553eSRob Clark 	struct efi_object loaded_image_info_obj = {};
131bf19273eSRob Clark 	struct efi_device_path *memdp = NULL;
13295c5553eSRob Clark 	ulong ret;
13395c5553eSRob Clark 
134e275458cSSimon Glass 	ulong (*entry)(void *image_handle, struct efi_system_table *st)
135e275458cSSimon Glass 		asmlinkage;
136b9939336SAlexander Graf 	ulong fdt_pages, fdt_size, fdt_start, fdt_end;
137f4f9993fSAlexander Graf 	const efi_guid_t fdt_guid = EFI_FDT_GUID;
138dea2174dSAlexander Graf 	bootm_headers_t img = { 0 };
139b9939336SAlexander Graf 
140bf19273eSRob Clark 	/*
141bf19273eSRob Clark 	 * Special case for efi payload not loaded from disk, such as
142bf19273eSRob Clark 	 * 'bootefi hello' or for example payload loaded directly into
143bf19273eSRob Clark 	 * memory via jtag/etc:
144bf19273eSRob Clark 	 */
145bf19273eSRob Clark 	if (!device_path && !image_path) {
146bf19273eSRob Clark 		printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
147bf19273eSRob Clark 		/* actual addresses filled in after efi_load_pe() */
148bf19273eSRob Clark 		memdp = efi_dp_from_mem(0, 0, 0);
149bf19273eSRob Clark 		device_path = image_path = memdp;
150bf19273eSRob Clark 	} else {
151bf19273eSRob Clark 		assert(device_path && image_path);
152bf19273eSRob Clark 	}
153bf19273eSRob Clark 
15495c5553eSRob Clark 	/* Initialize and populate EFI object list */
15595c5553eSRob Clark 	if (!efi_obj_list_initalized)
15695c5553eSRob Clark 		efi_init_obj_list();
15795c5553eSRob Clark 
15895c5553eSRob Clark 	efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj,
15995c5553eSRob Clark 			       device_path, image_path);
16095c5553eSRob Clark 
161b9939336SAlexander Graf 	/*
162b9939336SAlexander Graf 	 * gd lives in a fixed register which may get clobbered while we execute
163b9939336SAlexander Graf 	 * the payload. So save it here and restore it on every callback entry
164b9939336SAlexander Graf 	 */
165b9939336SAlexander Graf 	efi_save_gd();
166b9939336SAlexander Graf 
1671c39809bSAlexander Graf 	if (fdt && !fdt_check_header(fdt)) {
168dea2174dSAlexander Graf 		/* Prepare fdt for payload */
1690d9d501fSAlexander Graf 		fdt = copy_fdt(fdt);
1700d9d501fSAlexander Graf 
1710d9d501fSAlexander Graf 		if (image_setup_libfdt(&img, fdt, 0, NULL)) {
172dea2174dSAlexander Graf 			printf("ERROR: Failed to process device tree\n");
173dea2174dSAlexander Graf 			return -EINVAL;
174dea2174dSAlexander Graf 		}
175dea2174dSAlexander Graf 
176dea2174dSAlexander Graf 		/* Link to it in the efi tables */
177f4f9993fSAlexander Graf 		efi_install_configuration_table(&fdt_guid, fdt);
178b9939336SAlexander Graf 
179b9939336SAlexander Graf 		/* And reserve the space in the memory map */
1800d9d501fSAlexander Graf 		fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK;
1810d9d501fSAlexander Graf 		fdt_end = ((ulong)fdt) + fdt_totalsize(fdt);
182b9939336SAlexander Graf 		fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK;
183b9939336SAlexander Graf 		fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
184b9939336SAlexander Graf 		/* Give a bootloader the chance to modify the device tree */
185b9939336SAlexander Graf 		fdt_pages += 2;
186b9939336SAlexander Graf 		efi_add_memory_map(fdt_start, fdt_pages,
187b9939336SAlexander Graf 				   EFI_BOOT_SERVICES_DATA, true);
188b9939336SAlexander Graf 	} else {
1891c39809bSAlexander Graf 		printf("WARNING: Invalid device tree, expect boot to fail\n");
190f4f9993fSAlexander Graf 		efi_install_configuration_table(&fdt_guid, NULL);
191b9939336SAlexander Graf 	}
192b9939336SAlexander Graf 
193b9939336SAlexander Graf 	/* Load the EFI payload */
194b9939336SAlexander Graf 	entry = efi_load_pe(efi, &loaded_image_info);
19595c5553eSRob Clark 	if (!entry) {
19695c5553eSRob Clark 		ret = -ENOENT;
19795c5553eSRob Clark 		goto exit;
19895c5553eSRob Clark 	}
19980a4800eSAlexander Graf 
200bf19273eSRob Clark 	if (memdp) {
201bf19273eSRob Clark 		struct efi_device_path_memory *mdp = (void *)memdp;
202bf19273eSRob Clark 		mdp->memory_type = loaded_image_info.image_code_type;
203bf19273eSRob Clark 		mdp->start_address = (uintptr_t)loaded_image_info.image_base;
204bf19273eSRob Clark 		mdp->end_address = mdp->start_address +
205bf19273eSRob Clark 				loaded_image_info.image_size;
206bf19273eSRob Clark 	}
207bf19273eSRob Clark 
208ad644e7cSRob Clark 	/* we don't support much: */
209ad644e7cSRob Clark 	env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported",
210ad644e7cSRob Clark 		"{ro,boot}(blob)0000000000000000");
211ad644e7cSRob Clark 
212b9939336SAlexander Graf 	/* Call our payload! */
213edcef3baSAlexander Graf 	debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
214a86aeaf2SAlexander Graf 
215a86aeaf2SAlexander Graf 	if (setjmp(&loaded_image_info.exit_jmp)) {
21695c5553eSRob Clark 		ret = loaded_image_info.exit_status;
21795c5553eSRob Clark 		goto exit;
218a86aeaf2SAlexander Graf 	}
219a86aeaf2SAlexander Graf 
22069bd459dSAlexander Graf #ifdef CONFIG_ARM64
22169bd459dSAlexander Graf 	/* On AArch64 we need to make sure we call our payload in < EL3 */
22269bd459dSAlexander Graf 	if (current_el() == 3) {
22369bd459dSAlexander Graf 		smp_kick_all_cpus();
22469bd459dSAlexander Graf 		dcache_disable();	/* flush cache before switch to EL2 */
225ec6617c3SAlison Wang 
226ec6617c3SAlison Wang 		/* Move into EL2 and keep running there */
227ec6617c3SAlison Wang 		armv8_switch_to_el2((ulong)entry, (ulong)&loaded_image_info,
2287c5e1febSAlison Wang 				    (ulong)&systab, 0, (ulong)efi_run_in_el2,
229ec6617c3SAlison Wang 				    ES_TO_AARCH64);
230ec6617c3SAlison Wang 
231ec6617c3SAlison Wang 		/* Should never reach here, efi exits with longjmp */
232ec6617c3SAlison Wang 		while (1) { }
23369bd459dSAlexander Graf 	}
23469bd459dSAlexander Graf #endif
23569bd459dSAlexander Graf 
23695c5553eSRob Clark 	ret = efi_do_enter(&loaded_image_info, &systab, entry);
23795c5553eSRob Clark 
23895c5553eSRob Clark exit:
23995c5553eSRob Clark 	/* image has returned, loaded-image obj goes *poof*: */
24095c5553eSRob Clark 	list_del(&loaded_image_info_obj.link);
24195c5553eSRob Clark 
24295c5553eSRob Clark 	return ret;
243b9939336SAlexander Graf }
244b9939336SAlexander Graf 
2459975fe96SRob Clark static int do_bootefi_bootmgr_exec(unsigned long fdt_addr)
2469975fe96SRob Clark {
2479975fe96SRob Clark 	struct efi_device_path *device_path, *file_path;
2489975fe96SRob Clark 	void *addr;
2499975fe96SRob Clark 	efi_status_t r;
2509975fe96SRob Clark 
2519975fe96SRob Clark 	/* Initialize and populate EFI object list */
2529975fe96SRob Clark 	if (!efi_obj_list_initalized)
2539975fe96SRob Clark 		efi_init_obj_list();
2549975fe96SRob Clark 
2559975fe96SRob Clark 	/*
2569975fe96SRob Clark 	 * gd lives in a fixed register which may get clobbered while we execute
2579975fe96SRob Clark 	 * the payload. So save it here and restore it on every callback entry
2589975fe96SRob Clark 	 */
2599975fe96SRob Clark 	efi_save_gd();
2609975fe96SRob Clark 
2619975fe96SRob Clark 	addr = efi_bootmgr_load(&device_path, &file_path);
2629975fe96SRob Clark 	if (!addr)
2639975fe96SRob Clark 		return 1;
2649975fe96SRob Clark 
2659975fe96SRob Clark 	printf("## Starting EFI application at %p ...\n", addr);
2669975fe96SRob Clark 	r = do_bootefi_exec(addr, (void *)fdt_addr, device_path, file_path);
2679975fe96SRob Clark 	printf("## Application terminated, r = %lu\n",
2689975fe96SRob Clark 	       r & ~EFI_ERROR_MASK);
2699975fe96SRob Clark 
2709975fe96SRob Clark 	if (r != EFI_SUCCESS)
2719975fe96SRob Clark 		return 1;
2729975fe96SRob Clark 
2739975fe96SRob Clark 	return 0;
2749975fe96SRob Clark }
2759975fe96SRob Clark 
276b9939336SAlexander Graf /* Interpreter command to boot an arbitrary EFI image from memory */
277b9939336SAlexander Graf static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
278b9939336SAlexander Graf {
2791c39809bSAlexander Graf 	char *saddr, *sfdt;
2801c39809bSAlexander Graf 	unsigned long addr, fdt_addr = 0;
2813eb0841bSHeinrich Schuchardt 	efi_status_t r;
282b9939336SAlexander Graf 
283b9939336SAlexander Graf 	if (argc < 2)
2843c1dcef6SBin Meng 		return CMD_RET_USAGE;
285c7ae3dfdSSimon Glass #ifdef CONFIG_CMD_BOOTEFI_HELLO
286c7ae3dfdSSimon Glass 	if (!strcmp(argv[1], "hello")) {
2875e44489bSHeinrich Schuchardt 		ulong size = __efi_helloworld_end - __efi_helloworld_begin;
288c7ae3dfdSSimon Glass 
28951c533fdSHeinrich Schuchardt 		saddr = env_get("loadaddr");
29051c533fdSHeinrich Schuchardt 		if (saddr)
29151c533fdSHeinrich Schuchardt 			addr = simple_strtoul(saddr, NULL, 16);
29251c533fdSHeinrich Schuchardt 		else
293c7ae3dfdSSimon Glass 			addr = CONFIG_SYS_LOAD_ADDR;
2945e44489bSHeinrich Schuchardt 		memcpy((char *)addr, __efi_helloworld_begin, size);
295c7ae3dfdSSimon Glass 	} else
296c7ae3dfdSSimon Glass #endif
297623b3a57SHeinrich Schuchardt #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
298623b3a57SHeinrich Schuchardt 	if (!strcmp(argv[1], "selftest")) {
2997aca68caSHeinrich Schuchardt 		struct efi_loaded_image loaded_image_info = {};
3007aca68caSHeinrich Schuchardt 		struct efi_object loaded_image_info_obj = {};
3017aca68caSHeinrich Schuchardt 
302*f972dc14SHeinrich Schuchardt 		/* Construct a dummy device path. */
303*f972dc14SHeinrich Schuchardt 		bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
304*f972dc14SHeinrich Schuchardt 						      (uintptr_t)&efi_selftest,
305*f972dc14SHeinrich Schuchardt 						      (uintptr_t)&efi_selftest);
306*f972dc14SHeinrich Schuchardt 		bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest");
307*f972dc14SHeinrich Schuchardt 
3087aca68caSHeinrich Schuchardt 		efi_setup_loaded_image(&loaded_image_info,
3097aca68caSHeinrich Schuchardt 				       &loaded_image_info_obj,
3107aca68caSHeinrich Schuchardt 				       bootefi_device_path, bootefi_image_path);
311623b3a57SHeinrich Schuchardt 		/*
312623b3a57SHeinrich Schuchardt 		 * gd lives in a fixed register which may get clobbered while we
313623b3a57SHeinrich Schuchardt 		 * execute the payload. So save it here and restore it on every
314623b3a57SHeinrich Schuchardt 		 * callback entry
315623b3a57SHeinrich Schuchardt 		 */
316623b3a57SHeinrich Schuchardt 		efi_save_gd();
317623b3a57SHeinrich Schuchardt 		/* Initialize and populate EFI object list */
318623b3a57SHeinrich Schuchardt 		if (!efi_obj_list_initalized)
319623b3a57SHeinrich Schuchardt 			efi_init_obj_list();
320623b3a57SHeinrich Schuchardt 		return efi_selftest(&loaded_image_info, &systab);
321623b3a57SHeinrich Schuchardt 	} else
322623b3a57SHeinrich Schuchardt #endif
3239975fe96SRob Clark 	if (!strcmp(argv[1], "bootmgr")) {
3249975fe96SRob Clark 		unsigned long fdt_addr = 0;
3259975fe96SRob Clark 
3269975fe96SRob Clark 		if (argc > 2)
3279975fe96SRob Clark 			fdt_addr = simple_strtoul(argv[2], NULL, 16);
3289975fe96SRob Clark 
3299975fe96SRob Clark 		return do_bootefi_bootmgr_exec(fdt_addr);
3309975fe96SRob Clark 	} else {
331b9939336SAlexander Graf 		saddr = argv[1];
332b9939336SAlexander Graf 
333b9939336SAlexander Graf 		addr = simple_strtoul(saddr, NULL, 16);
334b9939336SAlexander Graf 
3351c39809bSAlexander Graf 		if (argc > 2) {
3361c39809bSAlexander Graf 			sfdt = argv[2];
3371c39809bSAlexander Graf 			fdt_addr = simple_strtoul(sfdt, NULL, 16);
3381c39809bSAlexander Graf 		}
339c7ae3dfdSSimon Glass 	}
3401c39809bSAlexander Graf 
3415ee31bafSSimon Glass 	printf("## Starting EFI application at %08lx ...\n", addr);
34295c5553eSRob Clark 	r = do_bootefi_exec((void *)addr, (void *)fdt_addr,
34395c5553eSRob Clark 			    bootefi_device_path, bootefi_image_path);
3441da1bac4Sxypron.glpk@gmx.de 	printf("## Application terminated, r = %lu\n",
3451da1bac4Sxypron.glpk@gmx.de 	       r & ~EFI_ERROR_MASK);
346b9939336SAlexander Graf 
3471da1bac4Sxypron.glpk@gmx.de 	if (r != EFI_SUCCESS)
3481da1bac4Sxypron.glpk@gmx.de 		return 1;
3491da1bac4Sxypron.glpk@gmx.de 	else
3501da1bac4Sxypron.glpk@gmx.de 		return 0;
351b9939336SAlexander Graf }
352b9939336SAlexander Graf 
353b9939336SAlexander Graf #ifdef CONFIG_SYS_LONGHELP
354b9939336SAlexander Graf static char bootefi_help_text[] =
3551c39809bSAlexander Graf 	"<image address> [fdt address]\n"
3561c39809bSAlexander Graf 	"  - boot EFI payload stored at address <image address>.\n"
3571c39809bSAlexander Graf 	"    If specified, the device tree located at <fdt address> gets\n"
358c7ae3dfdSSimon Glass 	"    exposed as EFI configuration table.\n"
359c7ae3dfdSSimon Glass #ifdef CONFIG_CMD_BOOTEFI_HELLO
360623b3a57SHeinrich Schuchardt 	"bootefi hello\n"
361623b3a57SHeinrich Schuchardt 	"  - boot a sample Hello World application stored within U-Boot\n"
362623b3a57SHeinrich Schuchardt #endif
363623b3a57SHeinrich Schuchardt #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
364623b3a57SHeinrich Schuchardt 	"bootefi selftest\n"
365623b3a57SHeinrich Schuchardt 	"  - boot an EFI selftest application stored within U-Boot\n"
366c7ae3dfdSSimon Glass #endif
3679975fe96SRob Clark 	"bootmgr [fdt addr]\n"
3689975fe96SRob Clark 	"  - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
3699975fe96SRob Clark 	"\n"
3709975fe96SRob Clark 	"    If specified, the device tree located at <fdt address> gets\n"
3719975fe96SRob Clark 	"    exposed as EFI configuration table.\n";
372b9939336SAlexander Graf #endif
373b9939336SAlexander Graf 
374b9939336SAlexander Graf U_BOOT_CMD(
3751c39809bSAlexander Graf 	bootefi, 3, 0, do_bootefi,
37692dfd922SSergey Kubushyn 	"Boots an EFI payload from memory",
377b9939336SAlexander Graf 	bootefi_help_text
378b9939336SAlexander Graf );
3790f4060ebSAlexander Graf 
38095c5553eSRob Clark static int parse_partnum(const char *devnr)
38195c5553eSRob Clark {
38295c5553eSRob Clark 	const char *str = strchr(devnr, ':');
38395c5553eSRob Clark 	if (str) {
38495c5553eSRob Clark 		str++;
38595c5553eSRob Clark 		return simple_strtoul(str, NULL, 16);
38695c5553eSRob Clark 	}
38795c5553eSRob Clark 	return 0;
38895c5553eSRob Clark }
38995c5553eSRob Clark 
390c07ad7c0SAlexander Graf void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
3910f4060ebSAlexander Graf {
39295c5553eSRob Clark 	char filename[32] = { 0 }; /* dp->str is u16[32] long */
39395c5553eSRob Clark 	char *s;
3940f4060ebSAlexander Graf 
39595c5553eSRob Clark 	if (strcmp(dev, "Net")) {
39695c5553eSRob Clark 		struct blk_desc *desc;
39795c5553eSRob Clark 		int part;
39895c5553eSRob Clark 
399f9d334bdSAlexander Graf 		desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10));
40095c5553eSRob Clark 		part = parse_partnum(devnr);
401f9d334bdSAlexander Graf 
40295c5553eSRob Clark 		bootefi_device_path = efi_dp_from_part(desc, part);
40395c5553eSRob Clark 	} else {
40495c5553eSRob Clark #ifdef CONFIG_NET
40595c5553eSRob Clark 		bootefi_device_path = efi_dp_from_eth();
406f9d334bdSAlexander Graf #endif
407f9d334bdSAlexander Graf 	}
408f9d334bdSAlexander Graf 
4099975fe96SRob Clark 	if (!path)
4109975fe96SRob Clark 		return;
4119975fe96SRob Clark 
41249271666SAlexander Graf 	if (strcmp(dev, "Net")) {
41349271666SAlexander Graf 		/* Add leading / to fs paths, because they're absolute */
41495c5553eSRob Clark 		snprintf(filename, sizeof(filename), "/%s", path);
41549271666SAlexander Graf 	} else {
41695c5553eSRob Clark 		snprintf(filename, sizeof(filename), "%s", path);
41749271666SAlexander Graf 	}
4183e433e96SRob Clark 	/* DOS style file path: */
41995c5553eSRob Clark 	s = filename;
4203e433e96SRob Clark 	while ((s = strchr(s, '/')))
4213e433e96SRob Clark 		*s++ = '\\';
42295c5553eSRob Clark 	bootefi_image_path = efi_dp_from_file(NULL, 0, filename);
4230f4060ebSAlexander Graf }
424