Merge tag 'u-boot-amlogic-20200708' of https://gitlab.denx.de/u-boot/custodians/u...
[platform/kernel/u-boot.git] / lib / efi_loader / efi_bootmgr.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  EFI boot manager
4  *
5  *  Copyright (c) 2017 Rob Clark
6  */
7
8 #define LOG_CATEGORY LOGC_EFI
9
10 #include <common.h>
11 #include <charset.h>
12 #include <log.h>
13 #include <malloc.h>
14 #include <efi_loader.h>
15 #include <asm/unaligned.h>
16
17 static const struct efi_boot_services *bs;
18 static const struct efi_runtime_services *rs;
19
20 /*
21  * bootmgr implements the logic of trying to find a payload to boot
22  * based on the BootOrder + BootXXXX variables, and then loading it.
23  *
24  * TODO detecting a special key held (f9?) and displaying a boot menu
25  * like you would get on a PC would be clever.
26  *
27  * TODO if we had a way to write and persist variables after the OS
28  * has started, we'd also want to check OsIndications to see if we
29  * should do normal or recovery boot.
30  */
31
32
33 /**
34  * efi_deserialize_load_option() - parse serialized data
35  *
36  * Parse serialized data describing a load option and transform it to the
37  * efi_load_option structure.
38  *
39  * @lo:         pointer to target
40  * @data:       serialized data
41  * @size:       size of the load option, on return size of the optional data
42  * Return:      status code
43  */
44 efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data,
45                                          efi_uintn_t *size)
46 {
47         efi_uintn_t len;
48
49         len = sizeof(u32);
50         if (*size < len + 2 * sizeof(u16))
51                 return EFI_INVALID_PARAMETER;
52         lo->attributes = get_unaligned_le32(data);
53         data += len;
54         *size -= len;
55
56         len = sizeof(u16);
57         lo->file_path_length = get_unaligned_le16(data);
58         data += len;
59         *size -= len;
60
61         lo->label = (u16 *)data;
62         len = u16_strnlen(lo->label, *size / sizeof(u16) - 1);
63         if (lo->label[len])
64                 return EFI_INVALID_PARAMETER;
65         len = (len + 1) * sizeof(u16);
66         if (*size < len)
67                 return EFI_INVALID_PARAMETER;
68         data += len;
69         *size -= len;
70
71         len = lo->file_path_length;
72         if (*size < len)
73                 return EFI_INVALID_PARAMETER;
74         lo->file_path = (struct efi_device_path *)data;
75          /*
76           * TODO: validate device path. There should be an end node within
77           * the indicated file_path_length.
78           */
79         data += len;
80         *size -= len;
81
82         lo->optional_data = data;
83
84         return EFI_SUCCESS;
85 }
86
87 /**
88  * efi_serialize_load_option() - serialize load option
89  *
90  * Serialize efi_load_option structure into byte stream for BootXXXX.
91  *
92  * @data:       buffer for serialized data
93  * @lo:         load option
94  * Return:      size of allocated buffer
95  */
96 unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data)
97 {
98         unsigned long label_len;
99         unsigned long size;
100         u8 *p;
101
102         label_len = (u16_strlen(lo->label) + 1) * sizeof(u16);
103
104         /* total size */
105         size = sizeof(lo->attributes);
106         size += sizeof(lo->file_path_length);
107         size += label_len;
108         size += lo->file_path_length;
109         if (lo->optional_data)
110                 size += (utf8_utf16_strlen((const char *)lo->optional_data)
111                                            + 1) * sizeof(u16);
112         p = malloc(size);
113         if (!p)
114                 return 0;
115
116         /* copy data */
117         *data = p;
118         memcpy(p, &lo->attributes, sizeof(lo->attributes));
119         p += sizeof(lo->attributes);
120
121         memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length));
122         p += sizeof(lo->file_path_length);
123
124         memcpy(p, lo->label, label_len);
125         p += label_len;
126
127         memcpy(p, lo->file_path, lo->file_path_length);
128         p += lo->file_path_length;
129
130         if (lo->optional_data) {
131                 utf8_utf16_strcpy((u16 **)&p, (const char *)lo->optional_data);
132                 p += sizeof(u16); /* size of trailing \0 */
133         }
134         return size;
135 }
136
137 /**
138  * get_var() - get UEFI variable
139  *
140  * It is the caller's duty to free the returned buffer.
141  *
142  * @name:       name of variable
143  * @vendor:     vendor GUID of variable
144  * @size:       size of allocated buffer
145  * Return:      buffer with variable data or NULL
146  */
147 static void *get_var(u16 *name, const efi_guid_t *vendor,
148                      efi_uintn_t *size)
149 {
150         efi_guid_t *v = (efi_guid_t *)vendor;
151         efi_status_t ret;
152         void *buf = NULL;
153
154         *size = 0;
155         EFI_CALL(ret = rs->get_variable(name, v, NULL, size, buf));
156         if (ret == EFI_BUFFER_TOO_SMALL) {
157                 buf = malloc(*size);
158                 EFI_CALL(ret = rs->get_variable(name, v, NULL, size, buf));
159         }
160
161         if (ret != EFI_SUCCESS) {
162                 free(buf);
163                 *size = 0;
164                 return NULL;
165         }
166
167         return buf;
168 }
169
170 /**
171  * try_load_entry() - try to load image for boot option
172  *
173  * Attempt to load load-option number 'n', returning device_path and file_path
174  * if successful. This checks that the EFI_LOAD_OPTION is active (enabled)
175  * and that the specified file to boot exists.
176  *
177  * @n:          number of the boot option, e.g. 0x0a13 for Boot0A13
178  * @handle:     on return handle for the newly installed image
179  * Return:      status code
180  */
181 static efi_status_t try_load_entry(u16 n, efi_handle_t *handle)
182 {
183         struct efi_load_option lo;
184         u16 varname[] = L"Boot0000";
185         u16 hexmap[] = L"0123456789ABCDEF";
186         void *load_option;
187         efi_uintn_t size;
188         efi_status_t ret;
189
190         varname[4] = hexmap[(n & 0xf000) >> 12];
191         varname[5] = hexmap[(n & 0x0f00) >> 8];
192         varname[6] = hexmap[(n & 0x00f0) >> 4];
193         varname[7] = hexmap[(n & 0x000f) >> 0];
194
195         load_option = get_var(varname, &efi_global_variable_guid, &size);
196         if (!load_option)
197                 return EFI_LOAD_ERROR;
198
199         ret = efi_deserialize_load_option(&lo, load_option, &size);
200         if (ret != EFI_SUCCESS) {
201                 log_warning("Invalid load option for %ls\n", varname);
202                 goto error;
203         }
204
205         if (lo.attributes & LOAD_OPTION_ACTIVE) {
206                 u32 attributes;
207
208                 log_debug("%s: trying to load \"%ls\" from %pD\n",
209                           __func__, lo.label, lo.file_path);
210
211                 ret = EFI_CALL(efi_load_image(true, efi_root, lo.file_path,
212                                               NULL, 0, handle));
213                 if (ret != EFI_SUCCESS) {
214                         log_warning("Loading %ls '%ls' failed\n",
215                                     varname, lo.label);
216                         goto error;
217                 }
218
219                 attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
220                              EFI_VARIABLE_RUNTIME_ACCESS;
221                 size = sizeof(n);
222                 ret = EFI_CALL(efi_set_variable(
223                                 L"BootCurrent",
224                                 (efi_guid_t *)&efi_global_variable_guid,
225                                 attributes, size, &n));
226                 if (ret != EFI_SUCCESS) {
227                         if (EFI_CALL(efi_unload_image(*handle))
228                             != EFI_SUCCESS)
229                                 log_err("Unloading image failed\n");
230                         goto error;
231                 }
232
233                 log_info("Booting: %ls\n", lo.label);
234         } else {
235                 ret = EFI_LOAD_ERROR;
236         }
237
238 error:
239         free(load_option);
240
241         return ret;
242 }
243
244 /**
245  * efi_bootmgr_load() - try to load from BootNext or BootOrder
246  *
247  * Attempt to load from BootNext or in the order specified by BootOrder
248  * EFI variable, the available load-options, finding and returning
249  * the first one that can be loaded successfully.
250  *
251  * @handle:     on return handle for the newly installed image
252  * Return:      status code
253  */
254 efi_status_t efi_bootmgr_load(efi_handle_t *handle)
255 {
256         u16 bootnext, *bootorder;
257         efi_uintn_t size;
258         int i, num;
259         efi_status_t ret;
260
261         bs = systab.boottime;
262         rs = systab.runtime;
263
264         /* BootNext */
265         bootnext = 0;
266         size = sizeof(bootnext);
267         ret = EFI_CALL(efi_get_variable(L"BootNext",
268                                         (efi_guid_t *)&efi_global_variable_guid,
269                                         NULL, &size, &bootnext));
270         if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
271                 /* BootNext does exist here */
272                 if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16))
273                         log_err("BootNext must be 16-bit integer\n");
274
275                 /* delete BootNext */
276                 ret = EFI_CALL(efi_set_variable(
277                                         L"BootNext",
278                                         (efi_guid_t *)&efi_global_variable_guid,
279                                         EFI_VARIABLE_NON_VOLATILE, 0,
280                                         &bootnext));
281
282                 /* load BootNext */
283                 if (ret == EFI_SUCCESS) {
284                         if (size == sizeof(u16)) {
285                                 ret = try_load_entry(bootnext, handle);
286                                 if (ret == EFI_SUCCESS)
287                                         return ret;
288                                 log_warning(
289                                         "Loading from BootNext failed, falling back to BootOrder\n");
290                         }
291                 } else {
292                         log_err("Deleting BootNext failed\n");
293                 }
294         }
295
296         /* BootOrder */
297         bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
298         if (!bootorder) {
299                 log_info("BootOrder not defined\n");
300                 ret = EFI_NOT_FOUND;
301                 goto error;
302         }
303
304         num = size / sizeof(uint16_t);
305         for (i = 0; i < num; i++) {
306                 log_debug("%s trying to load Boot%04X\n", __func__,
307                           bootorder[i]);
308                 ret = try_load_entry(bootorder[i], handle);
309                 if (ret == EFI_SUCCESS)
310                         break;
311         }
312
313         free(bootorder);
314
315 error:
316         return ret;
317 }