xref: /openbmc/u-boot/cmd/bootefi.c (revision 79276eb2)
1f739fcd8STom Rini // SPDX-License-Identifier: GPL-2.0+
2b9939336SAlexander Graf /*
3b9939336SAlexander Graf  *  EFI application loader
4b9939336SAlexander Graf  *
5b9939336SAlexander Graf  *  Copyright (c) 2016 Alexander Graf
6b9939336SAlexander Graf  */
7b9939336SAlexander Graf 
8d78e40d6SHeinrich Schuchardt #include <charset.h>
9b9939336SAlexander Graf #include <common.h>
10b9939336SAlexander Graf #include <command.h>
119d922450SSimon Glass #include <dm.h>
12b9939336SAlexander Graf #include <efi_loader.h>
13d78e40d6SHeinrich Schuchardt #include <efi_selftest.h>
14b9939336SAlexander Graf #include <errno.h>
15b08c8c48SMasahiro Yamada #include <linux/libfdt.h>
16b08c8c48SMasahiro Yamada #include <linux/libfdt_env.h>
17354264b3SAlexander Graf #include <mapmem.h>
18ad0c1a3dSAlexander Graf #include <memalign.h>
190d9d501fSAlexander Graf #include <asm/global_data.h>
20e275458cSSimon Glass #include <asm-generic/sections.h>
21c3b11deaSHeinrich Schuchardt #include <asm-generic/unaligned.h>
22e275458cSSimon Glass #include <linux/linkage.h>
230d9d501fSAlexander Graf 
24dc500c36SMark Kettenis #ifdef CONFIG_ARMV7_NONSEC
25dc500c36SMark Kettenis #include <asm/armv7.h>
26dc500c36SMark Kettenis #include <asm/secure.h>
27dc500c36SMark Kettenis #endif
28dc500c36SMark Kettenis 
290d9d501fSAlexander Graf DECLARE_GLOBAL_DATA_PTR;
30b9939336SAlexander Graf 
31fc225e60SHeinrich Schuchardt #define OBJ_LIST_NOT_INITIALIZED 1
32fc225e60SHeinrich Schuchardt 
33fc225e60SHeinrich Schuchardt static efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED;
347cbc1241SHeinrich Schuchardt 
3595c5553eSRob Clark static struct efi_device_path *bootefi_image_path;
3695c5553eSRob Clark static struct efi_device_path *bootefi_device_path;
37b9939336SAlexander Graf 
387cbc1241SHeinrich Schuchardt /* Initialize and populate EFI object list */
39fc225e60SHeinrich Schuchardt efi_status_t efi_init_obj_list(void)
407cbc1241SHeinrich Schuchardt {
41fc225e60SHeinrich Schuchardt 	efi_status_t ret = EFI_SUCCESS;
42fc225e60SHeinrich Schuchardt 
43098a6cddSHeinrich Schuchardt 	/* Initialize once only */
44fc225e60SHeinrich Schuchardt 	if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
45fc225e60SHeinrich Schuchardt 		return efi_obj_list_initialized;
467cbc1241SHeinrich Schuchardt 
47640adadfSHeinrich Schuchardt 	/* Initialize system table */
48640adadfSHeinrich Schuchardt 	ret = efi_initialize_system_table();
49640adadfSHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
50640adadfSHeinrich Schuchardt 		goto out;
51640adadfSHeinrich Schuchardt 
5205ef48a2SHeinrich Schuchardt 	/* Initialize EFI driver uclass */
53fc225e60SHeinrich Schuchardt 	ret = efi_driver_init();
54fc225e60SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
55fc225e60SHeinrich Schuchardt 		goto out;
5605ef48a2SHeinrich Schuchardt 
57fc225e60SHeinrich Schuchardt 	ret = efi_console_register();
58fc225e60SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
59fc225e60SHeinrich Schuchardt 		goto out;
607cbc1241SHeinrich Schuchardt #ifdef CONFIG_PARTITIONS
61fc225e60SHeinrich Schuchardt 	ret = efi_disk_register();
62fc225e60SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
63fc225e60SHeinrich Schuchardt 		goto out;
647cbc1241SHeinrich Schuchardt #endif
657cbc1241SHeinrich Schuchardt #if defined(CONFIG_LCD) || defined(CONFIG_DM_VIDEO)
66fc225e60SHeinrich Schuchardt 	ret = efi_gop_register();
67fc225e60SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
68fc225e60SHeinrich Schuchardt 		goto out;
697cbc1241SHeinrich Schuchardt #endif
70092f2f35SJoe Hershberger #ifdef CONFIG_NET
71fc225e60SHeinrich Schuchardt 	ret = efi_net_register();
72fc225e60SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
73fc225e60SHeinrich Schuchardt 		goto out;
747cbc1241SHeinrich Schuchardt #endif
7586df34d4SBin Meng #ifdef CONFIG_GENERATE_ACPI_TABLE
7686df34d4SBin Meng 	ret = efi_acpi_register();
7786df34d4SBin Meng 	if (ret != EFI_SUCCESS)
7886df34d4SBin Meng 		goto out;
7986df34d4SBin Meng #endif
807cbc1241SHeinrich Schuchardt #ifdef CONFIG_GENERATE_SMBIOS_TABLE
81fc225e60SHeinrich Schuchardt 	ret = efi_smbios_register();
82fc225e60SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
83fc225e60SHeinrich Schuchardt 		goto out;
847cbc1241SHeinrich Schuchardt #endif
85fc225e60SHeinrich Schuchardt 	ret = efi_watchdog_register();
86fc225e60SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
87fc225e60SHeinrich Schuchardt 		goto out;
887cbc1241SHeinrich Schuchardt 
897cbc1241SHeinrich Schuchardt 	/* Initialize EFI runtime services */
90fc225e60SHeinrich Schuchardt 	ret = efi_reset_system_init();
91fc225e60SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
92fc225e60SHeinrich Schuchardt 		goto out;
93fc225e60SHeinrich Schuchardt 
94fc225e60SHeinrich Schuchardt out:
95fc225e60SHeinrich Schuchardt 	efi_obj_list_initialized = ret;
96fc225e60SHeinrich Schuchardt 	return ret;
977cbc1241SHeinrich Schuchardt }
987cbc1241SHeinrich Schuchardt 
99d78e40d6SHeinrich Schuchardt /*
100c3b11deaSHeinrich Schuchardt  * Allow unaligned memory access.
101c3b11deaSHeinrich Schuchardt  *
102c3b11deaSHeinrich Schuchardt  * This routine is overridden by architectures providing this feature.
103c3b11deaSHeinrich Schuchardt  */
104c3b11deaSHeinrich Schuchardt void __weak allow_unaligned(void)
105c3b11deaSHeinrich Schuchardt {
106c3b11deaSHeinrich Schuchardt }
107c3b11deaSHeinrich Schuchardt 
108c3b11deaSHeinrich Schuchardt /*
109d78e40d6SHeinrich Schuchardt  * Set the load options of an image from an environment variable.
110d78e40d6SHeinrich Schuchardt  *
111d78e40d6SHeinrich Schuchardt  * @loaded_image_info:	the image
112d78e40d6SHeinrich Schuchardt  * @env_var:		name of the environment variable
113d78e40d6SHeinrich Schuchardt  */
114d78e40d6SHeinrich Schuchardt static void set_load_options(struct efi_loaded_image *loaded_image_info,
115d78e40d6SHeinrich Schuchardt 			     const char *env_var)
116d78e40d6SHeinrich Schuchardt {
117d78e40d6SHeinrich Schuchardt 	size_t size;
118d78e40d6SHeinrich Schuchardt 	const char *env = env_get(env_var);
1197086a71aSHeinrich Schuchardt 	u16 *pos;
120d78e40d6SHeinrich Schuchardt 
121d78e40d6SHeinrich Schuchardt 	loaded_image_info->load_options = NULL;
122d78e40d6SHeinrich Schuchardt 	loaded_image_info->load_options_size = 0;
123d78e40d6SHeinrich Schuchardt 	if (!env)
124d78e40d6SHeinrich Schuchardt 		return;
1257086a71aSHeinrich Schuchardt 	size = utf8_utf16_strlen(env) + 1;
126d78e40d6SHeinrich Schuchardt 	loaded_image_info->load_options = calloc(size, sizeof(u16));
127d78e40d6SHeinrich Schuchardt 	if (!loaded_image_info->load_options) {
128d78e40d6SHeinrich Schuchardt 		printf("ERROR: Out of memory\n");
129d78e40d6SHeinrich Schuchardt 		return;
130d78e40d6SHeinrich Schuchardt 	}
1317086a71aSHeinrich Schuchardt 	pos = loaded_image_info->load_options;
1327086a71aSHeinrich Schuchardt 	utf8_utf16_strcpy(&pos, env);
133d78e40d6SHeinrich Schuchardt 	loaded_image_info->load_options_size = size * 2;
134d78e40d6SHeinrich Schuchardt }
135d78e40d6SHeinrich Schuchardt 
1369dff4900SSimon Glass /**
1379dff4900SSimon Glass  * copy_fdt() - Copy the device tree to a new location available to EFI
1389dff4900SSimon Glass  *
1399dff4900SSimon Glass  * The FDT is relocated into a suitable location within the EFI memory map.
1409dff4900SSimon Glass  * An additional 12KB is added to the space in case the device tree needs to be
1419dff4900SSimon Glass  * expanded later with fdt_open_into().
1429dff4900SSimon Glass  *
1439dff4900SSimon Glass  * @fdt_addr: On entry, address of start of FDT. On exit, address of relocated
1449dff4900SSimon Glass  *	FDT start
1459dff4900SSimon Glass  * @fdt_sizep: Returns new size of FDT, including
1469dff4900SSimon Glass  * @return new relocated address of FDT
1479dff4900SSimon Glass  */
1489dff4900SSimon Glass static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
1490d9d501fSAlexander Graf {
150ad0c1a3dSAlexander Graf 	unsigned long fdt_ram_start = -1L, fdt_pages;
1519dff4900SSimon Glass 	efi_status_t ret = 0;
1529dff4900SSimon Glass 	void *fdt, *new_fdt;
153ad0c1a3dSAlexander Graf 	u64 new_fdt_addr;
1549dff4900SSimon Glass 	uint fdt_size;
155ad0c1a3dSAlexander Graf 	int i;
1560d9d501fSAlexander Graf 
157ad0c1a3dSAlexander Graf 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
158ad0c1a3dSAlexander Graf 		u64 ram_start = gd->bd->bi_dram[i].start;
159ad0c1a3dSAlexander Graf 		u64 ram_size = gd->bd->bi_dram[i].size;
1600d9d501fSAlexander Graf 
161ad0c1a3dSAlexander Graf 		if (!ram_size)
162ad0c1a3dSAlexander Graf 			continue;
163ad0c1a3dSAlexander Graf 
164ad0c1a3dSAlexander Graf 		if (ram_start < fdt_ram_start)
165ad0c1a3dSAlexander Graf 			fdt_ram_start = ram_start;
166ad0c1a3dSAlexander Graf 	}
167ad0c1a3dSAlexander Graf 
168bc9a638aSSimon Glass 	/*
169bc9a638aSSimon Glass 	 * Give us at least 4KB of breathing room in case the device tree needs
170bc9a638aSSimon Glass 	 * to be expanded later. Round up to the nearest EFI page boundary.
171bc9a638aSSimon Glass 	 */
1729dff4900SSimon Glass 	fdt = map_sysmem(*fdt_addrp, 0);
1739dff4900SSimon Glass 	fdt_size = fdt_totalsize(fdt);
1749dff4900SSimon Glass 	fdt_size += 4096 * 3;
175bc9a638aSSimon Glass 	fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE);
176ad0c1a3dSAlexander Graf 	fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
177ad0c1a3dSAlexander Graf 
178baf70c02SSimon Glass 	/* Safe fdt location is at 127MB */
179baf70c02SSimon Glass 	new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size;
1809dff4900SSimon Glass 	ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
181e09159c8SHeinrich Schuchardt 				 EFI_RUNTIME_SERVICES_DATA, fdt_pages,
1829dff4900SSimon Glass 				 &new_fdt_addr);
1839dff4900SSimon Glass 	if (ret != EFI_SUCCESS) {
184ad0c1a3dSAlexander Graf 		/* If we can't put it there, put it somewhere */
185a44bffccSxypron.glpk@gmx.de 		new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size);
1869dff4900SSimon Glass 		ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
187e09159c8SHeinrich Schuchardt 					 EFI_RUNTIME_SERVICES_DATA, fdt_pages,
1889dff4900SSimon Glass 					 &new_fdt_addr);
1899dff4900SSimon Glass 		if (ret != EFI_SUCCESS) {
19085a6e9b3SAlexander Graf 			printf("ERROR: Failed to reserve space for FDT\n");
1919dff4900SSimon Glass 			goto done;
192ad0c1a3dSAlexander Graf 		}
19385a6e9b3SAlexander Graf 	}
19485a6e9b3SAlexander Graf 
1959dff4900SSimon Glass 	new_fdt = map_sysmem(new_fdt_addr, fdt_size);
1960d9d501fSAlexander Graf 	memcpy(new_fdt, fdt, fdt_totalsize(fdt));
1970d9d501fSAlexander Graf 	fdt_set_totalsize(new_fdt, fdt_size);
1980d9d501fSAlexander Graf 
1999dff4900SSimon Glass 	*fdt_addrp = new_fdt_addr;
2009dff4900SSimon Glass 	*fdt_sizep = fdt_size;
2019dff4900SSimon Glass done:
2029dff4900SSimon Glass 	return ret;
2030d9d501fSAlexander Graf }
2040d9d501fSAlexander Graf 
2053eb0841bSHeinrich Schuchardt static efi_status_t efi_do_enter(
2062074f700SHeinrich Schuchardt 			efi_handle_t image_handle, struct efi_system_table *st,
207c6fa5df6SAlexander Graf 			EFIAPI efi_status_t (*entry)(
208c6fa5df6SAlexander Graf 				efi_handle_t image_handle,
209b06d8ac3Sxypron.glpk@gmx.de 				struct efi_system_table *st))
210b06d8ac3Sxypron.glpk@gmx.de {
211b06d8ac3Sxypron.glpk@gmx.de 	efi_status_t ret = EFI_LOAD_ERROR;
212b06d8ac3Sxypron.glpk@gmx.de 
213b06d8ac3Sxypron.glpk@gmx.de 	if (entry)
214b06d8ac3Sxypron.glpk@gmx.de 		ret = entry(image_handle, st);
215b06d8ac3Sxypron.glpk@gmx.de 	st->boottime->exit(image_handle, ret, 0, NULL);
216b06d8ac3Sxypron.glpk@gmx.de 	return ret;
217b06d8ac3Sxypron.glpk@gmx.de }
218b06d8ac3Sxypron.glpk@gmx.de 
219ec6617c3SAlison Wang #ifdef CONFIG_ARM64
220c6fa5df6SAlexander Graf static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)(
2212074f700SHeinrich Schuchardt 			efi_handle_t image_handle, struct efi_system_table *st),
2222074f700SHeinrich Schuchardt 			efi_handle_t image_handle, struct efi_system_table *st)
223ec6617c3SAlison Wang {
224ec6617c3SAlison Wang 	/* Enable caches again */
225ec6617c3SAlison Wang 	dcache_enable();
226ec6617c3SAlison Wang 
227b06d8ac3Sxypron.glpk@gmx.de 	return efi_do_enter(image_handle, st, entry);
228ec6617c3SAlison Wang }
229ec6617c3SAlison Wang #endif
230ec6617c3SAlison Wang 
231dc500c36SMark Kettenis #ifdef CONFIG_ARMV7_NONSEC
232f17f2001SMark Kettenis static bool is_nonsec;
233f17f2001SMark Kettenis 
234dc500c36SMark Kettenis static efi_status_t efi_run_in_hyp(EFIAPI efi_status_t (*entry)(
235dc500c36SMark Kettenis 			efi_handle_t image_handle, struct efi_system_table *st),
236dc500c36SMark Kettenis 			efi_handle_t image_handle, struct efi_system_table *st)
237dc500c36SMark Kettenis {
238dc500c36SMark Kettenis 	/* Enable caches again */
239dc500c36SMark Kettenis 	dcache_enable();
240dc500c36SMark Kettenis 
241f17f2001SMark Kettenis 	is_nonsec = true;
242f17f2001SMark Kettenis 
243dc500c36SMark Kettenis 	return efi_do_enter(image_handle, st, entry);
244dc500c36SMark Kettenis }
245dc500c36SMark Kettenis #endif
246dc500c36SMark Kettenis 
247416e07e2SSimon Glass /*
248416e07e2SSimon Glass  * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
249416e07e2SSimon Glass  *
250416e07e2SSimon Glass  * The mem_rsv entries of the FDT are added to the memory map. Any failures are
251416e07e2SSimon Glass  * ignored because this is not critical and we would rather continue to try to
252416e07e2SSimon Glass  * boot.
253416e07e2SSimon Glass  *
254416e07e2SSimon Glass  * @fdt: Pointer to device tree
255416e07e2SSimon Glass  */
256416e07e2SSimon Glass static void efi_carve_out_dt_rsv(void *fdt)
257806d2fa8SAlexander Graf {
258806d2fa8SAlexander Graf 	int nr_rsv, i;
259806d2fa8SAlexander Graf 	uint64_t addr, size, pages;
260806d2fa8SAlexander Graf 
261806d2fa8SAlexander Graf 	nr_rsv = fdt_num_mem_rsv(fdt);
262806d2fa8SAlexander Graf 
263806d2fa8SAlexander Graf 	/* Look for an existing entry and add it to the efi mem map. */
264806d2fa8SAlexander Graf 	for (i = 0; i < nr_rsv; i++) {
265806d2fa8SAlexander Graf 		if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
266806d2fa8SAlexander Graf 			continue;
267806d2fa8SAlexander Graf 
268806d2fa8SAlexander Graf 		pages = ALIGN(size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT;
269416e07e2SSimon Glass 		if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
270416e07e2SSimon Glass 					false))
271416e07e2SSimon Glass 			printf("FDT memrsv map %d: Failed to add to map\n", i);
272806d2fa8SAlexander Graf 	}
273806d2fa8SAlexander Graf }
274806d2fa8SAlexander Graf 
2759dff4900SSimon Glass static efi_status_t efi_install_fdt(ulong fdt_addr)
276bc4f9133SHeinrich Schuchardt {
277bc4f9133SHeinrich Schuchardt 	bootm_headers_t img = { 0 };
2789dff4900SSimon Glass 	ulong fdt_pages, fdt_size, fdt_start;
279bc4f9133SHeinrich Schuchardt 	efi_status_t ret;
2809dff4900SSimon Glass 	void *fdt;
281bc4f9133SHeinrich Schuchardt 
2829dff4900SSimon Glass 	fdt = map_sysmem(fdt_addr, 0);
283bc4f9133SHeinrich Schuchardt 	if (fdt_check_header(fdt)) {
284bc4f9133SHeinrich Schuchardt 		printf("ERROR: invalid device tree\n");
285bc4f9133SHeinrich Schuchardt 		return EFI_INVALID_PARAMETER;
286bc4f9133SHeinrich Schuchardt 	}
287bc4f9133SHeinrich Schuchardt 
288bc4f9133SHeinrich Schuchardt 	/* Prepare fdt for payload */
2899dff4900SSimon Glass 	ret = copy_fdt(&fdt_addr, &fdt_size);
2909dff4900SSimon Glass 	if (ret)
2919dff4900SSimon Glass 		return ret;
292bc4f9133SHeinrich Schuchardt 
2939dff4900SSimon Glass 	unmap_sysmem(fdt);
2949dff4900SSimon Glass 	fdt = map_sysmem(fdt_addr, 0);
2959dff4900SSimon Glass 	fdt_size = fdt_totalsize(fdt);
296bc4f9133SHeinrich Schuchardt 	if (image_setup_libfdt(&img, fdt, 0, NULL)) {
297bc4f9133SHeinrich Schuchardt 		printf("ERROR: failed to process device tree\n");
298bc4f9133SHeinrich Schuchardt 		return EFI_LOAD_ERROR;
299bc4f9133SHeinrich Schuchardt 	}
300bc4f9133SHeinrich Schuchardt 
301416e07e2SSimon Glass 	efi_carve_out_dt_rsv(fdt);
302806d2fa8SAlexander Graf 
303bc4f9133SHeinrich Schuchardt 	/* Link to it in the efi tables */
304bc4f9133SHeinrich Schuchardt 	ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
305bc4f9133SHeinrich Schuchardt 	if (ret != EFI_SUCCESS)
306bc4f9133SHeinrich Schuchardt 		return EFI_OUT_OF_RESOURCES;
307bc4f9133SHeinrich Schuchardt 
308bc4f9133SHeinrich Schuchardt 	/* And reserve the space in the memory map */
3099dff4900SSimon Glass 	fdt_start = fdt_addr;
310bc4f9133SHeinrich Schuchardt 	fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
3119dff4900SSimon Glass 
312bc4f9133SHeinrich Schuchardt 	ret = efi_add_memory_map(fdt_start, fdt_pages,
313bc4f9133SHeinrich Schuchardt 				 EFI_BOOT_SERVICES_DATA, true);
3149dff4900SSimon Glass 
315bc4f9133SHeinrich Schuchardt 	return ret;
316bc4f9133SHeinrich Schuchardt }
317bc4f9133SHeinrich Schuchardt 
318b9939336SAlexander Graf /*
319b9939336SAlexander Graf  * Load an EFI payload into a newly allocated piece of memory, register all
320b9939336SAlexander Graf  * EFI objects it would want to access and jump to it.
321b9939336SAlexander Graf  */
322bc4f9133SHeinrich Schuchardt static efi_status_t do_bootefi_exec(void *efi,
32395c5553eSRob Clark 				    struct efi_device_path *device_path,
32495c5553eSRob Clark 				    struct efi_device_path *image_path)
325b9939336SAlexander Graf {
32695c5553eSRob Clark 	struct efi_loaded_image loaded_image_info = {};
32795c5553eSRob Clark 	struct efi_object loaded_image_info_obj = {};
3288887acc6SHeinrich Schuchardt 	efi_handle_t mem_handle = NULL;
329bf19273eSRob Clark 	struct efi_device_path *memdp = NULL;
33045204b10SHeinrich Schuchardt 	efi_status_t ret;
33195c5553eSRob Clark 
332c6fa5df6SAlexander Graf 	EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
333c6fa5df6SAlexander Graf 				     struct efi_system_table *st);
334b9939336SAlexander Graf 
335bf19273eSRob Clark 	/*
336bf19273eSRob Clark 	 * Special case for efi payload not loaded from disk, such as
337bf19273eSRob Clark 	 * 'bootefi hello' or for example payload loaded directly into
3388887acc6SHeinrich Schuchardt 	 * memory via jtag, etc:
339bf19273eSRob Clark 	 */
340bf19273eSRob Clark 	if (!device_path && !image_path) {
341bf19273eSRob Clark 		printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
342bf19273eSRob Clark 		/* actual addresses filled in after efi_load_pe() */
343bf19273eSRob Clark 		memdp = efi_dp_from_mem(0, 0, 0);
344bf19273eSRob Clark 		device_path = image_path = memdp;
3458887acc6SHeinrich Schuchardt 		/*
3468887acc6SHeinrich Schuchardt 		 * Grub expects that the device path of the loaded image is
3478887acc6SHeinrich Schuchardt 		 * installed on a handle.
3488887acc6SHeinrich Schuchardt 		 */
3498887acc6SHeinrich Schuchardt 		ret = efi_create_handle(&mem_handle);
3508887acc6SHeinrich Schuchardt 		if (ret != EFI_SUCCESS)
3518887acc6SHeinrich Schuchardt 			goto exit;
3528887acc6SHeinrich Schuchardt 		ret = efi_add_protocol(mem_handle, &efi_guid_device_path,
35358bc69d2SAlexander Graf 				       device_path);
35458bc69d2SAlexander Graf 		if (ret != EFI_SUCCESS)
35558bc69d2SAlexander Graf 			goto exit;
356bf19273eSRob Clark 	} else {
357bf19273eSRob Clark 		assert(device_path && image_path);
358bf19273eSRob Clark 	}
359bf19273eSRob Clark 
36095c5553eSRob Clark 	efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj,
36195c5553eSRob Clark 			       device_path, image_path);
36295c5553eSRob Clark 
363b9939336SAlexander Graf 	/*
364b9939336SAlexander Graf 	 * gd lives in a fixed register which may get clobbered while we execute
365b9939336SAlexander Graf 	 * the payload. So save it here and restore it on every callback entry
366b9939336SAlexander Graf 	 */
367b9939336SAlexander Graf 	efi_save_gd();
368b9939336SAlexander Graf 
369b57f48a8SHeinrich Schuchardt 	/* Transfer environment variable bootargs as load options */
370b57f48a8SHeinrich Schuchardt 	set_load_options(&loaded_image_info, "bootargs");
371b9939336SAlexander Graf 	/* Load the EFI payload */
372b9939336SAlexander Graf 	entry = efi_load_pe(efi, &loaded_image_info);
37395c5553eSRob Clark 	if (!entry) {
37445204b10SHeinrich Schuchardt 		ret = EFI_LOAD_ERROR;
37595c5553eSRob Clark 		goto exit;
37695c5553eSRob Clark 	}
37780a4800eSAlexander Graf 
378bf19273eSRob Clark 	if (memdp) {
379bf19273eSRob Clark 		struct efi_device_path_memory *mdp = (void *)memdp;
380bf19273eSRob Clark 		mdp->memory_type = loaded_image_info.image_code_type;
381bf19273eSRob Clark 		mdp->start_address = (uintptr_t)loaded_image_info.image_base;
382bf19273eSRob Clark 		mdp->end_address = mdp->start_address +
383bf19273eSRob Clark 				loaded_image_info.image_size;
384bf19273eSRob Clark 	}
385bf19273eSRob Clark 
386ad644e7cSRob Clark 	/* we don't support much: */
387ad644e7cSRob Clark 	env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported",
388ad644e7cSRob Clark 		"{ro,boot}(blob)0000000000000000");
389ad644e7cSRob Clark 
390b9939336SAlexander Graf 	/* Call our payload! */
391edcef3baSAlexander Graf 	debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
392a86aeaf2SAlexander Graf 
393a86aeaf2SAlexander Graf 	if (setjmp(&loaded_image_info.exit_jmp)) {
39495c5553eSRob Clark 		ret = loaded_image_info.exit_status;
39595c5553eSRob Clark 		goto exit;
396a86aeaf2SAlexander Graf 	}
397a86aeaf2SAlexander Graf 
39869bd459dSAlexander Graf #ifdef CONFIG_ARM64
39969bd459dSAlexander Graf 	/* On AArch64 we need to make sure we call our payload in < EL3 */
40069bd459dSAlexander Graf 	if (current_el() == 3) {
40169bd459dSAlexander Graf 		smp_kick_all_cpus();
40269bd459dSAlexander Graf 		dcache_disable();	/* flush cache before switch to EL2 */
403ec6617c3SAlison Wang 
404ec6617c3SAlison Wang 		/* Move into EL2 and keep running there */
405ea54ad59SHeinrich Schuchardt 		armv8_switch_to_el2((ulong)entry,
406ea54ad59SHeinrich Schuchardt 				    (ulong)&loaded_image_info_obj.handle,
4077c5e1febSAlison Wang 				    (ulong)&systab, 0, (ulong)efi_run_in_el2,
408ec6617c3SAlison Wang 				    ES_TO_AARCH64);
409ec6617c3SAlison Wang 
410ec6617c3SAlison Wang 		/* Should never reach here, efi exits with longjmp */
411ec6617c3SAlison Wang 		while (1) { }
41269bd459dSAlexander Graf 	}
41369bd459dSAlexander Graf #endif
41469bd459dSAlexander Graf 
415dc500c36SMark Kettenis #ifdef CONFIG_ARMV7_NONSEC
416f17f2001SMark Kettenis 	if (armv7_boot_nonsec() && !is_nonsec) {
417dc500c36SMark Kettenis 		dcache_disable();	/* flush cache before switch to HYP */
418dc500c36SMark Kettenis 
419dc500c36SMark Kettenis 		armv7_init_nonsec();
420dc500c36SMark Kettenis 		secure_ram_addr(_do_nonsec_entry)(
421dc500c36SMark Kettenis 					efi_run_in_hyp,
422dc500c36SMark Kettenis 					(uintptr_t)entry,
423dc500c36SMark Kettenis 					(uintptr_t)loaded_image_info_obj.handle,
424dc500c36SMark Kettenis 					(uintptr_t)&systab);
425dc500c36SMark Kettenis 
426dc500c36SMark Kettenis 		/* Should never reach here, efi exits with longjmp */
427dc500c36SMark Kettenis 		while (1) { }
428dc500c36SMark Kettenis 	}
429dc500c36SMark Kettenis #endif
430dc500c36SMark Kettenis 
431ea54ad59SHeinrich Schuchardt 	ret = efi_do_enter(loaded_image_info_obj.handle, &systab, entry);
43295c5553eSRob Clark 
43395c5553eSRob Clark exit:
43495c5553eSRob Clark 	/* image has returned, loaded-image obj goes *poof*: */
43595c5553eSRob Clark 	list_del(&loaded_image_info_obj.link);
4368887acc6SHeinrich Schuchardt 	if (mem_handle)
4378887acc6SHeinrich Schuchardt 		efi_delete_handle(mem_handle);
43895c5553eSRob Clark 
43995c5553eSRob Clark 	return ret;
440b9939336SAlexander Graf }
441b9939336SAlexander Graf 
442bc4f9133SHeinrich Schuchardt static int do_bootefi_bootmgr_exec(void)
4439975fe96SRob Clark {
4449975fe96SRob Clark 	struct efi_device_path *device_path, *file_path;
4459975fe96SRob Clark 	void *addr;
4469975fe96SRob Clark 	efi_status_t r;
4479975fe96SRob Clark 
4489975fe96SRob Clark 	/*
4499975fe96SRob Clark 	 * gd lives in a fixed register which may get clobbered while we execute
4509975fe96SRob Clark 	 * the payload. So save it here and restore it on every callback entry
4519975fe96SRob Clark 	 */
4529975fe96SRob Clark 	efi_save_gd();
4539975fe96SRob Clark 
4549975fe96SRob Clark 	addr = efi_bootmgr_load(&device_path, &file_path);
4559975fe96SRob Clark 	if (!addr)
4569975fe96SRob Clark 		return 1;
4579975fe96SRob Clark 
4589975fe96SRob Clark 	printf("## Starting EFI application at %p ...\n", addr);
459bc4f9133SHeinrich Schuchardt 	r = do_bootefi_exec(addr, device_path, file_path);
4609975fe96SRob Clark 	printf("## Application terminated, r = %lu\n",
4619975fe96SRob Clark 	       r & ~EFI_ERROR_MASK);
4629975fe96SRob Clark 
4639975fe96SRob Clark 	if (r != EFI_SUCCESS)
4649975fe96SRob Clark 		return 1;
4659975fe96SRob Clark 
4669975fe96SRob Clark 	return 0;
4679975fe96SRob Clark }
4689975fe96SRob Clark 
469b9939336SAlexander Graf /* Interpreter command to boot an arbitrary EFI image from memory */
470b9939336SAlexander Graf static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
471b9939336SAlexander Graf {
472bc4f9133SHeinrich Schuchardt 	unsigned long addr;
473bc4f9133SHeinrich Schuchardt 	char *saddr;
4743eb0841bSHeinrich Schuchardt 	efi_status_t r;
475354264b3SAlexander Graf 	unsigned long fdt_addr;
476b9939336SAlexander Graf 
477c3b11deaSHeinrich Schuchardt 	/* Allow unaligned memory access */
478c3b11deaSHeinrich Schuchardt 	allow_unaligned();
479c3b11deaSHeinrich Schuchardt 
480fc225e60SHeinrich Schuchardt 	/* Initialize EFI drivers */
481fc225e60SHeinrich Schuchardt 	r = efi_init_obj_list();
482fc225e60SHeinrich Schuchardt 	if (r != EFI_SUCCESS) {
483fc225e60SHeinrich Schuchardt 		printf("Error: Cannot set up EFI drivers, r = %lu\n",
484fc225e60SHeinrich Schuchardt 		       r & ~EFI_ERROR_MASK);
485fc225e60SHeinrich Schuchardt 		return CMD_RET_FAILURE;
486fc225e60SHeinrich Schuchardt 	}
487fc225e60SHeinrich Schuchardt 
488b9939336SAlexander Graf 	if (argc < 2)
4893c1dcef6SBin Meng 		return CMD_RET_USAGE;
490bc4f9133SHeinrich Schuchardt 
491bc4f9133SHeinrich Schuchardt 	if (argc > 2) {
492354264b3SAlexander Graf 		fdt_addr = simple_strtoul(argv[2], NULL, 16);
493bc4f9133SHeinrich Schuchardt 		if (!fdt_addr && *argv[2] != '0')
494bc4f9133SHeinrich Schuchardt 			return CMD_RET_USAGE;
495bc4f9133SHeinrich Schuchardt 		/* Install device tree */
4969dff4900SSimon Glass 		r = efi_install_fdt(fdt_addr);
497bc4f9133SHeinrich Schuchardt 		if (r != EFI_SUCCESS) {
498bc4f9133SHeinrich Schuchardt 			printf("ERROR: failed to install device tree\n");
499bc4f9133SHeinrich Schuchardt 			return CMD_RET_FAILURE;
500bc4f9133SHeinrich Schuchardt 		}
501bc4f9133SHeinrich Schuchardt 	} else {
502bc4f9133SHeinrich Schuchardt 		/* Remove device tree. EFI_NOT_FOUND can be ignored here */
503bc4f9133SHeinrich Schuchardt 		efi_install_configuration_table(&efi_guid_fdt, NULL);
504bc4f9133SHeinrich Schuchardt 		printf("WARNING: booting without device tree\n");
505bc4f9133SHeinrich Schuchardt 	}
506c7ae3dfdSSimon Glass #ifdef CONFIG_CMD_BOOTEFI_HELLO
507c7ae3dfdSSimon Glass 	if (!strcmp(argv[1], "hello")) {
5085e44489bSHeinrich Schuchardt 		ulong size = __efi_helloworld_end - __efi_helloworld_begin;
509c7ae3dfdSSimon Glass 
51051c533fdSHeinrich Schuchardt 		saddr = env_get("loadaddr");
51151c533fdSHeinrich Schuchardt 		if (saddr)
51251c533fdSHeinrich Schuchardt 			addr = simple_strtoul(saddr, NULL, 16);
51351c533fdSHeinrich Schuchardt 		else
514c7ae3dfdSSimon Glass 			addr = CONFIG_SYS_LOAD_ADDR;
515354264b3SAlexander Graf 		memcpy(map_sysmem(addr, size), __efi_helloworld_begin, size);
516c7ae3dfdSSimon Glass 	} else
517c7ae3dfdSSimon Glass #endif
518623b3a57SHeinrich Schuchardt #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
519623b3a57SHeinrich Schuchardt 	if (!strcmp(argv[1], "selftest")) {
5207aca68caSHeinrich Schuchardt 		struct efi_loaded_image loaded_image_info = {};
5217aca68caSHeinrich Schuchardt 		struct efi_object loaded_image_info_obj = {};
5227aca68caSHeinrich Schuchardt 
523f972dc14SHeinrich Schuchardt 		/* Construct a dummy device path. */
524f972dc14SHeinrich Schuchardt 		bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
525f972dc14SHeinrich Schuchardt 						      (uintptr_t)&efi_selftest,
526f972dc14SHeinrich Schuchardt 						      (uintptr_t)&efi_selftest);
527f972dc14SHeinrich Schuchardt 		bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest");
528f972dc14SHeinrich Schuchardt 
5297aca68caSHeinrich Schuchardt 		efi_setup_loaded_image(&loaded_image_info,
5307aca68caSHeinrich Schuchardt 				       &loaded_image_info_obj,
5317aca68caSHeinrich Schuchardt 				       bootefi_device_path, bootefi_image_path);
532623b3a57SHeinrich Schuchardt 		/*
533623b3a57SHeinrich Schuchardt 		 * gd lives in a fixed register which may get clobbered while we
534623b3a57SHeinrich Schuchardt 		 * execute the payload. So save it here and restore it on every
535623b3a57SHeinrich Schuchardt 		 * callback entry
536623b3a57SHeinrich Schuchardt 		 */
537623b3a57SHeinrich Schuchardt 		efi_save_gd();
538d78e40d6SHeinrich Schuchardt 		/* Transfer environment variable efi_selftest as load options */
539d78e40d6SHeinrich Schuchardt 		set_load_options(&loaded_image_info, "efi_selftest");
540d78e40d6SHeinrich Schuchardt 		/* Execute the test */
541ea54ad59SHeinrich Schuchardt 		r = efi_selftest(loaded_image_info_obj.handle, &systab);
542c2b53902SHeinrich Schuchardt 		efi_restore_gd();
543d78e40d6SHeinrich Schuchardt 		free(loaded_image_info.load_options);
544c2b53902SHeinrich Schuchardt 		list_del(&loaded_image_info_obj.link);
545c2b53902SHeinrich Schuchardt 		return r != EFI_SUCCESS;
546623b3a57SHeinrich Schuchardt 	} else
547623b3a57SHeinrich Schuchardt #endif
5489975fe96SRob Clark 	if (!strcmp(argv[1], "bootmgr")) {
549bc4f9133SHeinrich Schuchardt 		return do_bootefi_bootmgr_exec();
5509975fe96SRob Clark 	} else {
551b9939336SAlexander Graf 		saddr = argv[1];
552b9939336SAlexander Graf 
553b9939336SAlexander Graf 		addr = simple_strtoul(saddr, NULL, 16);
55449db1cb8SHeinrich Schuchardt 		/* Check that a numeric value was passed */
55549db1cb8SHeinrich Schuchardt 		if (!addr && *saddr != '0')
55649db1cb8SHeinrich Schuchardt 			return CMD_RET_USAGE;
557b9939336SAlexander Graf 
558c7ae3dfdSSimon Glass 	}
5591c39809bSAlexander Graf 
5605ee31bafSSimon Glass 	printf("## Starting EFI application at %08lx ...\n", addr);
561354264b3SAlexander Graf 	r = do_bootefi_exec(map_sysmem(addr, 0), bootefi_device_path,
562bc4f9133SHeinrich Schuchardt 			    bootefi_image_path);
5631da1bac4Sxypron.glpk@gmx.de 	printf("## Application terminated, r = %lu\n",
5641da1bac4Sxypron.glpk@gmx.de 	       r & ~EFI_ERROR_MASK);
565b9939336SAlexander Graf 
5661da1bac4Sxypron.glpk@gmx.de 	if (r != EFI_SUCCESS)
5671da1bac4Sxypron.glpk@gmx.de 		return 1;
5681da1bac4Sxypron.glpk@gmx.de 	else
5691da1bac4Sxypron.glpk@gmx.de 		return 0;
570b9939336SAlexander Graf }
571b9939336SAlexander Graf 
572b9939336SAlexander Graf #ifdef CONFIG_SYS_LONGHELP
573b9939336SAlexander Graf static char bootefi_help_text[] =
5741c39809bSAlexander Graf 	"<image address> [fdt address]\n"
5751c39809bSAlexander Graf 	"  - boot EFI payload stored at address <image address>.\n"
5761c39809bSAlexander Graf 	"    If specified, the device tree located at <fdt address> gets\n"
577c7ae3dfdSSimon Glass 	"    exposed as EFI configuration table.\n"
578c7ae3dfdSSimon Glass #ifdef CONFIG_CMD_BOOTEFI_HELLO
579623b3a57SHeinrich Schuchardt 	"bootefi hello\n"
580623b3a57SHeinrich Schuchardt 	"  - boot a sample Hello World application stored within U-Boot\n"
581623b3a57SHeinrich Schuchardt #endif
582623b3a57SHeinrich Schuchardt #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
583bc4f9133SHeinrich Schuchardt 	"bootefi selftest [fdt address]\n"
584623b3a57SHeinrich Schuchardt 	"  - boot an EFI selftest application stored within U-Boot\n"
585d78e40d6SHeinrich Schuchardt 	"    Use environment variable efi_selftest to select a single test.\n"
586d78e40d6SHeinrich Schuchardt 	"    Use 'setenv efi_selftest list' to enumerate all tests.\n"
587c7ae3dfdSSimon Glass #endif
588f623e07fSHeinrich Schuchardt 	"bootefi bootmgr [fdt addr]\n"
5899975fe96SRob Clark 	"  - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
5909975fe96SRob Clark 	"\n"
5919975fe96SRob Clark 	"    If specified, the device tree located at <fdt address> gets\n"
5929975fe96SRob Clark 	"    exposed as EFI configuration table.\n";
593b9939336SAlexander Graf #endif
594b9939336SAlexander Graf 
595b9939336SAlexander Graf U_BOOT_CMD(
5961c39809bSAlexander Graf 	bootefi, 3, 0, do_bootefi,
59792dfd922SSergey Kubushyn 	"Boots an EFI payload from memory",
598b9939336SAlexander Graf 	bootefi_help_text
599b9939336SAlexander Graf );
6000f4060ebSAlexander Graf 
601c07ad7c0SAlexander Graf void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
6020f4060ebSAlexander Graf {
60395c5553eSRob Clark 	char filename[32] = { 0 }; /* dp->str is u16[32] long */
60495c5553eSRob Clark 	char *s;
6050f4060ebSAlexander Graf 
606*79276eb2SHeinrich Schuchardt 	/* efi_set_bootdev is typically called repeatedly, recover memory */
607*79276eb2SHeinrich Schuchardt 	efi_free_pool(bootefi_device_path);
608*79276eb2SHeinrich Schuchardt 	efi_free_pool(bootefi_image_path);
609*79276eb2SHeinrich Schuchardt 	/* If blk_get_device_part_str fails, avoid duplicate free. */
610*79276eb2SHeinrich Schuchardt 	bootefi_device_path = NULL;
611*79276eb2SHeinrich Schuchardt 	bootefi_image_path = NULL;
612*79276eb2SHeinrich Schuchardt 
61395c5553eSRob Clark 	if (strcmp(dev, "Net")) {
61495c5553eSRob Clark 		struct blk_desc *desc;
6152db1eba1SHeinrich Schuchardt 		disk_partition_t fs_partition;
61695c5553eSRob Clark 		int part;
61795c5553eSRob Clark 
6182db1eba1SHeinrich Schuchardt 		part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
6192db1eba1SHeinrich Schuchardt 					       1);
6202db1eba1SHeinrich Schuchardt 		if (part < 0)
6218300be61SStefan Roese 			return;
622f9d334bdSAlexander Graf 
62395c5553eSRob Clark 		bootefi_device_path = efi_dp_from_part(desc, part);
62495c5553eSRob Clark 	} else {
625092f2f35SJoe Hershberger #ifdef CONFIG_NET
62695c5553eSRob Clark 		bootefi_device_path = efi_dp_from_eth();
627f9d334bdSAlexander Graf #endif
628f9d334bdSAlexander Graf 	}
629f9d334bdSAlexander Graf 
6309975fe96SRob Clark 	if (!path)
6319975fe96SRob Clark 		return;
6329975fe96SRob Clark 
63349271666SAlexander Graf 	if (strcmp(dev, "Net")) {
63449271666SAlexander Graf 		/* Add leading / to fs paths, because they're absolute */
63595c5553eSRob Clark 		snprintf(filename, sizeof(filename), "/%s", path);
63649271666SAlexander Graf 	} else {
63795c5553eSRob Clark 		snprintf(filename, sizeof(filename), "%s", path);
63849271666SAlexander Graf 	}
6393e433e96SRob Clark 	/* DOS style file path: */
64095c5553eSRob Clark 	s = filename;
6413e433e96SRob Clark 	while ((s = strchr(s, '/')))
6423e433e96SRob Clark 		*s++ = '\\';
64395c5553eSRob Clark 	bootefi_image_path = efi_dp_from_file(NULL, 0, filename);
6440f4060ebSAlexander Graf }
645