efi_loader: Use system fdt as fallback
[platform/kernel/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 <common.h>
10 #include <command.h>
11 #include <efi_loader.h>
12 #include <errno.h>
13 #include <libfdt.h>
14 #include <libfdt_env.h>
15 #include <malloc.h>
16 #include <asm/global_data.h>
17
18 DECLARE_GLOBAL_DATA_PTR;
19
20 /*
21  * When booting using the "bootefi" command, we don't know which
22  * physical device the file came from. So we create a pseudo-device
23  * called "bootefi" with the device path /bootefi.
24  *
25  * In addition to the originating device we also declare the file path
26  * of "bootefi" based loads to be /bootefi.
27  */
28 static struct efi_device_path_file_path bootefi_image_path[] = {
29         {
30                 .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
31                 .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
32                 .dp.length = sizeof(bootefi_image_path[0]),
33                 .str = { 'b','o','o','t','e','f','i' },
34         }, {
35                 .dp.type = DEVICE_PATH_TYPE_END,
36                 .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
37                 .dp.length = sizeof(bootefi_image_path[0]),
38         }
39 };
40
41 static struct efi_device_path_file_path bootefi_device_path[] = {
42         {
43                 .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
44                 .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
45                 .dp.length = sizeof(bootefi_image_path[0]),
46                 .str = { 'b','o','o','t','e','f','i' },
47         }, {
48                 .dp.type = DEVICE_PATH_TYPE_END,
49                 .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
50                 .dp.length = sizeof(bootefi_image_path[0]),
51         }
52 };
53
54 static efi_status_t bootefi_open_dp(void *handle, efi_guid_t *protocol,
55                         void **protocol_interface, void *agent_handle,
56                         void *controller_handle, uint32_t attributes)
57 {
58         *protocol_interface = bootefi_device_path;
59         return EFI_SUCCESS;
60 }
61
62 /* The EFI loaded_image interface for the image executed via "bootefi" */
63 static struct efi_loaded_image loaded_image_info = {
64         .device_handle = bootefi_device_path,
65         .file_path = bootefi_image_path,
66 };
67
68 /* The EFI object struct for the image executed via "bootefi" */
69 static struct efi_object loaded_image_info_obj = {
70         .handle = &loaded_image_info,
71         .protocols = {
72                 {
73                         /*
74                          * When asking for the loaded_image interface, just
75                          * return handle which points to loaded_image_info
76                          */
77                         .guid = &efi_guid_loaded_image,
78                         .open = &efi_return_handle,
79                 },
80                 {
81                         /*
82                          * When asking for the device path interface, return
83                          * bootefi_device_path
84                          */
85                         .guid = &efi_guid_device_path,
86                         .open = &bootefi_open_dp,
87                 },
88         },
89 };
90
91 /* The EFI object struct for the device the "bootefi" image was loaded from */
92 static struct efi_object bootefi_device_obj = {
93         .handle = bootefi_device_path,
94         .protocols = {
95                 {
96                         /* When asking for the device path interface, return
97                          * bootefi_device_path */
98                         .guid = &efi_guid_device_path,
99                         .open = &bootefi_open_dp,
100                 }
101         },
102 };
103
104 static void *copy_fdt(void *fdt)
105 {
106         u64 fdt_size = fdt_totalsize(fdt);
107         void *new_fdt;
108
109         /* Give us 64kb breathing room */
110         fdt_size += 64 * 1024;
111
112         new_fdt = malloc(fdt_size);
113         memcpy(new_fdt, fdt, fdt_totalsize(fdt));
114         fdt_set_totalsize(new_fdt, fdt_size);
115
116         return new_fdt;
117 }
118
119 /*
120  * Load an EFI payload into a newly allocated piece of memory, register all
121  * EFI objects it would want to access and jump to it.
122  */
123 static unsigned long do_bootefi_exec(void *efi)
124 {
125         ulong (*entry)(void *image_handle, struct efi_system_table *st);
126         ulong fdt_pages, fdt_size, fdt_start, fdt_end;
127         bootm_headers_t img = { 0 };
128         void *fdt = working_fdt;
129
130         /*
131          * gd lives in a fixed register which may get clobbered while we execute
132          * the payload. So save it here and restore it on every callback entry
133          */
134         efi_save_gd();
135
136         /* Update system table to point to our currently loaded FDT */
137
138         /* Fall back to included fdt if none was manually loaded */
139         if (!fdt && gd->fdt_blob)
140                 fdt = (void *)gd->fdt_blob;
141
142         if (fdt) {
143                 /* Prepare fdt for payload */
144                 fdt = copy_fdt(fdt);
145
146                 if (image_setup_libfdt(&img, fdt, 0, NULL)) {
147                         printf("ERROR: Failed to process device tree\n");
148                         return -EINVAL;
149                 }
150
151                 /* Link to it in the efi tables */
152                 systab.tables[0].guid = EFI_FDT_GUID;
153                 systab.tables[0].table = fdt;
154                 systab.nr_tables = 1;
155
156                 /* And reserve the space in the memory map */
157                 fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK;
158                 fdt_end = ((ulong)fdt) + fdt_totalsize(fdt);
159                 fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK;
160                 fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
161                 /* Give a bootloader the chance to modify the device tree */
162                 fdt_pages += 2;
163                 efi_add_memory_map(fdt_start, fdt_pages,
164                                    EFI_BOOT_SERVICES_DATA, true);
165         } else {
166                 printf("WARNING: No device tree loaded, expect boot to fail\n");
167                 systab.nr_tables = 0;
168         }
169
170         /* Load the EFI payload */
171         entry = efi_load_pe(efi, &loaded_image_info);
172         if (!entry)
173                 return -ENOENT;
174
175         /* Initialize and populate EFI object list */
176         INIT_LIST_HEAD(&efi_obj_list);
177         list_add_tail(&loaded_image_info_obj.link, &efi_obj_list);
178         list_add_tail(&bootefi_device_obj.link, &efi_obj_list);
179 #ifdef CONFIG_PARTITIONS
180         efi_disk_register();
181 #endif
182 #ifdef CONFIG_LCD
183         efi_gop_register();
184 #endif
185
186         /* Call our payload! */
187 #ifdef DEBUG_EFI
188         printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
189 #endif
190         return entry(&loaded_image_info, &systab);
191 }
192
193
194 /* Interpreter command to boot an arbitrary EFI image from memory */
195 static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
196 {
197         char *saddr;
198         unsigned long addr;
199         int r = 0;
200
201         if (argc < 2)
202                 return 1;
203         saddr = argv[1];
204
205         addr = simple_strtoul(saddr, NULL, 16);
206
207         printf("## Starting EFI application at 0x%08lx ...\n", addr);
208         r = do_bootefi_exec((void *)addr);
209         printf("## Application terminated, r = %d\n", r);
210
211         if (r != 0)
212                 r = 1;
213
214         return r;
215 }
216
217 #ifdef CONFIG_SYS_LONGHELP
218 static char bootefi_help_text[] =
219         "<image address>\n"
220         "  - boot EFI payload stored at address <image address>\n"
221         "\n"
222         "Since most EFI payloads want to have a device tree provided, please\n"
223         "make sure you load a device tree using the fdt addr command before\n"
224         "executing bootefi.\n";
225 #endif
226
227 U_BOOT_CMD(
228         bootefi, 2, 0, do_bootefi,
229         "Boots an EFI payload from memory\n",
230         bootefi_help_text
231 );
232
233 void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
234 {
235         __maybe_unused struct blk_desc *desc;
236         char devname[32] = { 0 }; /* dp->str is u16[32] long */
237         char *colon;
238
239         /* Assemble the condensed device name we use in efi_disk.c */
240         snprintf(devname, sizeof(devname), "%s%s", dev, devnr);
241         colon = strchr(devname, ':');
242
243 #ifdef CONFIG_ISO_PARTITION
244         /* For ISOs we create partition block devices */
245         desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10));
246         if (desc && (desc->type != DEV_TYPE_UNKNOWN) &&
247             (desc->part_type == PART_TYPE_ISO)) {
248                 if (!colon)
249                         snprintf(devname, sizeof(devname), "%s%s:1", dev,
250                                  devnr);
251                 colon = NULL;
252         }
253 #endif
254
255         if (colon)
256                 *colon = '\0';
257
258         /* Patch bootefi_device_path to the target device */
259         memset(bootefi_device_path[0].str, 0, sizeof(bootefi_device_path[0].str));
260         ascii2unicode(bootefi_device_path[0].str, devname);
261
262         /* Patch bootefi_image_path to the target file path */
263         memset(bootefi_image_path[0].str, 0, sizeof(bootefi_image_path[0].str));
264         snprintf(devname, sizeof(devname), "%s", path);
265         ascii2unicode(bootefi_image_path[0].str, devname);
266 }