efi_loader: do_bootefi_exec should always return an EFI status code
[pandora-u-boot.git] / cmd / bootefi.c
1 /*
2  *  EFI application loader
3  *
4  *  Copyright (c) 2016 Alexander Graf
5  *
6  *  SPDX-License-Identifier:     GPL-2.0+
7  */
8
9 #include <charset.h>
10 #include <common.h>
11 #include <command.h>
12 #include <dm.h>
13 #include <efi_loader.h>
14 #include <efi_selftest.h>
15 #include <errno.h>
16 #include <linux/libfdt.h>
17 #include <linux/libfdt_env.h>
18 #include <memalign.h>
19 #include <asm/global_data.h>
20 #include <asm-generic/sections.h>
21 #include <linux/linkage.h>
22
23 DECLARE_GLOBAL_DATA_PTR;
24
25 static u8 efi_obj_list_initialized;
26
27 static struct efi_device_path *bootefi_image_path;
28 static struct efi_device_path *bootefi_device_path;
29
30 /* Initialize and populate EFI object list */
31 static void efi_init_obj_list(void)
32 {
33         /* Initialize once only */
34         if (efi_obj_list_initialized)
35                 return;
36         efi_obj_list_initialized = 1;
37
38         /* Initialize EFI driver uclass */
39         efi_driver_init();
40
41         efi_console_register();
42 #ifdef CONFIG_PARTITIONS
43         efi_disk_register();
44 #endif
45 #if defined(CONFIG_LCD) || defined(CONFIG_DM_VIDEO)
46         efi_gop_register();
47 #endif
48 #ifdef CONFIG_CMD_NET
49         efi_net_register();
50 #endif
51 #ifdef CONFIG_GENERATE_SMBIOS_TABLE
52         efi_smbios_register();
53 #endif
54         efi_watchdog_register();
55
56         /* Initialize EFI runtime services */
57         efi_reset_system_init();
58         efi_get_time_init();
59 }
60
61 /*
62  * Set the load options of an image from an environment variable.
63  *
64  * @loaded_image_info:  the image
65  * @env_var:            name of the environment variable
66  */
67 static void set_load_options(struct efi_loaded_image *loaded_image_info,
68                              const char *env_var)
69 {
70         size_t size;
71         const char *env = env_get(env_var);
72
73         loaded_image_info->load_options = NULL;
74         loaded_image_info->load_options_size = 0;
75         if (!env)
76                 return;
77         size = strlen(env) + 1;
78         loaded_image_info->load_options = calloc(size, sizeof(u16));
79         if (!loaded_image_info->load_options) {
80                 printf("ERROR: Out of memory\n");
81                 return;
82         }
83         utf8_to_utf16(loaded_image_info->load_options, (u8 *)env, size);
84         loaded_image_info->load_options_size = size * 2;
85 }
86
87 static void *copy_fdt(void *fdt)
88 {
89         u64 fdt_size = fdt_totalsize(fdt);
90         unsigned long fdt_ram_start = -1L, fdt_pages;
91         u64 new_fdt_addr;
92         void *new_fdt;
93         int i;
94
95         for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
96                 u64 ram_start = gd->bd->bi_dram[i].start;
97                 u64 ram_size = gd->bd->bi_dram[i].size;
98
99                 if (!ram_size)
100                         continue;
101
102                 if (ram_start < fdt_ram_start)
103                         fdt_ram_start = ram_start;
104         }
105
106         /* Give us at least 4kb breathing room */
107         fdt_size = ALIGN(fdt_size + 4096, EFI_PAGE_SIZE);
108         fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
109
110         /* Safe fdt location is at 128MB */
111         new_fdt_addr = fdt_ram_start + (128 * 1024 * 1024) + fdt_size;
112         if (efi_allocate_pages(1, EFI_RUNTIME_SERVICES_DATA, fdt_pages,
113                                &new_fdt_addr) != EFI_SUCCESS) {
114                 /* If we can't put it there, put it somewhere */
115                 new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size);
116                 if (efi_allocate_pages(1, EFI_RUNTIME_SERVICES_DATA, fdt_pages,
117                                        &new_fdt_addr) != EFI_SUCCESS) {
118                         printf("ERROR: Failed to reserve space for FDT\n");
119                         return NULL;
120                 }
121         }
122
123         new_fdt = (void*)(ulong)new_fdt_addr;
124         memcpy(new_fdt, fdt, fdt_totalsize(fdt));
125         fdt_set_totalsize(new_fdt, fdt_size);
126
127         return new_fdt;
128 }
129
130 static efi_status_t efi_do_enter(
131                         efi_handle_t image_handle, struct efi_system_table *st,
132                         EFIAPI efi_status_t (*entry)(
133                                 efi_handle_t image_handle,
134                                 struct efi_system_table *st))
135 {
136         efi_status_t ret = EFI_LOAD_ERROR;
137
138         if (entry)
139                 ret = entry(image_handle, st);
140         st->boottime->exit(image_handle, ret, 0, NULL);
141         return ret;
142 }
143
144 #ifdef CONFIG_ARM64
145 static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)(
146                         efi_handle_t image_handle, struct efi_system_table *st),
147                         efi_handle_t image_handle, struct efi_system_table *st)
148 {
149         /* Enable caches again */
150         dcache_enable();
151
152         return efi_do_enter(image_handle, st, entry);
153 }
154 #endif
155
156 /*
157  * Load an EFI payload into a newly allocated piece of memory, register all
158  * EFI objects it would want to access and jump to it.
159  */
160 static efi_status_t do_bootefi_exec(void *efi, void *fdt,
161                                     struct efi_device_path *device_path,
162                                     struct efi_device_path *image_path)
163 {
164         struct efi_loaded_image loaded_image_info = {};
165         struct efi_object loaded_image_info_obj = {};
166         struct efi_device_path *memdp = NULL;
167         efi_status_t ret;
168
169         EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
170                                      struct efi_system_table *st);
171         ulong fdt_pages, fdt_size, fdt_start, fdt_end;
172         const efi_guid_t fdt_guid = EFI_FDT_GUID;
173         bootm_headers_t img = { 0 };
174
175         /*
176          * Special case for efi payload not loaded from disk, such as
177          * 'bootefi hello' or for example payload loaded directly into
178          * memory via jtag/etc:
179          */
180         if (!device_path && !image_path) {
181                 printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
182                 /* actual addresses filled in after efi_load_pe() */
183                 memdp = efi_dp_from_mem(0, 0, 0);
184                 device_path = image_path = memdp;
185         } else {
186                 assert(device_path && image_path);
187         }
188
189         /* Initialize and populate EFI object list */
190         efi_init_obj_list();
191
192         efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj,
193                                device_path, image_path);
194
195         /*
196          * gd lives in a fixed register which may get clobbered while we execute
197          * the payload. So save it here and restore it on every callback entry
198          */
199         efi_save_gd();
200
201         if (fdt && !fdt_check_header(fdt)) {
202                 /* Prepare fdt for payload */
203                 fdt = copy_fdt(fdt);
204
205                 if (image_setup_libfdt(&img, fdt, 0, NULL)) {
206                         printf("ERROR: Failed to process device tree\n");
207                         return -EINVAL;
208                 }
209
210                 /* Link to it in the efi tables */
211                 efi_install_configuration_table(&fdt_guid, fdt);
212
213                 /* And reserve the space in the memory map */
214                 fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK;
215                 fdt_end = ((ulong)fdt) + fdt_totalsize(fdt);
216                 fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK;
217                 fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
218                 /* Give a bootloader the chance to modify the device tree */
219                 fdt_pages += 2;
220                 efi_add_memory_map(fdt_start, fdt_pages,
221                                    EFI_BOOT_SERVICES_DATA, true);
222         } else {
223                 printf("WARNING: Invalid device tree, expect boot to fail\n");
224                 efi_install_configuration_table(&fdt_guid, NULL);
225         }
226
227         /* Transfer environment variable bootargs as load options */
228         set_load_options(&loaded_image_info, "bootargs");
229         /* Load the EFI payload */
230         entry = efi_load_pe(efi, &loaded_image_info);
231         if (!entry) {
232                 ret = EFI_LOAD_ERROR;
233                 goto exit;
234         }
235
236         if (memdp) {
237                 struct efi_device_path_memory *mdp = (void *)memdp;
238                 mdp->memory_type = loaded_image_info.image_code_type;
239                 mdp->start_address = (uintptr_t)loaded_image_info.image_base;
240                 mdp->end_address = mdp->start_address +
241                                 loaded_image_info.image_size;
242         }
243
244         /* we don't support much: */
245         env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported",
246                 "{ro,boot}(blob)0000000000000000");
247
248         /* Call our payload! */
249         debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
250
251         if (setjmp(&loaded_image_info.exit_jmp)) {
252                 ret = loaded_image_info.exit_status;
253                 goto exit;
254         }
255
256 #ifdef CONFIG_ARM64
257         /* On AArch64 we need to make sure we call our payload in < EL3 */
258         if (current_el() == 3) {
259                 smp_kick_all_cpus();
260                 dcache_disable();       /* flush cache before switch to EL2 */
261
262                 /* Move into EL2 and keep running there */
263                 armv8_switch_to_el2((ulong)entry,
264                                     (ulong)&loaded_image_info_obj.handle,
265                                     (ulong)&systab, 0, (ulong)efi_run_in_el2,
266                                     ES_TO_AARCH64);
267
268                 /* Should never reach here, efi exits with longjmp */
269                 while (1) { }
270         }
271 #endif
272
273         ret = efi_do_enter(loaded_image_info_obj.handle, &systab, entry);
274
275 exit:
276         /* image has returned, loaded-image obj goes *poof*: */
277         list_del(&loaded_image_info_obj.link);
278
279         return ret;
280 }
281
282 static int do_bootefi_bootmgr_exec(unsigned long fdt_addr)
283 {
284         struct efi_device_path *device_path, *file_path;
285         void *addr;
286         efi_status_t r;
287
288         /* Initialize and populate EFI object list */
289         efi_init_obj_list();
290
291         /*
292          * gd lives in a fixed register which may get clobbered while we execute
293          * the payload. So save it here and restore it on every callback entry
294          */
295         efi_save_gd();
296
297         addr = efi_bootmgr_load(&device_path, &file_path);
298         if (!addr)
299                 return 1;
300
301         printf("## Starting EFI application at %p ...\n", addr);
302         r = do_bootefi_exec(addr, (void *)fdt_addr, device_path, file_path);
303         printf("## Application terminated, r = %lu\n",
304                r & ~EFI_ERROR_MASK);
305
306         if (r != EFI_SUCCESS)
307                 return 1;
308
309         return 0;
310 }
311
312 /* Interpreter command to boot an arbitrary EFI image from memory */
313 static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
314 {
315         char *saddr, *sfdt;
316         unsigned long addr, fdt_addr = 0;
317         efi_status_t r;
318
319         if (argc < 2)
320                 return CMD_RET_USAGE;
321 #ifdef CONFIG_CMD_BOOTEFI_HELLO
322         if (!strcmp(argv[1], "hello")) {
323                 ulong size = __efi_helloworld_end - __efi_helloworld_begin;
324
325                 saddr = env_get("loadaddr");
326                 if (saddr)
327                         addr = simple_strtoul(saddr, NULL, 16);
328                 else
329                         addr = CONFIG_SYS_LOAD_ADDR;
330                 memcpy((char *)addr, __efi_helloworld_begin, size);
331         } else
332 #endif
333 #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
334         if (!strcmp(argv[1], "selftest")) {
335                 struct efi_loaded_image loaded_image_info = {};
336                 struct efi_object loaded_image_info_obj = {};
337
338                 /* Construct a dummy device path. */
339                 bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
340                                                       (uintptr_t)&efi_selftest,
341                                                       (uintptr_t)&efi_selftest);
342                 bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest");
343
344                 efi_setup_loaded_image(&loaded_image_info,
345                                        &loaded_image_info_obj,
346                                        bootefi_device_path, bootefi_image_path);
347                 /*
348                  * gd lives in a fixed register which may get clobbered while we
349                  * execute the payload. So save it here and restore it on every
350                  * callback entry
351                  */
352                 efi_save_gd();
353                 /* Initialize and populate EFI object list */
354                 efi_init_obj_list();
355                 /* Transfer environment variable efi_selftest as load options */
356                 set_load_options(&loaded_image_info, "efi_selftest");
357                 /* Execute the test */
358                 r = efi_selftest(loaded_image_info_obj.handle, &systab);
359                 efi_restore_gd();
360                 free(loaded_image_info.load_options);
361                 list_del(&loaded_image_info_obj.link);
362                 return r != EFI_SUCCESS;
363         } else
364 #endif
365         if (!strcmp(argv[1], "bootmgr")) {
366                 unsigned long fdt_addr = 0;
367
368                 if (argc > 2)
369                         fdt_addr = simple_strtoul(argv[2], NULL, 16);
370
371                 return do_bootefi_bootmgr_exec(fdt_addr);
372         } else {
373                 saddr = argv[1];
374
375                 addr = simple_strtoul(saddr, NULL, 16);
376                 /* Check that a numeric value was passed */
377                 if (!addr && *saddr != '0')
378                         return CMD_RET_USAGE;
379
380                 if (argc > 2) {
381                         sfdt = argv[2];
382                         fdt_addr = simple_strtoul(sfdt, NULL, 16);
383                 }
384         }
385
386         printf("## Starting EFI application at %08lx ...\n", addr);
387         r = do_bootefi_exec((void *)addr, (void *)fdt_addr,
388                             bootefi_device_path, bootefi_image_path);
389         printf("## Application terminated, r = %lu\n",
390                r & ~EFI_ERROR_MASK);
391
392         if (r != EFI_SUCCESS)
393                 return 1;
394         else
395                 return 0;
396 }
397
398 #ifdef CONFIG_SYS_LONGHELP
399 static char bootefi_help_text[] =
400         "<image address> [fdt address]\n"
401         "  - boot EFI payload stored at address <image address>.\n"
402         "    If specified, the device tree located at <fdt address> gets\n"
403         "    exposed as EFI configuration table.\n"
404 #ifdef CONFIG_CMD_BOOTEFI_HELLO
405         "bootefi hello\n"
406         "  - boot a sample Hello World application stored within U-Boot\n"
407 #endif
408 #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
409         "bootefi selftest\n"
410         "  - boot an EFI selftest application stored within U-Boot\n"
411         "    Use environment variable efi_selftest to select a single test.\n"
412         "    Use 'setenv efi_selftest list' to enumerate all tests.\n"
413 #endif
414         "bootefi bootmgr [fdt addr]\n"
415         "  - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
416         "\n"
417         "    If specified, the device tree located at <fdt address> gets\n"
418         "    exposed as EFI configuration table.\n";
419 #endif
420
421 U_BOOT_CMD(
422         bootefi, 3, 0, do_bootefi,
423         "Boots an EFI payload from memory",
424         bootefi_help_text
425 );
426
427 static int parse_partnum(const char *devnr)
428 {
429         const char *str = strchr(devnr, ':');
430         if (str) {
431                 str++;
432                 return simple_strtoul(str, NULL, 16);
433         }
434         return 0;
435 }
436
437 void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
438 {
439         char filename[32] = { 0 }; /* dp->str is u16[32] long */
440         char *s;
441
442         if (strcmp(dev, "Net")) {
443                 struct blk_desc *desc;
444                 int part;
445
446                 desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10));
447                 if (!desc)
448                         return;
449                 part = parse_partnum(devnr);
450
451                 bootefi_device_path = efi_dp_from_part(desc, part);
452         } else {
453 #ifdef CONFIG_CMD_NET
454                 bootefi_device_path = efi_dp_from_eth();
455 #endif
456         }
457
458         if (!path)
459                 return;
460
461         if (strcmp(dev, "Net")) {
462                 /* Add leading / to fs paths, because they're absolute */
463                 snprintf(filename, sizeof(filename), "/%s", path);
464         } else {
465                 snprintf(filename, sizeof(filename), "%s", path);
466         }
467         /* DOS style file path: */
468         s = filename;
469         while ((s = strchr(s, '/')))
470                 *s++ = '\\';
471         bootefi_image_path = efi_dp_from_file(NULL, 0, filename);
472 }