Blame view

cmd/bootefi.c 18.2 KB
f739fcd83   Tom Rini   SPDX: Convert a f...
1
  // SPDX-License-Identifier: GPL-2.0+
b9939336d   Alexander Graf   efi_loader: Add "...
2
3
4
5
  /*
   *  EFI application loader
   *
   *  Copyright (c) 2016 Alexander Graf
b9939336d   Alexander Graf   efi_loader: Add "...
6
7
8
   */
  
  #include <common.h>
f6c6df7eb   Heinrich Schuchardt   efi_loader: refac...
9
  #include <charset.h>
b9939336d   Alexander Graf   efi_loader: Add "...
10
  #include <command.h>
9d922450a   Simon Glass   dm: Use dm.h head...
11
  #include <dm.h>
b9939336d   Alexander Graf   efi_loader: Add "...
12
  #include <efi_loader.h>
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
13
  #include <efi_selftest.h>
7b51b576d   Simon Glass   env: Move env_get...
14
  #include <env.h>
b9939336d   Alexander Graf   efi_loader: Add "...
15
  #include <errno.h>
336d4615f   Simon Glass   dm: core: Create ...
16
  #include <malloc.h>
b08c8c487   Masahiro Yamada   libfdt: move head...
17
18
  #include <linux/libfdt.h>
  #include <linux/libfdt_env.h>
354264b31   Alexander Graf   efi_loader: Use m...
19
  #include <mapmem.h>
ad0c1a3d2   Alexander Graf   efi_loader: Put f...
20
  #include <memalign.h>
e275458c2   Simon Glass   efi: Fix missing ...
21
22
  #include <asm-generic/sections.h>
  #include <linux/linkage.h>
0d9d501f3   Alexander Graf   efi_loader: Use s...
23
24
  
  DECLARE_GLOBAL_DATA_PTR;
b9939336d   Alexander Graf   efi_loader: Add "...
25

95c5553ea   Rob Clark   efi_loader: refac...
26
27
  static struct efi_device_path *bootefi_image_path;
  static struct efi_device_path *bootefi_device_path;
b9939336d   Alexander Graf   efi_loader: Add "...
28

810371a0b   Heinrich Schuchardt   efi_loader: fix f...
29
  /**
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
30
31
   * Set the load options of an image from an environment variable.
   *
a3850e40e   Heinrich Schuchardt   efi_loader: free ...
32
33
34
35
   * @handle:		the image handle
   * @env_var:		name of the environment variable
   * @load_options:	pointer to load options (output)
   * Return:		status code
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
36
   */
a3850e40e   Heinrich Schuchardt   efi_loader: free ...
37
38
  static efi_status_t set_load_options(efi_handle_t handle, const char *env_var,
  				     u16 **load_options)
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
39
  {
defa7b8ed   AKASHI Takahiro   cmd: bootefi: rew...
40
  	struct efi_loaded_image *loaded_image_info;
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
41
42
  	size_t size;
  	const char *env = env_get(env_var);
7086a71aa   Heinrich Schuchardt   efi_loader: buffe...
43
  	u16 *pos;
defa7b8ed   AKASHI Takahiro   cmd: bootefi: rew...
44
  	efi_status_t ret;
a3850e40e   Heinrich Schuchardt   efi_loader: free ...
45
  	*load_options = NULL;
defa7b8ed   AKASHI Takahiro   cmd: bootefi: rew...
46
47
48
49
50
51
52
53
  	ret = EFI_CALL(systab.boottime->open_protocol(
  					handle,
  					&efi_guid_loaded_image,
  					(void **)&loaded_image_info,
  					efi_root, NULL,
  					EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL));
  	if (ret != EFI_SUCCESS)
  		return EFI_INVALID_PARAMETER;
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
54
55
56
57
  
  	loaded_image_info->load_options = NULL;
  	loaded_image_info->load_options_size = 0;
  	if (!env)
defa7b8ed   AKASHI Takahiro   cmd: bootefi: rew...
58
  		goto out;
7086a71aa   Heinrich Schuchardt   efi_loader: buffe...
59
  	size = utf8_utf16_strlen(env) + 1;
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
60
61
62
63
  	loaded_image_info->load_options = calloc(size, sizeof(u16));
  	if (!loaded_image_info->load_options) {
  		printf("ERROR: Out of memory
  ");
defa7b8ed   AKASHI Takahiro   cmd: bootefi: rew...
64
65
66
67
  		EFI_CALL(systab.boottime->close_protocol(handle,
  							 &efi_guid_loaded_image,
  							 efi_root, NULL));
  		return EFI_OUT_OF_RESOURCES;
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
68
  	}
7086a71aa   Heinrich Schuchardt   efi_loader: buffe...
69
  	pos = loaded_image_info->load_options;
a3850e40e   Heinrich Schuchardt   efi_loader: free ...
70
  	*load_options = pos;
7086a71aa   Heinrich Schuchardt   efi_loader: buffe...
71
  	utf8_utf16_strcpy(&pos, env);
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
72
  	loaded_image_info->load_options_size = size * 2;
defa7b8ed   AKASHI Takahiro   cmd: bootefi: rew...
73
74
75
76
77
  
  out:
  	return EFI_CALL(systab.boottime->close_protocol(handle,
  							&efi_guid_loaded_image,
  							efi_root, NULL));
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
78
  }
6182495e1   Heinrich Schuchardt   efi_loader: need ...
79
  #if !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)
9dff49008   Simon Glass   efi: sandbox: Tid...
80
81
82
  /**
   * copy_fdt() - Copy the device tree to a new location available to EFI
   *
16b615d9a   Heinrich Schuchardt   efi_loader: fix m...
83
   * The FDT is copied to a suitable location within the EFI memory map.
c3772ca1e   Heinrich Schuchardt   efi_loader: macro...
84
   * Additional 12 KiB are added to the space in case the device tree needs to be
9dff49008   Simon Glass   efi: sandbox: Tid...
85
86
   * expanded later with fdt_open_into().
   *
16b615d9a   Heinrich Schuchardt   efi_loader: fix m...
87
88
   * @fdtp:	On entry a pointer to the flattened device tree.
   *		On exit a pointer to the copy of the flattened device tree.
4574d1b3d   Heinrich Schuchardt   efi_loader: memor...
89
90
   *		FDT start
   * Return:	status code
9dff49008   Simon Glass   efi: sandbox: Tid...
91
   */
16b615d9a   Heinrich Schuchardt   efi_loader: fix m...
92
  static efi_status_t copy_fdt(void **fdtp)
0d9d501f3   Alexander Graf   efi_loader: Use s...
93
  {
ad0c1a3d2   Alexander Graf   efi_loader: Put f...
94
  	unsigned long fdt_ram_start = -1L, fdt_pages;
9dff49008   Simon Glass   efi: sandbox: Tid...
95
96
  	efi_status_t ret = 0;
  	void *fdt, *new_fdt;
ad0c1a3d2   Alexander Graf   efi_loader: Put f...
97
  	u64 new_fdt_addr;
9dff49008   Simon Glass   efi: sandbox: Tid...
98
  	uint fdt_size;
ad0c1a3d2   Alexander Graf   efi_loader: Put f...
99
  	int i;
0d9d501f3   Alexander Graf   efi_loader: Use s...
100

9dff49008   Simon Glass   efi: sandbox: Tid...
101
102
103
  	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
  		u64 ram_start = gd->bd->bi_dram[i].start;
  		u64 ram_size = gd->bd->bi_dram[i].size;
0d9d501f3   Alexander Graf   efi_loader: Use s...
104

ad0c1a3d2   Alexander Graf   efi_loader: Put f...
105
106
107
108
109
110
  		if (!ram_size)
  			continue;
  
  		if (ram_start < fdt_ram_start)
  			fdt_ram_start = ram_start;
  	}
bc9a638a1   Simon Glass   efi: Tidy up devi...
111
  	/*
c3772ca1e   Heinrich Schuchardt   efi_loader: macro...
112
113
  	 * Give us at least 12 KiB of breathing room in case the device tree
  	 * needs to be expanded later.
bc9a638a1   Simon Glass   efi: Tidy up devi...
114
  	 */
16b615d9a   Heinrich Schuchardt   efi_loader: fix m...
115
  	fdt = *fdtp;
c3772ca1e   Heinrich Schuchardt   efi_loader: macro...
116
117
  	fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
  	fdt_size = fdt_pages << EFI_PAGE_SHIFT;
ad0c1a3d2   Alexander Graf   efi_loader: Put f...
118

16b615d9a   Heinrich Schuchardt   efi_loader: fix m...
119
120
121
122
123
124
  	/*
  	 * Safe fdt location is at 127 MiB.
  	 * On the sandbox convert from the sandbox address space.
  	 */
  	new_fdt_addr = (uintptr_t)map_sysmem(fdt_ram_start + 0x7f00000 +
  					     fdt_size, 0);
9dff49008   Simon Glass   efi: sandbox: Tid...
125
  	ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
29361ec47   Ilias Apalodimas   Change FDT memory...
126
  				 EFI_BOOT_SERVICES_DATA, fdt_pages,
9dff49008   Simon Glass   efi: sandbox: Tid...
127
128
  				 &new_fdt_addr);
  	if (ret != EFI_SUCCESS) {
ad0c1a3d2   Alexander Graf   efi_loader: Put f...
129
  		/* If we can't put it there, put it somewhere */
a44bffcc9   xypron.glpk@gmx.de   efi_loader: use E...
130
  		new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size);
9dff49008   Simon Glass   efi: sandbox: Tid...
131
  		ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
29361ec47   Ilias Apalodimas   Change FDT memory...
132
  					 EFI_BOOT_SERVICES_DATA, fdt_pages,
9dff49008   Simon Glass   efi: sandbox: Tid...
133
134
  					 &new_fdt_addr);
  		if (ret != EFI_SUCCESS) {
85a6e9b3c   Alexander Graf   efi_loader: Add c...
135
136
  			printf("ERROR: Failed to reserve space for FDT
  ");
9dff49008   Simon Glass   efi: sandbox: Tid...
137
  			goto done;
85a6e9b3c   Alexander Graf   efi_loader: Add c...
138
  		}
ad0c1a3d2   Alexander Graf   efi_loader: Put f...
139
  	}
16b615d9a   Heinrich Schuchardt   efi_loader: fix m...
140
  	new_fdt = (void *)(uintptr_t)new_fdt_addr;
0d9d501f3   Alexander Graf   efi_loader: Use s...
141
142
  	memcpy(new_fdt, fdt, fdt_totalsize(fdt));
  	fdt_set_totalsize(new_fdt, fdt_size);
16b615d9a   Heinrich Schuchardt   efi_loader: fix m...
143
  	*fdtp = (void *)(uintptr_t)new_fdt_addr;
9dff49008   Simon Glass   efi: sandbox: Tid...
144
145
  done:
  	return ret;
0d9d501f3   Alexander Graf   efi_loader: Use s...
146
  }
7be64b885   Atish Patra   cmd: bootefi: Par...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  static void efi_reserve_memory(u64 addr, u64 size)
  {
  	u64 pages;
  
  	/* Convert from sandbox address space. */
  	addr = (uintptr_t)map_sysmem(addr, 0);
  	pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK));
  	addr &= ~EFI_PAGE_MASK;
  	if (efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
  			       false) != EFI_SUCCESS)
  		printf("Reserved memory mapping failed addr %llx size %llx
  ",
  		       addr, size);
  }
810371a0b   Heinrich Schuchardt   efi_loader: fix f...
161
  /**
416e07e2c   Simon Glass   efi: Drop error r...
162
163
164
165
166
167
168
169
170
   * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
   *
   * The mem_rsv entries of the FDT are added to the memory map. Any failures are
   * ignored because this is not critical and we would rather continue to try to
   * boot.
   *
   * @fdt: Pointer to device tree
   */
  static void efi_carve_out_dt_rsv(void *fdt)
806d2fa8e   Alexander Graf   efi_loader: Respe...
171
172
  {
  	int nr_rsv, i;
7be64b885   Atish Patra   cmd: bootefi: Par...
173
174
  	u64 addr, size;
  	int nodeoffset, subnode;
806d2fa8e   Alexander Graf   efi_loader: Respe...
175
176
177
178
179
180
181
  
  	nr_rsv = fdt_num_mem_rsv(fdt);
  
  	/* Look for an existing entry and add it to the efi mem map. */
  	for (i = 0; i < nr_rsv; i++) {
  		if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
  			continue;
7be64b885   Atish Patra   cmd: bootefi: Par...
182
183
  		efi_reserve_memory(addr, size);
  	}
806d2fa8e   Alexander Graf   efi_loader: Respe...
184

7be64b885   Atish Patra   cmd: bootefi: Par...
185
186
187
188
189
190
191
192
193
194
195
196
  	/* process reserved-memory */
  	nodeoffset = fdt_subnode_offset(fdt, 0, "reserved-memory");
  	if (nodeoffset >= 0) {
  		subnode = fdt_first_subnode(fdt, nodeoffset);
  		while (subnode >= 0) {
  			/* check if this subnode has a reg property */
  			addr = fdtdec_get_addr_size(fdt, subnode, "reg",
  						    (fdt_size_t *)&size);
  			/*
  			 * The /reserved-memory node may have children with
  			 * a size instead of a reg property.
  			 */
4ef2b0d55   Heinrich Schuchardt   efi_loader: only ...
197
198
  			if (addr != FDT_ADDR_T_NONE &&
  			    fdtdec_get_is_enabled(fdt, subnode))
7be64b885   Atish Patra   cmd: bootefi: Par...
199
200
201
  				efi_reserve_memory(addr, size);
  			subnode = fdt_next_subnode(fdt, subnode);
  		}
806d2fa8e   Alexander Graf   efi_loader: Respe...
202
  	}
806d2fa8e   Alexander Graf   efi_loader: Respe...
203
  }
e878e6a7d   AKASHI Takahiro   cmd: bootefi: car...
204
  /**
6182495e1   Heinrich Schuchardt   efi_loader: need ...
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
   * get_config_table() - get configuration table
   *
   * @guid:	GUID of the configuration table
   * Return:	pointer to configuration table or NULL
   */
  static void *get_config_table(const efi_guid_t *guid)
  {
  	size_t i;
  
  	for (i = 0; i < systab.nr_tables; i++) {
  		if (!guidcmp(guid, &systab.tables[i].guid))
  			return systab.tables[i].table;
  	}
  	return NULL;
  }
  
  #endif /* !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) */
  
  /**
7a597259d   Heinrich Schuchardt   efi_loader: pass ...
224
   * efi_install_fdt() - install device tree
e2d82f8b2   Heinrich Schuchardt   efi_loader: comme...
225
   *
7d4d551e7   Heinrich Schuchardt   efi_loader: fix e...
226
227
228
229
   * If fdt is not EFI_FDT_USE_INTERNAL, the device tree located at that memory
   * address will will be installed as configuration table, otherwise the device
   * tree located at the address indicated by environment variable fdt_addr or as
   * fallback fdtcontroladdr will be used.
e2d82f8b2   Heinrich Schuchardt   efi_loader: comme...
230
   *
7a597259d   Heinrich Schuchardt   efi_loader: pass ...
231
232
   * On architectures using ACPI tables device trees shall not be installed as
   * configuration table.
e2d82f8b2   Heinrich Schuchardt   efi_loader: comme...
233
   *
7d4d551e7   Heinrich Schuchardt   efi_loader: fix e...
234
   * @fdt:	address of device tree or EFI_FDT_USE_INTERNAL to use the
753aa18f1   Heinrich Schuchardt   efi_loader: use h...
235
236
237
   *		the hardware device tree as indicated by environment variable
   *		fdt_addr or as fallback the internal device tree as indicated by
   *		the environment variable fdtcontroladdr
e878e6a7d   AKASHI Takahiro   cmd: bootefi: car...
238
   * Return:	status code
e878e6a7d   AKASHI Takahiro   cmd: bootefi: car...
239
   */
f64f22325   Heinrich Schuchardt   efi_loader: expor...
240
  efi_status_t efi_install_fdt(void *fdt)
e878e6a7d   AKASHI Takahiro   cmd: bootefi: car...
241
  {
6182495e1   Heinrich Schuchardt   efi_loader: need ...
242
243
244
245
246
  	/*
  	 * The EBBR spec requires that we have either an FDT or an ACPI table
  	 * but not both.
  	 */
  #if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)
f64f22325   Heinrich Schuchardt   efi_loader: expor...
247
  	if (fdt) {
6182495e1   Heinrich Schuchardt   efi_loader: need ...
248
249
250
251
252
  		printf("ERROR: can't have ACPI table and device tree.
  ");
  		return EFI_LOAD_ERROR;
  	}
  #else
3ffc52fd2   AKASHI Takahiro   cmd: bootefi: mer...
253
  	bootm_headers_t img = { 0 };
e878e6a7d   AKASHI Takahiro   cmd: bootefi: car...
254
  	efi_status_t ret;
f64f22325   Heinrich Schuchardt   efi_loader: expor...
255
  	if (fdt == EFI_FDT_USE_INTERNAL) {
7a597259d   Heinrich Schuchardt   efi_loader: pass ...
256
  		const char *fdt_opt;
f64f22325   Heinrich Schuchardt   efi_loader: expor...
257
  		uintptr_t fdt_addr;
7a597259d   Heinrich Schuchardt   efi_loader: pass ...
258

6182495e1   Heinrich Schuchardt   efi_loader: need ...
259
260
261
  		/* Look for device tree that is already installed */
  		if (get_config_table(&efi_guid_fdt))
  			return EFI_SUCCESS;
753aa18f1   Heinrich Schuchardt   efi_loader: use h...
262
263
264
  		/* Check if there is a hardware device tree */
  		fdt_opt = env_get("fdt_addr");
  		/* Use our own device tree as fallback */
6182495e1   Heinrich Schuchardt   efi_loader: need ...
265
  		if (!fdt_opt) {
753aa18f1   Heinrich Schuchardt   efi_loader: use h...
266
267
268
269
270
271
  			fdt_opt = env_get("fdtcontroladdr");
  			if (!fdt_opt) {
  				printf("ERROR: need device tree
  ");
  				return EFI_NOT_FOUND;
  			}
6182495e1   Heinrich Schuchardt   efi_loader: need ...
272
273
274
  		}
  		fdt_addr = simple_strtoul(fdt_opt, NULL, 16);
  		if (!fdt_addr) {
753aa18f1   Heinrich Schuchardt   efi_loader: use h...
275
276
  			printf("ERROR: invalid $fdt_addr or $fdtcontroladdr
  ");
6182495e1   Heinrich Schuchardt   efi_loader: need ...
277
  			return EFI_LOAD_ERROR;
3ffc52fd2   AKASHI Takahiro   cmd: bootefi: mer...
278
  		}
f64f22325   Heinrich Schuchardt   efi_loader: expor...
279
  		fdt = map_sysmem(fdt_addr, 0);
6182495e1   Heinrich Schuchardt   efi_loader: need ...
280
  	}
3ffc52fd2   AKASHI Takahiro   cmd: bootefi: mer...
281

6182495e1   Heinrich Schuchardt   efi_loader: need ...
282
  	/* Install device tree */
6182495e1   Heinrich Schuchardt   efi_loader: need ...
283
284
285
286
287
  	if (fdt_check_header(fdt)) {
  		printf("ERROR: invalid device tree
  ");
  		return EFI_LOAD_ERROR;
  	}
3ffc52fd2   AKASHI Takahiro   cmd: bootefi: mer...
288

6182495e1   Heinrich Schuchardt   efi_loader: need ...
289
290
291
292
293
294
295
  	/* Prepare device tree for payload */
  	ret = copy_fdt(&fdt);
  	if (ret) {
  		printf("ERROR: out of memory
  ");
  		return EFI_OUT_OF_RESOURCES;
  	}
3ffc52fd2   AKASHI Takahiro   cmd: bootefi: mer...
296

6182495e1   Heinrich Schuchardt   efi_loader: need ...
297
298
299
300
301
  	if (image_setup_libfdt(&img, fdt, 0, NULL)) {
  		printf("ERROR: failed to process device tree
  ");
  		return EFI_LOAD_ERROR;
  	}
fef907b2e   Heinrich Schuchardt   efi_loader: creat...
302
303
  	/* Create memory reservations as indicated by the device tree */
  	efi_carve_out_dt_rsv(fdt);
6182495e1   Heinrich Schuchardt   efi_loader: need ...
304
305
306
307
308
309
  	/* Install device tree as UEFI table */
  	ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
  	if (ret != EFI_SUCCESS) {
  		printf("ERROR: failed to install device tree
  ");
  		return ret;
e878e6a7d   AKASHI Takahiro   cmd: bootefi: car...
310
  	}
6182495e1   Heinrich Schuchardt   efi_loader: need ...
311
  #endif /* GENERATE_ACPI_TABLE */
e878e6a7d   AKASHI Takahiro   cmd: bootefi: car...
312
313
314
  
  	return EFI_SUCCESS;
  }
5e2f03910   Simon Glass   efi: Rename boote...
315
  /**
c982874e9   Heinrich Schuchardt   efi_loader: refac...
316
317
   * do_bootefi_exec() - execute EFI binary
   *
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
318
   * @handle:		handle of loaded image
c982874e9   Heinrich Schuchardt   efi_loader: refac...
319
320
321
322
   * Return:		status code
   *
   * Load the EFI binary into a newly assigned memory unwinding the relocation
   * information, install the loaded image protocol, and call the binary.
b9939336d   Alexander Graf   efi_loader: Add "...
323
   */
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
324
  static efi_status_t do_bootefi_exec(efi_handle_t handle)
b9939336d   Alexander Graf   efi_loader: Add "...
325
  {
45204b102   Heinrich Schuchardt   efi_loader: do_bo...
326
  	efi_status_t ret;
556d8dc93   Heinrich Schuchardt   efi_loader: imple...
327
328
  	efi_uintn_t exit_data_size = 0;
  	u16 *exit_data = NULL;
a3850e40e   Heinrich Schuchardt   efi_loader: free ...
329
  	u16 *load_options;
95c5553ea   Rob Clark   efi_loader: refac...
330

3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
331
  	/* Transfer environment variable as load options */
a3850e40e   Heinrich Schuchardt   efi_loader: free ...
332
  	ret = set_load_options(handle, "bootargs", &load_options);
8f7e2b298   Heinrich Schuchardt   efi_loader: set e...
333
  	if (ret != EFI_SUCCESS)
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
334
  		return ret;
bf19273e8   Rob Clark   efi_loader: Add m...
335

b9939336d   Alexander Graf   efi_loader: Add "...
336
  	/* Call our payload! */
556d8dc93   Heinrich Schuchardt   efi_loader: imple...
337
338
339
340
341
342
343
344
  	ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data));
  	printf("## Application terminated, r = %lu
  ", ret & ~EFI_ERROR_MASK);
  	if (ret && exit_data) {
  		printf("## %ls
  ", exit_data);
  		efi_free_pool(exit_data);
  	}
95c5553ea   Rob Clark   efi_loader: refac...
345

3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
346
  	efi_restore_gd();
5e2f03910   Simon Glass   efi: Rename boote...
347

a3850e40e   Heinrich Schuchardt   efi_loader: free ...
348
  	free(load_options);
95c5553ea   Rob Clark   efi_loader: refac...
349
350
  
  	return ret;
b9939336d   Alexander Graf   efi_loader: Add "...
351
  }
d6b21894d   AKASHI Takahiro   cmd: bootefi: car...
352
  /**
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
353
   * do_efibootmgr() - execute EFI boot manager
d6b21894d   AKASHI Takahiro   cmd: bootefi: car...
354
   *
d6b21894d   AKASHI Takahiro   cmd: bootefi: car...
355
   * Return:	status code
d6b21894d   AKASHI Takahiro   cmd: bootefi: car...
356
   */
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
357
  static int do_efibootmgr(void)
cc999d58e   AKASHI Takahiro   cmd: bootefi: mov...
358
  {
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
359
  	efi_handle_t handle;
d6b21894d   AKASHI Takahiro   cmd: bootefi: car...
360
  	efi_status_t ret;
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
361
362
363
364
365
366
  	ret = efi_bootmgr_load(&handle);
  	if (ret != EFI_SUCCESS) {
  		printf("EFI boot manager: Cannot load any image
  ");
  		return CMD_RET_FAILURE;
  	}
cc999d58e   AKASHI Takahiro   cmd: bootefi: mov...
367

6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
368
  	ret = do_bootefi_exec(handle);
cc999d58e   AKASHI Takahiro   cmd: bootefi: mov...
369

d6b21894d   AKASHI Takahiro   cmd: bootefi: car...
370
  	if (ret != EFI_SUCCESS)
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
371
  		return CMD_RET_FAILURE;
cc999d58e   AKASHI Takahiro   cmd: bootefi: mov...
372

6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
373
  	return CMD_RET_SUCCESS;
cc999d58e   AKASHI Takahiro   cmd: bootefi: mov...
374
  }
810371a0b   Heinrich Schuchardt   efi_loader: fix f...
375
  /**
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
376
377
378
379
   * do_bootefi_image() - execute EFI binary
   *
   * Set up memory image for the binary to be loaded, prepare device path, and
   * then call do_bootefi_exec() to execute it.
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
380
381
   *
   * @image_opt:	string of image start address
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
382
   * Return:	status code
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
383
   */
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
384
  static int do_bootefi_image(const char *image_opt)
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
385
  {
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
386
  	void *image_buf;
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
387
388
  	unsigned long addr, size;
  	const char *size_str;
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
389
  	efi_status_t ret;
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
390
391
392
  #ifdef CONFIG_CMD_BOOTEFI_HELLO
  	if (!strcmp(image_opt, "hello")) {
  		char *saddr;
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
393
394
  
  		saddr = env_get("loadaddr");
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
395
  		size = __efi_helloworld_end - __efi_helloworld_begin;
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
396
397
398
399
  		if (saddr)
  			addr = simple_strtoul(saddr, NULL, 16);
  		else
  			addr = CONFIG_SYS_LOAD_ADDR;
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
400
401
402
  
  		image_buf = map_sysmem(addr, size);
  		memcpy(image_buf, __efi_helloworld_begin, size);
f9ceb6ac1   Heinrich Schuchardt   efi_loader: carve...
403
404
405
406
  		efi_free_pool(bootefi_device_path);
  		efi_free_pool(bootefi_image_path);
  		bootefi_device_path = NULL;
  		bootefi_image_path = NULL;
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
407
408
409
  	} else
  #endif
  	{
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
410
411
412
413
414
  		size_str = env_get("filesize");
  		if (size_str)
  			size = simple_strtoul(size_str, NULL, 16);
  		else
  			size = 0;
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
415
416
417
418
  		addr = simple_strtoul(image_opt, NULL, 16);
  		/* Check that a numeric value was passed */
  		if (!addr && *image_opt != '0')
  			return CMD_RET_USAGE;
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
419
420
  
  		image_buf = map_sysmem(addr, size);
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
421
  	}
f9ceb6ac1   Heinrich Schuchardt   efi_loader: carve...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
  	ret = efi_run_image(image_buf, size);
  
  	if (ret != EFI_SUCCESS)
  		return CMD_RET_FAILURE;
  
  	return CMD_RET_SUCCESS;
  }
  
  /**
   * efi_run_image() - run loaded UEFI image
   *
   * @source_buffer:	memory address of the UEFI image
   * @source_size:	size of the UEFI image
   * Return:		status code
   */
  efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size)
  {
  	efi_handle_t mem_handle = NULL, handle;
  	struct efi_device_path *file_path = NULL;
  	efi_status_t ret;
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
442

f9ceb6ac1   Heinrich Schuchardt   efi_loader: carve...
443
  	if (!bootefi_device_path || !bootefi_image_path) {
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
444
445
446
447
448
449
  		/*
  		 * Special case for efi payload not loaded from disk,
  		 * such as 'bootefi hello' or for example payload
  		 * loaded directly into memory via JTAG, etc:
  		 */
  		file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
f9ceb6ac1   Heinrich Schuchardt   efi_loader: carve...
450
451
  					    (uintptr_t)source_buffer,
  					    source_size);
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
452
453
454
455
456
457
458
459
460
461
462
463
464
  		/*
  		 * Make sure that device for device_path exist
  		 * in load_image(). Otherwise, shell and grub will fail.
  		 */
  		ret = efi_create_handle(&mem_handle);
  		if (ret != EFI_SUCCESS)
  			goto out;
  
  		ret = efi_add_protocol(mem_handle, &efi_guid_device_path,
  				       file_path);
  		if (ret != EFI_SUCCESS)
  			goto out;
  	} else {
f9ceb6ac1   Heinrich Schuchardt   efi_loader: carve...
465
466
  		file_path = efi_dp_append(bootefi_device_path,
  					  bootefi_image_path);
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
467
  	}
f9ceb6ac1   Heinrich Schuchardt   efi_loader: carve...
468
469
  	ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer,
  				      source_size, &handle));
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
470
471
472
473
  	if (ret != EFI_SUCCESS)
  		goto out;
  
  	ret = do_bootefi_exec(handle);
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
474
475
476
477
478
479
  
  out:
  	if (mem_handle)
  		efi_delete_handle(mem_handle);
  	if (file_path)
  		efi_free_pool(file_path);
f9ceb6ac1   Heinrich Schuchardt   efi_loader: carve...
480
  	return ret;
e2e4098e1   AKASHI Takahiro   cmd: bootefi: car...
481
  }
d9717eae3   Simon Glass   efi: Split out te...
482
  #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
483
484
485
486
487
488
489
  static efi_status_t bootefi_run_prepare(const char *load_options_path,
  		struct efi_device_path *device_path,
  		struct efi_device_path *image_path,
  		struct efi_loaded_image_obj **image_objp,
  		struct efi_loaded_image **loaded_image_infop)
  {
  	efi_status_t ret;
a3850e40e   Heinrich Schuchardt   efi_loader: free ...
490
  	u16 *load_options;
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
491
492
493
494
495
496
497
  
  	ret = efi_setup_loaded_image(device_path, image_path, image_objp,
  				     loaded_image_infop);
  	if (ret != EFI_SUCCESS)
  		return ret;
  
  	/* Transfer environment variable as load options */
a3850e40e   Heinrich Schuchardt   efi_loader: free ...
498
499
  	return set_load_options((efi_handle_t)*image_objp, load_options_path,
  				&load_options);
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
500
  }
d9717eae3   Simon Glass   efi: Split out te...
501
502
503
  /**
   * bootefi_test_prepare() - prepare to run an EFI test
   *
1504bb0d9   Heinrich Schuchardt   efi_loader: clean...
504
   * Prepare to run a test as if it were provided by a loaded image.
d9717eae3   Simon Glass   efi: Split out te...
505
   *
1504bb0d9   Heinrich Schuchardt   efi_loader: clean...
506
507
508
509
510
511
512
   * @image_objp:		pointer to be set to the loaded image handle
   * @loaded_image_infop:	pointer to be set to the loaded image protocol
   * @path:		dummy file path used to construct the device path
   *			set in the loaded image protocol
   * @load_options_path:	name of a U-Boot environment variable. Its value is
   *			set as load options in the loaded image protocol.
   * Return:		status code
d9717eae3   Simon Glass   efi: Split out te...
513
514
515
   */
  static efi_status_t bootefi_test_prepare
  		(struct efi_loaded_image_obj **image_objp,
1504bb0d9   Heinrich Schuchardt   efi_loader: clean...
516
517
  		 struct efi_loaded_image **loaded_image_infop, const char *path,
  		 const char *load_options_path)
d9717eae3   Simon Glass   efi: Split out te...
518
  {
1504bb0d9   Heinrich Schuchardt   efi_loader: clean...
519
  	efi_status_t ret;
d9717eae3   Simon Glass   efi: Split out te...
520
  	/* Construct a dummy device path */
1504bb0d9   Heinrich Schuchardt   efi_loader: clean...
521
  	bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, 0, 0);
d9717eae3   Simon Glass   efi: Split out te...
522
523
  	if (!bootefi_device_path)
  		return EFI_OUT_OF_RESOURCES;
1504bb0d9   Heinrich Schuchardt   efi_loader: clean...
524

d9717eae3   Simon Glass   efi: Split out te...
525
  	bootefi_image_path = efi_dp_from_file(NULL, 0, path);
1504bb0d9   Heinrich Schuchardt   efi_loader: clean...
526
527
528
529
530
531
532
533
534
535
  	if (!bootefi_image_path) {
  		ret = EFI_OUT_OF_RESOURCES;
  		goto failure;
  	}
  
  	ret = bootefi_run_prepare(load_options_path, bootefi_device_path,
  				  bootefi_image_path, image_objp,
  				  loaded_image_infop);
  	if (ret == EFI_SUCCESS)
  		return ret;
d9717eae3   Simon Glass   efi: Split out te...
536

1504bb0d9   Heinrich Schuchardt   efi_loader: clean...
537
538
539
540
541
542
  	efi_free_pool(bootefi_image_path);
  	bootefi_image_path = NULL;
  failure:
  	efi_free_pool(bootefi_device_path);
  	bootefi_device_path = NULL;
  	return ret;
d9717eae3   Simon Glass   efi: Split out te...
543
  }
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  /**
   * bootefi_run_finish() - finish up after running an EFI test
   *
   * @loaded_image_info: Pointer to a struct which holds the loaded image info
   * @image_obj: Pointer to a struct which holds the loaded image object
   */
  static void bootefi_run_finish(struct efi_loaded_image_obj *image_obj,
  			       struct efi_loaded_image *loaded_image_info)
  {
  	efi_restore_gd();
  	free(loaded_image_info->load_options);
  	efi_delete_handle(&image_obj->header);
  }
  
  /**
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
559
   * do_efi_selftest() - execute EFI selftest
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
560
   *
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
561
   * Return:	status code
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
562
   */
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
563
  static int do_efi_selftest(void)
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
564
565
566
567
  {
  	struct efi_loaded_image_obj *image_obj;
  	struct efi_loaded_image *loaded_image_info;
  	efi_status_t ret;
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
568
569
570
571
572
573
574
575
576
577
578
  	ret = bootefi_test_prepare(&image_obj, &loaded_image_info,
  				   "\\selftest", "efi_selftest");
  	if (ret != EFI_SUCCESS)
  		return CMD_RET_FAILURE;
  
  	/* Execute the test */
  	ret = EFI_CALL(efi_selftest(&image_obj->header, &systab));
  	bootefi_run_finish(image_obj, loaded_image_info);
  
  	return ret != EFI_SUCCESS;
  }
d9717eae3   Simon Glass   efi: Split out te...
579
  #endif /* CONFIG_CMD_BOOTEFI_SELFTEST */
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
580
581
582
583
584
585
586
587
588
  /**
   * do_bootefi() - execute `bootefi` command
   *
   * @cmdtp:	table entry describing command
   * @flag:	bitmap indicating how the command was invoked
   * @argc:	number of arguments
   * @argv:	command line arguments
   * Return:	status code
   */
b9939336d   Alexander Graf   efi_loader: Add "...
589
590
  static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  {
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
591
  	efi_status_t ret;
f64f22325   Heinrich Schuchardt   efi_loader: expor...
592
  	void *fdt;
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
593

3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
594
595
  	if (argc < 2)
  		return CMD_RET_USAGE;
d6b21894d   AKASHI Takahiro   cmd: bootefi: car...
596

7e92db810   Heinrich Schuchardt   efi_loader: dedup...
597
598
599
600
601
602
603
604
  	/* Initialize EFI drivers */
  	ret = efi_init_obj_list();
  	if (ret != EFI_SUCCESS) {
  		printf("Error: Cannot initialize UEFI sub-system, r = %lu
  ",
  		       ret & ~EFI_ERROR_MASK);
  		return CMD_RET_FAILURE;
  	}
f64f22325   Heinrich Schuchardt   efi_loader: expor...
605
606
  	if (argc > 2) {
  		uintptr_t fdt_addr;
7a597259d   Heinrich Schuchardt   efi_loader: pass ...
607
  		fdt_addr = simple_strtoul(argv[2], NULL, 16);
f64f22325   Heinrich Schuchardt   efi_loader: expor...
608
609
610
611
612
  		fdt = map_sysmem(fdt_addr, 0);
  	} else {
  		fdt = EFI_FDT_USE_INTERNAL;
  	}
  	ret = efi_install_fdt(fdt);
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
613
614
615
616
  	if (ret == EFI_INVALID_PARAMETER)
  		return CMD_RET_USAGE;
  	else if (ret != EFI_SUCCESS)
  		return CMD_RET_FAILURE;
d6b21894d   AKASHI Takahiro   cmd: bootefi: car...
617
  	if (!strcmp(argv[1], "bootmgr"))
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
618
  		return do_efibootmgr();
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
619
620
  #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
  	else if (!strcmp(argv[1], "selftest"))
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
621
  		return do_efi_selftest();
3fc2b1633   AKASHI Takahiro   cmd: bootefi: car...
622
  #endif
7e92db810   Heinrich Schuchardt   efi_loader: dedup...
623
  	return do_bootefi_image(argv[1]);
b9939336d   Alexander Graf   efi_loader: Add "...
624
625
626
627
  }
  
  #ifdef CONFIG_SYS_LONGHELP
  static char bootefi_help_text[] =
1c39809b9   Alexander Graf   efi_loader: Pass ...
628
629
630
631
632
633
  	"<image address> [fdt address]
  "
  	"  - boot EFI payload stored at address <image address>.
  "
  	"    If specified, the device tree located at <fdt address> gets
  "
c7ae3dfdc   Simon Glass   efi: Add support ...
634
635
636
  	"    exposed as EFI configuration table.
  "
  #ifdef CONFIG_CMD_BOOTEFI_HELLO
623b3a579   Heinrich Schuchardt   efi_selftest: pro...
637
638
639
640
641
642
  	"bootefi hello
  "
  	"  - boot a sample Hello World application stored within U-Boot
  "
  #endif
  #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
bc4f9133e   Heinrich Schuchardt   efi_loader: suppo...
643
644
  	"bootefi selftest [fdt address]
  "
623b3a579   Heinrich Schuchardt   efi_selftest: pro...
645
646
  	"  - boot an EFI selftest application stored within U-Boot
  "
d78e40d65   Heinrich Schuchardt   efi_selftest: all...
647
648
649
650
  	"    Use environment variable efi_selftest to select a single test.
  "
  	"    Use 'setenv efi_selftest list' to enumerate all tests.
  "
c7ae3dfdc   Simon Glass   efi: Add support ...
651
  #endif
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
652
653
  	"bootefi bootmgr [fdt address]
  "
9975fe96b   Rob Clark   efi_loader: add b...
654
655
656
657
658
659
660
661
  	"  - load and boot EFI payload based on BootOrder/BootXXXX variables.
  "
  	"
  "
  	"    If specified, the device tree located at <fdt address> gets
  "
  	"    exposed as EFI configuration table.
  ";
b9939336d   Alexander Graf   efi_loader: Add "...
662
663
664
  #endif
  
  U_BOOT_CMD(
1c39809b9   Alexander Graf   efi_loader: Pass ...
665
  	bootefi, 3, 0, do_bootefi,
92dfd9221   Sergey Kubushyn   cmd: bootefi: cos...
666
  	"Boots an EFI payload from memory",
b9939336d   Alexander Graf   efi_loader: Add "...
667
668
  	bootefi_help_text
  );
0f4060ebc   Alexander Graf   efi_loader: Pass ...
669

810371a0b   Heinrich Schuchardt   efi_loader: fix f...
670
671
672
673
674
675
676
677
678
679
  /**
   * efi_set_bootdev() - set boot device
   *
   * This function is called when a file is loaded, e.g. via the 'load' command.
   * We use the path to this file to inform the UEFI binary about the boot device.
   *
   * @dev:	device, e.g. "MMC"
   * @devnr:	number of the device, e.g. "1:2"
   * @path:	path to file loaded
   */
95c5553ea   Rob Clark   efi_loader: refac...
680
681
  void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
  {
f1589ffb3   AKASHI Takahiro   efi_loader: add e...
682
683
  	struct efi_device_path *device, *image;
  	efi_status_t ret;
f9d334bdf   Alexander Graf   efi_loader: disk:...
684

79276eb24   Heinrich Schuchardt   efi_loader: memor...
685
686
687
  	/* efi_set_bootdev is typically called repeatedly, recover memory */
  	efi_free_pool(bootefi_device_path);
  	efi_free_pool(bootefi_image_path);
9975fe96b   Rob Clark   efi_loader: add b...
688

f1589ffb3   AKASHI Takahiro   efi_loader: add e...
689
690
691
  	ret = efi_dp_from_name(dev, devnr, path, &device, &image);
  	if (ret == EFI_SUCCESS) {
  		bootefi_device_path = device;
6b95b38c4   AKASHI Takahiro   efi_loader: rewor...
692
693
694
695
696
697
698
  		if (image) {
  			/* FIXME: image should not contain device */
  			struct efi_device_path *image_tmp = image;
  
  			efi_dp_split_file_path(image, &device, &image);
  			efi_free_pool(image_tmp);
  		}
f1589ffb3   AKASHI Takahiro   efi_loader: add e...
699
  		bootefi_image_path = image;
492716662   Alexander Graf   efi_loader: Make ...
700
  	} else {
f1589ffb3   AKASHI Takahiro   efi_loader: add e...
701
702
  		bootefi_device_path = NULL;
  		bootefi_image_path = NULL;
492716662   Alexander Graf   efi_loader: Make ...
703
  	}
0f4060ebc   Alexander Graf   efi_loader: Pass ...
704
  }